From 95c8e476bcaa7a9797a553cbba10cb03ffc8c50c Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 17 Mar 2020 17:24:44 +1100 Subject: [PATCH] Initial work towards v0.2.0 (#924) * Remove ping protocol * Initial renaming of network services * Correct rebasing relative to latest master * Start updating types * Adds HashMapDelay struct to utils * Initial network restructure * Network restructure. Adds new types for v0.2.0 * Removes build artefacts * Shift validation to beacon chain * Temporarily remove gossip validation This is to be updated to match current optimisation efforts. * Adds AggregateAndProof * Begin rebuilding pubsub encoding/decoding * Signature hacking * Shift gossipsup decoding into eth2_libp2p * Existing EF tests passing with fake_crypto * Shifts block encoding/decoding into RPC * Delete outdated API spec * All release tests passing bar genesis state parsing * Update and test YamlConfig * Update to spec v0.10 compatible BLS * Updates to BLS EF tests * Add EF test for AggregateVerify And delete unused hash2curve tests for uncompressed points * Update EF tests to v0.10.1 * Use optional block root correctly in block proc * Use genesis fork in deposit domain. All tests pass * Fast aggregate verify test * Update REST API docs * Fix unused import * Bump spec tags to v0.10.1 * Add `seconds_per_eth1_block` to chainspec * Update to timestamp based eth1 voting scheme * Return None from `get_votes_to_consider` if block cache is empty * Handle overflows in `is_candidate_block` * Revert to failing tests * Fix eth1 data sets test * Choose default vote according to spec * Fix collect_valid_votes tests * Fix `get_votes_to_consider` to choose all eligible blocks * Uncomment winning_vote tests * Add comments; remove unused code * Reduce seconds_per_eth1_block for simulation * Addressed review comments * Add test for default vote case * Fix logs * Remove unused functions * Meter default eth1 votes * Fix comments * Progress on attestation service * Address review comments; remove unused dependency * Initial work on removing libp2p lock * Add LRU caches to store (rollup) * Update attestation validation for DB changes (WIP) * Initial version of should_forward_block * Scaffold * Progress on attestation validation Also, consolidate prod+testing slot clocks so that they share much of the same implementation and can both handle sub-slot time changes. * Removes lock from libp2p service * Completed network lock removal * Finish(?) attestation processing * Correct network termination future * Add slot check to block check * Correct fmt issues * Remove Drop implementation for network service * Add first attempt at attestation proc. re-write * Add version 2 of attestation processing * Minor fixes * Add validator pubkey cache * Make get_indexed_attestation take a committee * Link signature processing into new attn verification * First working version * Ensure pubkey cache is updated * Add more metrics, slight optimizations * Clone committee cache during attestation processing * Update shuffling cache during block processing * Remove old commented-out code * Fix shuffling cache insert bug * Used indexed attestation in fork choice * Restructure attn processing, add metrics * Add more detailed metrics * Tidy, fix failing tests * Fix failing tests, tidy * Address reviewers suggestions * Disable/delete two outdated tests * Modification of validator for subscriptions * Add slot signing to validator client * Further progress on validation subscription * Adds necessary validator subscription functionality * Add new Pubkeys struct to signature_sets * Refactor with functional approach * Update beacon chain * Clean up validator <-> beacon node http types * Add aggregator status to ValidatorDuty * Impl Clone for manual slot clock * Fix minor errors * Further progress validator client subscription * Initial subscription and aggregation handling * Remove decompressed member from pubkey bytes * Progress to modifying val client for attestation aggregation * First draft of validator client upgrade for aggregate attestations * Add hashmap for indices lookup * Add state cache, remove store cache * Only build the head committee cache * Removes lock on a network channel * Partially implement beacon node subscription http api * Correct compilation issues * Change `get_attesting_indices` to use Vec * Fix failing test * Partial implementation of timer * Adds timer, removes exit_future, http api to op pool * Partial multiple aggregate attestation handling * Permits bulk messages accross gossipsub network channel * Correct compile issues * Improve gosispsub messaging and correct rest api helpers * Added global gossipsub subscriptions * Update validator subscriptions data structs * Tidy * Re-structure validator subscriptions * Initial handling of subscriptions * Re-structure network service * Add pubkey cache persistence file * Add more comments * Integrate persistence file into builder * Add pubkey cache tests * Add HashSetDelay and introduce into attestation service * Handles validator subscriptions * Add data_dir to beacon chain builder * Remove Option in pubkey cache persistence file * Ensure consistency between datadir/data_dir * Fix failing network test * Peer subnet discovery gets queued for future subscriptions * Reorganise attestation service functions * Initial wiring of attestation service * First draft of attestation service timing logic * Correct minor typos * Tidy * Fix todos * Improve tests * Add PeerInfo to connected peers mapping * Fix compile error * Fix compile error from merge * Split up block processing metrics * Tidy * Refactor get_pubkey_from_state * Remove commented-out code * Rename state_cache -> checkpoint_cache * Rename Checkpoint -> Snapshot * Tidy, add comments * Tidy up find_head function * Change some checkpoint -> snapshot * Add tests * Expose max_len * Remove dead code * Tidy * Fix bug * Add sync-speed metric * Add first attempt at VerifiableBlock * Start integrating into beacon chain * Integrate VerifiableBlock * Rename VerifableBlock -> PartialBlockVerification * Add start of typed methods * Add progress * Add further progress * Rename structs * Add full block verification to block_processing.rs * Further beacon chain integration * Update checks for gossip * Add todo * Start adding segement verification * Add passing chain segement test * Initial integration with batch sync * Minor changes * Tidy, add more error checking * Start adding chain_segment tests * Finish invalid signature tests * Include single and gossip verified blocks in tests * Add gossip verification tests * Start adding docs * Finish adding comments to block_processing.rs * Rename block_processing.rs -> block_verification * Start removing old block processing code * Fixes beacon_chain compilation * Fix project-wide compile errors * Remove old code * Correct code to pass all tests * Fix bug with beacon proposer index * Fix shim for BlockProcessingError * Only process one epoch at a time * Fix loop in chain segment processing * Correct tests from master merge * Add caching for state.eth1_data_votes * Add BeaconChain::validator_pubkey * Revert "Add caching for state.eth1_data_votes" This reverts commit cd73dcd6434fb8d8e6bf30c5356355598ea7b78e. Co-authored-by: Grant Wuerker Co-authored-by: Michael Sproul Co-authored-by: Michael Sproul Co-authored-by: pawan Co-authored-by: Paul Hauner --- Cargo.lock | 5179 ++++++++--------- Cargo.toml | 17 +- beacon_node/Cargo.toml | 2 +- beacon_node/beacon_chain/Cargo.toml | 4 +- beacon_node/beacon_chain/src/beacon_chain.rs | 1150 ++-- .../src/{checkpoint.rs => beacon_snapshot.rs} | 4 +- .../beacon_chain/src/block_verification.rs | 801 +++ .../block_processing_outcome.rs | 105 + beacon_node/beacon_chain/src/builder.rs | 47 +- beacon_node/beacon_chain/src/errors.rs | 39 +- beacon_node/beacon_chain/src/eth1_chain.rs | 6 +- .../src/fork_choice/checkpoint_manager.rs | 5 +- beacon_node/beacon_chain/src/lib.rs | 10 +- beacon_node/beacon_chain/src/metrics.rs | 4 + .../beacon_chain/src/snapshot_cache.rs | 217 + beacon_node/beacon_chain/src/test_utils.rs | 16 +- .../src/validator_pubkey_cache.rs | 83 +- .../tests/import_chain_segment_tests.rs | 572 ++ beacon_node/beacon_chain/tests/tests.rs | 23 +- beacon_node/client/Cargo.toml | 6 +- beacon_node/client/src/builder.rs | 111 +- beacon_node/client/src/lib.rs | 17 +- beacon_node/client/src/metrics.rs | 9 + beacon_node/client/src/notifier.rs | 15 +- beacon_node/eth1/Cargo.toml | 3 +- beacon_node/eth1/src/service.rs | 8 +- beacon_node/eth2-libp2p/Cargo.toml | 2 +- beacon_node/eth2-libp2p/src/behaviour.rs | 204 +- beacon_node/eth2-libp2p/src/config.rs | 12 +- beacon_node/eth2-libp2p/src/discovery.rs | 60 +- beacon_node/eth2-libp2p/src/globals.rs | 30 - beacon_node/eth2-libp2p/src/lib.rs | 19 +- beacon_node/eth2-libp2p/src/rpc/codec/base.rs | 52 +- beacon_node/eth2-libp2p/src/rpc/codec/mod.rs | 25 +- beacon_node/eth2-libp2p/src/rpc/codec/ssz.rs | 61 +- beacon_node/eth2-libp2p/src/rpc/handler.rs | 102 +- beacon_node/eth2-libp2p/src/rpc/methods.rs | 26 +- beacon_node/eth2-libp2p/src/rpc/mod.rs | 34 +- beacon_node/eth2-libp2p/src/rpc/protocol.rs | 63 +- beacon_node/eth2-libp2p/src/service.rs | 48 +- beacon_node/eth2-libp2p/src/topics.rs | 71 - .../eth2-libp2p/src/{ => types}/error.rs | 0 beacon_node/eth2-libp2p/src/types/globals.rs | 68 + beacon_node/eth2-libp2p/src/types/mod.rs | 10 + .../eth2-libp2p/src/types/peer_info.rs | 45 + beacon_node/eth2-libp2p/src/types/pubsub.rs | 170 + beacon_node/eth2-libp2p/src/types/topics.rs | 140 + beacon_node/eth2-libp2p/tests/common/mod.rs | 24 +- .../eth2-libp2p/tests/gossipsub_tests.rs | 31 +- beacon_node/eth2-libp2p/tests/noise.rs | 11 +- beacon_node/eth2-libp2p/tests/rpc_tests.rs | 152 +- beacon_node/genesis/Cargo.toml | 2 +- beacon_node/network/Cargo.toml | 5 +- .../network/src/attestation_service/mod.rs | 575 ++ beacon_node/network/src/error.rs | 2 - beacon_node/network/src/lib.rs | 13 +- beacon_node/network/src/message_handler.rs | 367 -- beacon_node/network/src/persisted_dht.rs | 12 +- beacon_node/network/src/router/mod.rs | 275 + .../processor.rs} | 85 +- beacon_node/network/src/service.rs | 247 +- beacon_node/network/src/sync/manager.rs | 12 +- beacon_node/network/src/sync/mod.rs | 5 - .../network/src/sync/network_context.rs | 23 +- .../src/sync/range_sync/batch_processing.rs | 172 +- .../network/src/sync/range_sync/chain.rs | 44 +- .../src/sync/range_sync/chain_collection.rs | 18 +- .../network/src/sync/range_sync/range.rs | 18 +- beacon_node/rest_api/Cargo.toml | 7 +- beacon_node/rest_api/src/beacon.rs | 72 +- beacon_node/rest_api/src/helpers.rs | 88 +- beacon_node/rest_api/src/lib.rs | 26 +- beacon_node/rest_api/src/network.rs | 21 +- beacon_node/rest_api/src/router.rs | 42 +- beacon_node/rest_api/src/validator.rs | 328 +- beacon_node/rest_api/tests/test.rs | 10 +- beacon_node/src/config.rs | 9 +- beacon_node/src/lib.rs | 2 +- beacon_node/store/Cargo.toml | 2 +- beacon_node/store/src/hot_cold_store.rs | 62 +- beacon_node/store/src/iter.rs | 6 +- beacon_node/store/src/leveldb_store.rs | 2 +- beacon_node/store/src/lib.rs | 4 +- beacon_node/store/src/memory_store.rs | 2 +- beacon_node/store/src/state_batch.rs | 2 +- beacon_node/timer/Cargo.toml | 14 + beacon_node/timer/src/lib.rs | 97 + beacon_node/version/Cargo.toml | 2 +- beacon_node/websocket_server/Cargo.toml | 3 +- beacon_node/websocket_server/src/lib.rs | 43 +- book/src/http_validator.md | 29 +- eth2/operation_pool/Cargo.toml | 2 +- eth2/operation_pool/src/lib.rs | 179 +- eth2/operation_pool/src/persistence.rs | 15 +- eth2/proto_array_fork_choice/Cargo.toml | 2 +- eth2/state_processing/Cargo.toml | 4 +- .../src/common/get_attesting_indices.rs | 22 +- .../src/common/initiate_validator_exit.rs | 2 +- .../src/common/slash_validator.rs | 2 +- eth2/state_processing/src/lib.rs | 4 +- .../src/per_block_processing.rs | 26 +- .../block_signature_verifier.rs | 137 +- .../src/per_block_processing/errors.rs | 2 + .../is_valid_indexed_attestation.rs | 3 +- .../per_block_processing/signature_sets.rs | 141 +- .../src/per_block_processing/verify_exit.rs | 13 +- .../verify_proposer_slashing.rs | 10 +- eth2/types/Cargo.toml | 2 +- eth2/types/src/aggregate_and_proof.rs | 80 + eth2/types/src/attestation.rs | 10 +- eth2/types/src/beacon_state.rs | 50 +- eth2/types/src/chain_spec.rs | 23 + eth2/types/src/eth_spec.rs | 4 + eth2/types/src/lib.rs | 4 + eth2/types/src/slot_epoch.rs | 1 + eth2/types/src/subnet_id.rs | 26 + eth2/utils/bls/Cargo.toml | 2 +- eth2/utils/bls/src/fake_public_key.rs | 8 + eth2/utils/bls/src/macros.rs | 51 +- eth2/utils/bls/src/public_key.rs | 14 +- eth2/utils/compare_fields/Cargo.toml | 2 +- eth2/utils/compare_fields_derive/Cargo.toml | 2 +- eth2/utils/deposit_contract/Cargo.toml | 2 +- eth2/utils/eth2_config/Cargo.toml | 2 +- eth2/utils/eth2_interop_keypairs/Cargo.toml | 2 +- eth2/utils/eth2_testnet_config/Cargo.toml | 2 +- eth2/utils/hashmap_delay/Cargo.toml | 9 + eth2/utils/hashmap_delay/src/hashmap_delay.rs | 161 + eth2/utils/hashmap_delay/src/hashset_delay.rs | 157 + eth2/utils/hashmap_delay/src/lib.rs | 21 + eth2/utils/int_to_bytes/Cargo.toml | 2 +- eth2/utils/lighthouse_bootstrap/Cargo.toml | 2 +- eth2/utils/lighthouse_metrics/Cargo.toml | 2 +- eth2/utils/logging/Cargo.toml | 2 +- eth2/utils/merkle_proof/Cargo.toml | 2 +- eth2/utils/remote_beacon_node/Cargo.toml | 4 +- eth2/utils/remote_beacon_node/src/lib.rs | 92 +- eth2/utils/rest_types/Cargo.toml | 15 + eth2/utils/rest_types/src/beacon.rs | 65 + eth2/utils/rest_types/src/lib.rs | 15 + eth2/utils/rest_types/src/validator.rs | 108 + eth2/utils/serde_hex/Cargo.toml | 2 +- eth2/utils/slot_clock/Cargo.toml | 3 +- eth2/utils/slot_clock/src/lib.rs | 15 +- .../utils/slot_clock/src/manual_slot_clock.rs | 165 + .../slot_clock/src/system_time_slot_clock.rs | 82 +- .../slot_clock/src/testing_slot_clock.rs | 64 - eth2/utils/ssz_types/src/bitfield.rs | 2 +- eth2/utils/swap_or_not_shuffle/Cargo.toml | 2 +- eth2/utils/test_random_derive/Cargo.toml | 2 +- lcli/Cargo.toml | 2 +- lighthouse/Cargo.toml | 2 +- lighthouse/environment/Cargo.toml | 2 +- tests/ef_tests/Cargo.toml | 2 +- tests/eth1_test_rig/Cargo.toml | 2 +- tests/node_test_rig/Cargo.toml | 2 +- tests/simulator/Cargo.toml | 2 +- validator_client/Cargo.toml | 3 +- validator_client/src/attestation_service.rs | 306 +- validator_client/src/duties_service.rs | 170 +- validator_client/src/validator_store.rs | 38 +- 161 files changed, 9771 insertions(+), 5266 deletions(-) rename beacon_node/beacon_chain/src/{checkpoint.rs => beacon_snapshot.rs} (95%) create mode 100644 beacon_node/beacon_chain/src/block_verification.rs create mode 100644 beacon_node/beacon_chain/src/block_verification/block_processing_outcome.rs create mode 100644 beacon_node/beacon_chain/src/snapshot_cache.rs create mode 100644 beacon_node/beacon_chain/tests/import_chain_segment_tests.rs create mode 100644 beacon_node/client/src/metrics.rs delete mode 100644 beacon_node/eth2-libp2p/src/globals.rs delete mode 100644 beacon_node/eth2-libp2p/src/topics.rs rename beacon_node/eth2-libp2p/src/{ => types}/error.rs (100%) create mode 100644 beacon_node/eth2-libp2p/src/types/globals.rs create mode 100644 beacon_node/eth2-libp2p/src/types/mod.rs create mode 100644 beacon_node/eth2-libp2p/src/types/peer_info.rs create mode 100644 beacon_node/eth2-libp2p/src/types/pubsub.rs create mode 100644 beacon_node/eth2-libp2p/src/types/topics.rs create mode 100644 beacon_node/network/src/attestation_service/mod.rs delete mode 100644 beacon_node/network/src/message_handler.rs create mode 100644 beacon_node/network/src/router/mod.rs rename beacon_node/network/src/{message_processor.rs => router/processor.rs} (92%) create mode 100644 beacon_node/timer/Cargo.toml create mode 100644 beacon_node/timer/src/lib.rs create mode 100644 eth2/types/src/aggregate_and_proof.rs create mode 100644 eth2/types/src/subnet_id.rs create mode 100644 eth2/utils/hashmap_delay/Cargo.toml create mode 100644 eth2/utils/hashmap_delay/src/hashmap_delay.rs create mode 100644 eth2/utils/hashmap_delay/src/hashset_delay.rs create mode 100644 eth2/utils/hashmap_delay/src/lib.rs create mode 100644 eth2/utils/rest_types/Cargo.toml create mode 100644 eth2/utils/rest_types/src/beacon.rs create mode 100644 eth2/utils/rest_types/src/lib.rs create mode 100644 eth2/utils/rest_types/src/validator.rs create mode 100644 eth2/utils/slot_clock/src/manual_slot_clock.rs delete mode 100644 eth2/utils/slot_clock/src/testing_slot_clock.rs diff --git a/Cargo.lock b/Cargo.lock index ce0a7e69a..5ca814628 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,997 +4,1080 @@ name = "account_manager" version = "0.0.1" dependencies = [ - "bls 0.1.0", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "deposit_contract 0.1.0", - "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "environment 0.1.0", - "eth2_ssz 0.1.2", - "eth2_ssz_derive 0.1.0", - "eth2_testnet_config 0.1.0", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-term 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "types 0.1.0", - "validator_client 0.1.0", - "web3 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bls", + "clap", + "deposit_contract", + "dirs", + "environment", + "eth2_ssz", + "eth2_ssz_derive", + "eth2_testnet_config", + "futures", + "hex 0.3.2", + "libc", + "rayon", + "slog", + "slog-async", + "slog-term", + "tempdir", + "types", + "validator_client", + "web3", ] [[package]] name = "adler32" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" [[package]] name = "aes-ctr" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" dependencies = [ - "aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aes-soft", + "aesni", + "ctr", + "stream-cipher", ] [[package]] name = "aes-soft" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait", + "byteorder 1.3.4", + "opaque-debug", ] [[package]] name = "aesni" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait", + "opaque-debug", + "stream-cipher", ] [[package]] name = "ahash" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f33b5018f120946c1dcf279194f238a9f146725593ead1c08fa47ff22b0b5d3" dependencies = [ - "const-random 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "const-random", ] [[package]] name = "aho-corasick" -version = "0.7.6" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" dependencies = [ - "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] [[package]] name = "amcl" version = "0.2.0" -source = "git+https://github.com/sigp/milagro_bls?branch=eth2.0-v0.10#52fab41dd086951ade699894b690e95ede1efafd" +source = "git+https://github.com/sigp/milagro_bls?branch=eth2.0-v0.10#9f946ca454ad1da4cd1344bd632b7306704bc904" dependencies = [ - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2", + "lazy_static", ] [[package]] name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8", ] -[[package]] -name = "anyhow" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "arc-swap" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7b8a9123b8027467bce0099fe556c628a53c8d83df0507084c31e9ba2e39aff" [[package]] name = "arrayref" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "arrayvec" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" dependencies = [ - "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop", ] [[package]] name = "arrayvec" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" [[package]] name = "asn1_der" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fce6b6a0ffdafebd82c87e79e3f40e8d2c523e5fea5566ff6b90509bf98d638" dependencies = [ - "asn1_der_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "asn1_der_derive", ] [[package]] name = "asn1_der_derive" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d0864d84b8e07b145449be9a8537db86bf9de5ce03b913214694643b4743502" dependencies = [ - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3", + "syn 1.0.16", ] [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", + "winapi 0.3.8", ] [[package]] name = "autocfg" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" [[package]] name = "autocfg" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "backtrace" -version = "0.3.41" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8" dependencies = [ - "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys", + "cfg-if", + "libc", + "rustc-demangle", ] [[package]] name = "backtrace-sys" -version = "0.1.32" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca797db0057bae1a7aa2eef3283a874695455cecf08a43bfb8507ee0ebc1ed69" dependencies = [ - "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", ] [[package]] name = "base64" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", + "safemem", ] [[package]] name = "base64" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", ] [[package]] name = "base64" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" [[package]] name = "beacon_chain" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "environment 0.1.0", - "eth1 0.1.0", - "eth2_config 0.1.0", - "eth2_hashing 0.1.1", - "eth2_ssz 0.1.2", - "eth2_ssz_derive 0.1.0", - "eth2_ssz_types 0.2.0", - "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "genesis 0.1.0", - "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lighthouse_bootstrap 0.1.0", - "lighthouse_metrics 0.1.0", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lru 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "merkle_proof 0.1.0", - "operation_pool 0.1.0", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proto_array_fork_choice 0.1.0", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sloggers 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "slot_clock 0.1.0", - "state_processing 0.1.0", - "store 0.1.0", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tree_hash 0.1.1", - "types 0.1.0", - "websocket_server 0.1.0", + "environment", + "eth1", + "eth2_config", + "eth2_hashing", + "eth2_ssz", + "eth2_ssz_derive", + "eth2_ssz_types", + "futures", + "genesis", + "integer-sqrt", + "lazy_static", + "lighthouse_bootstrap", + "lighthouse_metrics", + "log 0.4.8", + "lru 0.4.3", + "merkle_proof", + "operation_pool", + "parking_lot 0.9.0", + "proto_array_fork_choice", + "rand 0.7.3", + "rayon", + "serde", + "serde_derive", + "serde_json", + "serde_yaml", + "slog", + "sloggers", + "slot_clock", + "state_processing", + "store", + "tempfile", + "tokio", + "tree_hash", + "types", + "websocket_server", ] [[package]] name = "beacon_node" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "beacon_chain 0.1.0", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "client 0.1.0", - "ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "environment 0.1.0", - "eth2-libp2p 0.1.0", - "eth2_config 0.1.0", - "eth2_ssz 0.1.2", - "eth2_testnet_config 0.1.0", - "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "genesis 0.1.0", - "lighthouse_bootstrap 0.1.0", - "logging 0.1.0", - "node_test_rig 0.1.0", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-term 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "store 0.1.0", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "types 0.1.0", - "version 0.1.0", + "beacon_chain", + "clap", + "client", + "ctrlc", + "dirs", + "env_logger 0.7.1", + "environment", + "eth2-libp2p", + "eth2_config", + "eth2_ssz", + "eth2_testnet_config", + "exit-future", + "futures", + "genesis", + "lighthouse_bootstrap", + "logging", + "node_test_rig", + "rand 0.7.3", + "slog", + "slog-async", + "slog-term", + "store", + "tokio", + "tokio-timer 0.2.13", + "types", + "version", ] [[package]] name = "bigint" version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebecac13b3c745150d7b6c3ea7572d372f09d627c2077e893bf26c5c7f70d282" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", + "crunchy 0.1.6", ] [[package]] name = "bincode" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", + "serde", ] [[package]] name = "bitflags" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bitvec" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993f74b4c99c1908d156b8d2e0fb6277736b0ecbd833982fd1241d39b2766a6" [[package]] name = "blake2" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330" dependencies = [ - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools", + "crypto-mac", + "digest", + "opaque-debug", ] [[package]] name = "blake2b_simd" version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref", + "arrayvec 0.5.1", + "constant_time_eq", ] [[package]] name = "block-buffer" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-padding", + "byte-tools", + "byteorder 1.3.4", + "generic-array", ] [[package]] name = "block-cipher-trait" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array", ] [[package]] name = "block-padding" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" dependencies = [ - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools", ] [[package]] name = "bls" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "eth2_hashing 0.1.1", - "eth2_ssz 0.1.2", - "eth2_ssz_types 0.2.0", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "milagro_bls 1.0.0 (git+https://github.com/sigp/milagro_bls?branch=eth2.0-v0.10)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_hex 0.1.0", - "tree_hash 0.1.1", + "eth2_hashing", + "eth2_ssz", + "eth2_ssz_types", + "hex 0.3.2", + "milagro_bls", + "rand 0.7.3", + "serde", + "serde_derive", + "serde_hex", + "tree_hash", ] [[package]] name = "bs58" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c95ee6bba9d950218b6cc910cf62bc9e0a171d0f4537e3627b0f54d08549b188" [[package]] name = "bs58" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b170cd256a3f9fa6b9edae3e44a7dfdfc77e8124dbc3e2612d75f9c3e2396dae" [[package]] name = "bstr" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2889e6d50f394968c8bf4240dc3f2a7eb4680844d27308f798229ac9d4725f41" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "memchr", + "regex-automata", + "serde", ] [[package]] name = "bumpalo" -version = "3.1.2" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f359dc14ff8911330a51ef78022d376f25ed00248912803b58f00cb1c27f742" [[package]] name = "byte-slice-cast" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" [[package]] name = "byte-tools" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" [[package]] name = "byteorder" -version = "1.3.2" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "bytes" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "c2-chacha" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", + "either", + "iovec", ] [[package]] name = "c_linked_list" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4964518bd3b4a8190e832886cdc0da9794f12e8e6c1613a9e90ff331c4c8724b" [[package]] name = "cached_tree_hash" version = "0.1.0" dependencies = [ - "eth2_hashing 0.1.1", - "eth2_ssz 0.1.2", - "eth2_ssz_derive 0.1.0", - "eth2_ssz_types 0.2.0", - "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_macros 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tree_hash 0.1.1", + "eth2_hashing", + "eth2_ssz", + "eth2_ssz_derive", + "eth2_ssz_types", + "ethereum-types 0.8.0", + "quickcheck", + "quickcheck_macros", + "smallvec 1.2.0", + "tree_hash", ] [[package]] name = "cast" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version", ] [[package]] name = "cc" version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "chrono" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" dependencies = [ - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer", + "num-traits", + "time", ] [[package]] name = "clap" version = "2.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ansi_term", + "atty", + "bitflags 1.2.1", + "strsim", + "textwrap", + "unicode-width", + "vec_map", ] [[package]] name = "clear_on_drop" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" dependencies = [ - "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", ] [[package]] name = "client" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "beacon_chain 0.1.0", - "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "environment 0.1.0", - "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", - "eth1 0.1.0", - "eth2-libp2p 0.1.0", - "eth2_config 0.1.0", - "eth2_ssz 0.1.2", - "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "genesis 0.1.0", - "lighthouse_bootstrap 0.1.0", - "network 0.1.0", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "prometheus 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "rest_api 0.1.0", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sloggers 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "slot_clock 0.1.0", - "store 0.1.0", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tree_hash 0.1.1", - "types 0.1.0", - "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "websocket_server 0.1.0", + "beacon_chain", + "dirs", + "environment", + "error-chain", + "eth1", + "eth2-libp2p", + "eth2_config", + "eth2_ssz", + "futures", + "genesis", + "lazy_static", + "lighthouse_bootstrap", + "lighthouse_metrics", + "network", + "parking_lot 0.9.0", + "prometheus", + "reqwest", + "rest_api", + "serde", + "serde_derive", + "serde_yaml", + "slog", + "slog-async", + "sloggers", + "slot_clock", + "store", + "timer", + "tokio", + "toml", + "tree_hash", + "types", + "url 2.1.1", + "websocket_server", ] [[package]] name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", ] [[package]] name = "colored" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "lazy_static", + "winapi 0.3.8", ] [[package]] name = "compare_fields" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "compare_fields_derive 0.1.0", + "compare_fields_derive", ] [[package]] name = "compare_fields_derive" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13", + "syn 0.15.44", ] [[package]] name = "console_error_panic_hook" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "wasm-bindgen", ] [[package]] name = "const-random" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a" dependencies = [ - "const-random-macro 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", + "const-random-macro", + "proc-macro-hack", ] [[package]] name = "const-random-macro" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a" dependencies = [ - "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "proc-macro-hack", ] [[package]] name = "constant_time_eq" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "cookie" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" dependencies = [ - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "time", + "url 1.7.2", ] [[package]] name = "cookie_store" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c" dependencies = [ - "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "publicsuffix 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie", + "failure", + "idna 0.1.5", + "log 0.4.8", + "publicsuffix", + "serde", + "serde_json", + "time", + "try_from", + "url 1.7.2", ] [[package]] name = "core-foundation" -version = "0.6.4" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" dependencies = [ - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys", + "libc", ] [[package]] name = "core-foundation-sys" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" [[package]] name = "crc32fast" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "criterion" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc755679c12bda8e5523a71e4d654b6bf2e14bd838dfc48cde6559a05caf7d1" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "csv 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "tinytemplate 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", ] [[package]] name = "criterion-plot" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01e15e0ea58e8234f96146b1f91fa9d0e4dd7a38da93ff7a75d42c0b9d3a545" dependencies = [ - "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cast", + "itertools", ] [[package]] name = "crossbeam" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be" [[package]] name = "crossbeam" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "crossbeam-channel 0.4.2", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils 0.7.2", ] [[package]] name = "crossbeam-channel" -version = "0.4.0" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" dependencies = [ - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6", +] + +[[package]] +name = "crossbeam-channel" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" +dependencies = [ + "crossbeam-utils 0.7.2", + "maybe-uninit", ] [[package]] name = "crossbeam-deque" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" dependencies = [ - "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch", + "crossbeam-utils 0.7.2", + "maybe-uninit", ] [[package]] name = "crossbeam-epoch" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-queue" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0", + "cfg-if", + "crossbeam-utils 0.7.2", + "lazy_static", + "maybe-uninit", + "memoffset", + "scopeguard 1.1.0", ] [[package]] name = "crossbeam-queue" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "crossbeam-utils 0.7.2", ] [[package]] name = "crossbeam-utils" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "lazy_static", ] [[package]] name = "crossbeam-utils" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0", + "cfg-if", + "lazy_static", ] [[package]] name = "crunchy" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" [[package]] name = "crunchy" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-mac" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array", + "subtle 1.0.0", ] [[package]] name = "csv" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279" dependencies = [ - "bstr 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr", + "csv-core", + "itoa", + "ryu", + "serde", ] [[package]] name = "csv-core" -version = "0.1.6" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" dependencies = [ - "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] [[package]] name = "ctr" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait", + "stream-cipher", ] [[package]] name = "ctrlc" -version = "3.1.3" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a4ba686dff9fa4c1c9636ce1010b0cf98ceb421361b0bb3d6faeec43bd217a7" dependencies = [ - "nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "nix", + "winapi 0.3.8", ] [[package]] name = "cuckoofilter" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dd43f7cfaffe0a386636a10baea2ee05cc50df3b77bea4a456c9572a939bf1f" dependencies = [ - "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 0.5.3", + "rand 0.3.23", ] [[package]] name = "curve25519-dalek" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7dcd30ba50cdf88b55b033456138b7c0ac4afdc436d82e1b79f370f24cc66d" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", + "clear_on_drop", + "digest", + "rand_core 0.3.1", + "subtle 2.2.2", ] [[package]] name = "curve25519-dalek" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26778518a7f6cffa1d25a44b602b62b979bd88adb9e99ffec546998cf3404839" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", + "digest", + "rand_core 0.5.1", + "subtle 2.2.2", + "zeroize 1.1.0", ] [[package]] name = "data-encoding" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11c0346158a19b3627234e15596f5e465c360fcdb97d817bcb255e0510f5a788" [[package]] name = "db-key" version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72465f46d518f6015d9cf07f7f3013a95dd6b9c2747c3d65ae0cce43929d14f" [[package]] name = "deposit_contract" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "eth2_ssz 0.1.2", - "ethabi 9.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "tree_hash 0.1.1", - "types 0.1.0", + "eth2_ssz", + "ethabi 9.0.1", + "reqwest", + "serde_json", + "tree_hash", + "types", ] [[package]] name = "derivative" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c6d883546668a3e2011b6a716a7330b82eabb0151b138217f632c8243e17135" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", ] [[package]] name = "derive_more" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a141330240c921ec6d074a3e188a7c7ef95668bb95e7d44fa0e5778ec2a7afe" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "proc-macro2 0.4.30", + "quote 0.6.13", + "regex", + "rustc_version", + "syn 0.15.44", ] [[package]] name = "digest" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array", ] [[package]] name = "dirs" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "dirs-sys", ] [[package]] name = "dirs-sys" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "redox_users", + "winapi 0.3.8", ] [[package]] name = "dns-parser" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", + "quick-error", ] [[package]] name = "dtoa" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" [[package]] name = "ed25519-dalek" version = "1.0.0-pre.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978710b352437433c97b2bff193f2fb1dfd58a093f863dd95e225a19baa599a2" dependencies = [ - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clear_on_drop", + "curve25519-dalek 2.0.0", + "rand 0.7.3", + "sha2", ] [[package]] name = "ef_tests" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "bls 0.1.0", - "cached_tree_hash 0.1.0", - "compare_fields 0.1.0", - "eth2_ssz 0.1.2", - "eth2_ssz_derive 0.1.0", - "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", - "state_processing 0.1.0", - "swap_or_not_shuffle 0.1.0", - "tree_hash 0.1.1", - "tree_hash_derive 0.2.0", - "types 0.1.0", - "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bls", + "cached_tree_hash", + "compare_fields", + "eth2_ssz", + "eth2_ssz_derive", + "ethereum-types 0.8.0", + "hex 0.3.2", + "rayon", + "serde", + "serde_derive", + "serde_repr", + "serde_yaml", + "state_processing", + "swap_or_not_shuffle", + "tree_hash", + "tree_hash_derive", + "types", + "walkdir", ] [[package]] name = "either" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" [[package]] name = "encoding_rs" version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] @@ -1002,891 +1085,960 @@ name = "enr" version = "0.1.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libsecp256k1 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.10.1", + "bs58 0.3.0", + "clap", + "hex 0.4.2", + "libp2p-core", + "libsecp256k1 0.3.5", + "log 0.4.8", + "rand 0.7.3", + "rlp", + "serde", + "sha3", ] [[package]] name = "env_logger" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "humantime", + "log 0.4.8", + "regex", + "termcolor", ] [[package]] name = "env_logger" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "humantime", + "log 0.4.8", + "regex", + "termcolor", ] [[package]] name = "environment" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "eth2_config 0.1.0", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "logging 0.1.0", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-term 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sloggers 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "types 0.1.0", + "ctrlc", + "env_logger 0.6.2", + "eth2_config", + "futures", + "logging", + "parking_lot 0.7.1", + "slog", + "slog-async", + "slog-json", + "slog-term", + "sloggers", + "tokio", + "types", ] [[package]] name = "error-chain" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d371106cc88ffdfb1eabd7111e432da544f16f3e2d7bf1dfe8bf575f1df045cd" dependencies = [ - "backtrace 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace", + "version_check 0.9.1", ] [[package]] name = "eth1" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "environment 0.1.0", - "eth1_test_rig 0.1.0", - "eth2_hashing 0.1.1", - "eth2_ssz 0.1.2", - "eth2_ssz_derive 0.1.0", - "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libflate 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "lighthouse_metrics 0.1.0", - "merkle_proof 0.1.0", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "state_processing 0.1.0", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tree_hash 0.1.1", - "types 0.1.0", - "web3 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "environment", + "eth1_test_rig", + "eth2_hashing", + "eth2_ssz", + "eth2_ssz_derive", + "futures", + "hex 0.3.2", + "lazy_static", + "libflate", + "lighthouse_metrics", + "merkle_proof", + "parking_lot 0.7.1", + "reqwest", + "serde", + "serde_json", + "slog", + "state_processing", + "tokio", + "toml", + "tree_hash", + "types", + "web3", ] [[package]] name = "eth1_test_rig" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "deposit_contract 0.1.0", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "types 0.1.0", - "web3 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "deposit_contract", + "futures", + "serde_json", + "tokio", + "types", + "web3", ] [[package]] name = "eth2-libp2p" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "enr 0.1.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", - "eth2_ssz 0.1.2", - "eth2_ssz_derive 0.1.0", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "lighthouse_metrics 0.1.0", - "lru 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-stdlog 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-term 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io-timeout 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "types 0.1.0", - "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "version 0.1.0", + "base64 0.11.0", + "dirs", + "enr", + "error-chain", + "eth2_ssz", + "eth2_ssz_derive", + "fnv", + "futures", + "hex 0.3.2", + "lazy_static", + "libp2p", + "lighthouse_metrics", + "lru 0.4.3", + "parking_lot 0.9.0", + "serde", + "serde_derive", + "sha2", + "slog", + "slog-async", + "slog-stdlog 4.0.0", + "slog-term", + "smallvec 1.2.0", + "tempdir", + "tokio", + "tokio-io-timeout", + "types", + "unsigned-varint", + "version", ] [[package]] name = "eth2_config" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "types 0.1.0", + "serde", + "serde_derive", + "toml", + "types", ] [[package]] name = "eth2_hashing" version = "0.1.1" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-test 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "ring", + "rustc-hex", + "sha2", + "wasm-bindgen-test", ] [[package]] name = "eth2_interop_keypairs" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "eth2_hashing 0.1.1", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "milagro_bls 1.0.0 (git+https://github.com/sigp/milagro_bls?branch=eth2.0-v0.10)", - "num-bigint 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.11.0", + "eth2_hashing", + "hex 0.3.2", + "lazy_static", + "milagro_bls", + "num-bigint", + "serde", + "serde_derive", + "serde_yaml", ] [[package]] name = "eth2_ssz" version = "0.1.2" dependencies = [ - "eth2_ssz_derive 0.1.0", - "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "eth2_ssz_derive", + "ethereum-types 0.8.0", + "smallvec 1.2.0", ] [[package]] name = "eth2_ssz_derive" version = "0.1.0" dependencies = [ - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13", + "syn 0.15.44", ] [[package]] name = "eth2_ssz_types" version = "0.2.0" dependencies = [ - "eth2_ssz 0.1.2", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_hex 0.1.0", - "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tree_hash 0.1.1", - "tree_hash_derive 0.2.0", - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "eth2_ssz", + "serde", + "serde_derive", + "serde_hex", + "serde_yaml", + "tree_hash", + "tree_hash_derive", + "typenum", ] [[package]] name = "eth2_testnet_config" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "eth2-libp2p 0.1.0", - "eth2_ssz 0.1.2", - "reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "types 0.1.0", + "eth2-libp2p", + "eth2_ssz", + "reqwest", + "serde", + "serde_yaml", + "tempdir", + "types", ] [[package]] name = "ethabi" version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebdeeea85a6d217b9fcc862906d7e283c047e04114165c433756baf5dce00a6c" dependencies = [ - "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain", + "ethereum-types 0.6.0", + "rustc-hex", + "serde", + "serde_derive", + "serde_json", + "tiny-keccak", ] [[package]] name = "ethabi" version = "9.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965126c64662832991f5a748893577630b558e47fa94e7f35aefcd20d737cef7" dependencies = [ - "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain", + "ethereum-types 0.8.0", + "rustc-hex", + "serde", + "serde_derive", + "serde_json", + "tiny-keccak", ] [[package]] name = "ethbloom" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3932e82d64d347a045208924002930dc105a138995ccdc1479d0f05f0359f17c" dependencies = [ - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-rlp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.2.2", + "fixed-hash 0.3.2", + "impl-rlp", + "impl-serde 0.2.3", + "tiny-keccak", ] [[package]] name = "ethbloom" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cfe1c169414b709cf28aa30c74060bdb830a03a8ba473314d079ac79d80a5f" dependencies = [ - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fixed-hash 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-rlp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.2.2", + "fixed-hash 0.5.2", + "impl-rlp", + "impl-serde 0.2.3", + "tiny-keccak", ] [[package]] name = "ethereum-types" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62d1bc682337e2c5ec98930853674dd2b4bd5d0d246933a9e98e5280f7c76c5f" dependencies = [ - "ethbloom 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-rlp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "primitive-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethbloom 0.6.4", + "fixed-hash 0.3.2", + "impl-rlp", + "impl-serde 0.2.3", + "primitive-types 0.3.0", + "uint 0.7.1", ] [[package]] name = "ethereum-types" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba744248e3553a393143d5ebb68939fc3a4ec0c22a269682535f5ffe7fed728c" dependencies = [ - "ethbloom 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fixed-hash 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-rlp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "primitive-types 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethbloom 0.8.1", + "fixed-hash 0.5.2", + "impl-rlp", + "impl-serde 0.2.3", + "primitive-types 0.6.2", + "uint 0.8.2", ] [[package]] name = "exit-future" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8013f441e38e31c670e7f34ec8f1d5d3a2bd9d303c1ff83976ca886005e8f48" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "parking_lot 0.7.1", ] [[package]] name = "failure" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" dependencies = [ - "backtrace 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace", + "failure_derive", ] [[package]] name = "failure_derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" dependencies = [ - "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9", + "quote 1.0.3", + "syn 1.0.16", + "synstructure", ] [[package]] name = "fake-simd" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" [[package]] name = "fixed-hash" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1a683d1234507e4f3bf2736eeddf0de1dc65996dc0164d57eba0a74bcf29489" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", + "heapsize", + "rand 0.5.6", + "rustc-hex", + "static_assertions 0.2.5", ] [[package]] name = "fixed-hash" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3367952ceb191f4ab95dd5685dc163ac539e36202f9fcfd0cb22f9f9c542fefc" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", + "rand 0.7.3", + "rustc-hex", + "static_assertions 1.1.0", ] [[package]] name = "flate2" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd6d6f4752952feb71363cffc9ebac9411b75b87c6ab6058c40c8900cf43c0f" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "crc32fast", + "futures", + "libc", + "libz-sys", + "miniz_oxide", + "tokio-io", ] [[package]] name = "fnv" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" [[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "foreign-types-shared", ] [[package]] name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "fuchsia-zircon-sys", ] [[package]] name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" [[package]] name = "futures-cpupool" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "num_cpus", ] [[package]] name = "gcc" version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" [[package]] name = "generic-array" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" dependencies = [ - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "typenum", ] [[package]] name = "genesis" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "environment 0.1.0", - "eth1 0.1.0", - "eth1_test_rig 0.1.0", - "eth2_hashing 0.1.1", - "eth2_ssz 0.1.2", - "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "int_to_bytes 0.1.0", - "merkle_proof 0.1.0", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "state_processing 0.1.0", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tree_hash 0.1.1", - "types 0.1.0", + "environment", + "eth1", + "eth1_test_rig", + "eth2_hashing", + "eth2_ssz", + "exit-future", + "futures", + "int_to_bytes", + "merkle_proof", + "parking_lot 0.7.1", + "rayon", + "serde", + "serde_derive", + "slog", + "state_processing", + "tokio", + "tree_hash", + "types", ] [[package]] name = "get_if_addrs" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abddb55a898d32925f3148bd281174a68eeb68bbfd9a5938a57b18f506ee4ef7" dependencies = [ - "c_linked_list 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "get_if_addrs-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "c_linked_list", + "get_if_addrs-sys", + "libc", + "winapi 0.2.8", ] [[package]] name = "get_if_addrs-sys" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d04f9fb746cf36b191c00f3ede8bde9c8e64f9f4b05ae2694a9ccf5e3f5ab48" dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc", + "libc", ] [[package]] name = "getrandom" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "wasi", ] [[package]] name = "h2" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", + "bytes", + "fnv", + "futures", + "http", + "indexmap", + "log 0.4.8", + "slab 0.4.2", + "string", + "tokio-io", ] [[package]] name = "hashbrown" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353" [[package]] name = "hashbrown" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead" dependencies = [ - "ahash 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "ahash", + "autocfg 0.1.7", +] + +[[package]] +name = "hashmap_delay" +version = "0.2.0" +dependencies = [ + "futures", + "tokio-timer 0.2.13", ] [[package]] name = "heapsize" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "heck" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8", ] [[package]] name = "hermit-abi" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "hex" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" [[package]] name = "hex" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" [[package]] name = "hkdf" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fa08a006102488bd9cd5b8013aabe84955cf5ae22e304c2caf655b633aefae3" dependencies = [ - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "digest", + "hmac", ] [[package]] name = "hmac" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" dependencies = [ - "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-mac", + "digest", ] [[package]] name = "hmac-drbg" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" dependencies = [ - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "digest", + "generic-array", + "hmac", ] [[package]] name = "http" version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "fnv", + "itoa", ] [[package]] name = "http-body" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "http", + "tokio-buf", ] [[package]] name = "httparse" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" [[package]] name = "humantime" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" dependencies = [ - "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error", ] [[package]] name = "hyper" version = "0.10.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.9.3", + "httparse", + "language-tags", + "log 0.3.9", + "mime 0.2.6", + "num_cpus", + "time", + "traitobject", + "typeable", + "unicase 1.4.2", + "url 1.7.2", ] [[package]] name = "hyper" version = "0.12.35" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "futures-cpupool", + "h2", + "http", + "http-body", + "httparse", + "iovec", + "itoa", + "log 0.4.8", + "net2", + "rustc_version", + "time", + "tokio", + "tokio-buf", + "tokio-executor", + "tokio-io", + "tokio-reactor", + "tokio-tcp", + "tokio-threadpool", + "tokio-timer 0.2.13", + "want", ] [[package]] name = "hyper-tls" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "hyper 0.12.35", + "native-tls", + "tokio-io", ] [[package]] name = "idna" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", + "unicode-bidi", + "unicode-normalization", ] [[package]] name = "idna" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", + "unicode-bidi", + "unicode-normalization", ] [[package]] name = "impl-codec" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2050d823639fbeae26b2b5ba09aca8907793117324858070ade0673c49f793b" dependencies = [ - "parity-codec 3.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec", ] [[package]] name = "impl-codec" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1be51a921b067b0eaca2fad532d9400041561aa922221cc65f95a85641c6bf53" dependencies = [ - "parity-scale-codec 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-scale-codec", ] [[package]] name = "impl-rlp" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f7a72f11830b52333f36e3b09a288333888bf54380fd0ac0790a3c31ab0f3c5" dependencies = [ - "rlp 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rlp", ] [[package]] name = "impl-serde" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58e3cae7e99c7ff5a995da2cf78dd0a5383740eda71d98cf7b1910c301ac69b8" dependencies = [ - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] name = "impl-serde" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bbe9ea9b182f0fb1cabbd61f4ff9b7b7b9197955e95a7e4c27de5055eb29ff8" dependencies = [ - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] name = "indexmap" -version = "1.3.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0", ] [[package]] name = "int_to_bytes" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "hex 0.3.2", + "yaml-rust", ] [[package]] name = "integer-sqrt" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f65877bf7d44897a473350b1046277941cee20b263397e90869c50b6e766088b" [[package]] name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "ipnet" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47be2f14c678be2fdcab04ab1171db51b2762ce6f0a8ee87c8dd4a04ed216135" [[package]] name = "itertools" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" dependencies = [ - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "either", ] [[package]] name = "itoa" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" [[package]] name = "js-sys" -version = "0.3.35" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cb931d43e71f560c81badb0191596562bafad2be06a3f9025b845c847c60df5" dependencies = [ - "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen", ] [[package]] name = "jsonrpc-core" version = "11.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b83fdc5e0218128d0d270f2f2e7a5ea716f3240c8518a58bc89e6716ba8581" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "log 0.4.8", + "serde", + "serde_derive", + "serde_json", ] [[package]] name = "keccak" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" [[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8", + "winapi-build", ] [[package]] name = "language-tags" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lazycell" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" [[package]] name = "lcli" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "environment 0.1.0", - "eth1_test_rig 0.1.0", - "eth2_ssz 0.1.2", - "eth2_testnet_config 0.1.0", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "genesis 0.1.0", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", - "simple_logger 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "state_processing 0.1.0", - "types 0.1.0", - "web3 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap", + "dirs", + "environment", + "eth1_test_rig", + "eth2_ssz", + "eth2_testnet_config", + "futures", + "genesis", + "hex 0.3.2", + "log 0.4.8", + "regex", + "serde", + "serde_yaml", + "simple_logger", + "state_processing", + "types", + "web3", ] [[package]] name = "leveldb" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8438a36a31c982ac399c4477d7e3c62cc7a6bf91bb6f42837b7e1033359fcbad" dependencies = [ - "db-key 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "leveldb-sys 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "db-key", + "leveldb-sys", + "libc", ] [[package]] name = "leveldb-sys" version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71f46429bb70612c3e939aaeed27ffd31a24a773d21728a1a426e4089d6778d2" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "libc" -version = "0.2.66" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" [[package]] name = "libflate" version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9135df43b1f5d0e333385cb6e7897ecd1a43d7d11b91ac003f4d2c2d2401fdd" dependencies = [ - "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "adler32", + "crc32fast", + "rle-decode-fast", + "take_mut", ] [[package]] @@ -1894,39 +2046,39 @@ name = "libp2p" version = "0.13.2" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "enr 0.1.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-core-derive 0.13.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-deflate 0.5.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-discv5 0.1.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-dns 0.13.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-floodsub 0.13.1 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-gossipsub 0.1.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-identify 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-kad 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-mdns 0.13.1 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-mplex 0.13.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-noise 0.11.1 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-ping 0.13.1 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-plaintext 0.13.1 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-secio 0.13.1 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-swarm 0.3.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-tcp 0.13.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-uds 0.13.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-wasm-ext 0.6.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-websocket 0.13.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-yamux 0.13.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "parity-multiaddr 0.6.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "parity-multihash 0.2.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "enr", + "futures", + "lazy_static", + "libp2p-core", + "libp2p-core-derive", + "libp2p-deflate", + "libp2p-discv5", + "libp2p-dns", + "libp2p-floodsub", + "libp2p-gossipsub", + "libp2p-identify", + "libp2p-kad", + "libp2p-mdns", + "libp2p-mplex", + "libp2p-noise", + "libp2p-ping", + "libp2p-plaintext", + "libp2p-secio", + "libp2p-swarm", + "libp2p-tcp", + "libp2p-uds", + "libp2p-wasm-ext", + "libp2p-websocket", + "libp2p-yamux", + "parity-multiaddr", + "parity-multihash", + "parking_lot 0.9.0", + "smallvec 0.6.13", + "tokio-codec", + "tokio-executor", + "tokio-io", + "wasm-timer", ] [[package]] @@ -1934,34 +2086,34 @@ name = "libp2p-core" version = "0.13.2" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "asn1_der 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "ed25519-dalek 1.0.0-pre.3 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libsecp256k1 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "multistream-select 0.6.1 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "parity-multiaddr 0.6.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "parity-multihash 0.2.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "asn1_der", + "bs58 0.3.0", + "bytes", + "ed25519-dalek", + "failure", + "fnv", + "futures", + "lazy_static", + "libsecp256k1 0.3.5", + "log 0.4.8", + "multistream-select", + "parity-multiaddr", + "parity-multihash", + "parking_lot 0.9.0", + "protobuf", + "quick-error", + "rand 0.7.3", + "ring", + "rw-stream-sink", + "sha2", + "smallvec 0.6.13", + "tokio-executor", + "tokio-io", + "unsigned-varint", + "untrusted", + "void", + "wasm-timer", + "zeroize 1.1.0", ] [[package]] @@ -1969,8 +2121,8 @@ name = "libp2p-core-derive" version = "0.13.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3", + "syn 1.0.16", ] [[package]] @@ -1978,10 +2130,10 @@ name = "libp2p-deflate" version = "0.5.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2", + "futures", + "libp2p-core", + "tokio-io", ] [[package]] @@ -1989,30 +2141,30 @@ name = "libp2p-discv5" version = "0.1.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "enr 0.1.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hkdf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-swarm 0.3.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libsecp256k1 0.3.1 (git+https://github.com/SigP/libsecp256k1?branch=ecdh_generalise)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.6.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "parity-multihash 0.2.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12", + "bigint", + "digest", + "enr", + "fnv", + "futures", + "hex 0.4.2", + "hkdf", + "libp2p-core", + "libp2p-swarm", + "libsecp256k1 0.3.1", + "log 0.4.8", + "openssl", + "parity-multiaddr", + "parity-multihash", + "rand 0.6.5", + "rlp", + "sha2", + "smallvec 0.6.13", + "tokio-io", + "tokio-timer 0.2.13", + "tokio-udp", + "void", + "zeroize 0.6.0", ] [[package]] @@ -2020,10 +2172,10 @@ name = "libp2p-dns" version = "0.13.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "libp2p-core", + "log 0.4.8", + "tokio-dns-unofficial", ] [[package]] @@ -2031,17 +2183,17 @@ name = "libp2p-floodsub" version = "0.13.1" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "cuckoofilter 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-swarm 0.3.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bs58 0.3.0", + "bytes", + "cuckoofilter", + "fnv", + "futures", + "libp2p-core", + "libp2p-swarm", + "protobuf", + "rand 0.6.5", + "smallvec 0.6.13", + "tokio-io", ] [[package]] @@ -2049,24 +2201,24 @@ name = "libp2p-gossipsub" version = "0.1.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bs58 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-swarm 0.3.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lru 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.10.1", + "bs58 0.2.5", + "byteorder 1.3.4", + "bytes", + "fnv", + "futures", + "libp2p-core", + "libp2p-swarm", + "log 0.4.8", + "lru 0.1.17", + "protobuf", + "rand 0.6.5", + "sha2", + "smallvec 1.2.0", + "tokio-codec", + "tokio-io", + "tokio-timer 0.2.13", + "unsigned-varint", ] [[package]] @@ -2074,18 +2226,18 @@ name = "libp2p-identify" version = "0.13.2" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-swarm 0.3.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.6.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "libp2p-core", + "libp2p-swarm", + "log 0.4.8", + "parity-multiaddr", + "protobuf", + "smallvec 0.6.13", + "tokio-codec", + "tokio-io", + "unsigned-varint", + "wasm-timer", ] [[package]] @@ -2093,26 +2245,26 @@ name = "libp2p-kad" version = "0.13.2" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-swarm 0.3.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.6.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "parity-multihash 0.2.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.5.1", + "bytes", + "either", + "fnv", + "futures", + "libp2p-core", + "libp2p-swarm", + "log 0.4.8", + "parity-multiaddr", + "parity-multihash", + "protobuf", + "rand 0.7.3", + "sha2", + "smallvec 0.6.13", + "tokio-codec", + "tokio-io", + "uint 0.8.2", + "unsigned-varint", + "void", + "wasm-timer", ] [[package]] @@ -2120,21 +2272,21 @@ name = "libp2p-mdns" version = "0.13.1" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-swarm 0.3.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.6.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "data-encoding", + "dns-parser", + "futures", + "libp2p-core", + "libp2p-swarm", + "log 0.4.8", + "net2", + "parity-multiaddr", + "rand 0.6.5", + "smallvec 0.6.13", + "tokio-io", + "tokio-reactor", + "tokio-udp", + "void", + "wasm-timer", ] [[package]] @@ -2142,15 +2294,15 @@ name = "libp2p-mplex" version = "0.13.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "fnv", + "futures", + "libp2p-core", + "log 0.4.8", + "parking_lot 0.9.0", + "tokio-codec", + "tokio-io", + "unsigned-varint", ] [[package]] @@ -2158,19 +2310,19 @@ name = "libp2p-noise" version = "0.11.1" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)", - "snow 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "x25519-dalek 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "curve25519-dalek 1.2.3", + "futures", + "lazy_static", + "libp2p-core", + "log 0.4.8", + "protobuf", + "rand 0.7.3", + "ring", + "snow", + "tokio-io", + "x25519-dalek", + "zeroize 1.1.0", ] [[package]] @@ -2178,16 +2330,16 @@ name = "libp2p-ping" version = "0.13.1" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "libp2p-swarm 0.3.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multiaddr 0.6.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "libp2p-core", + "libp2p-swarm", + "log 0.4.8", + "parity-multiaddr", + "rand 0.7.3", + "tokio-io", + "void", + "wasm-timer", ] [[package]] @@ -2195,14 +2347,14 @@ name = "libp2p-plaintext" version = "0.13.1" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "libp2p-core", + "log 0.4.8", + "protobuf", + "rw-stream-sink", + "tokio-io", + "void", ] [[package]] @@ -2210,28 +2362,28 @@ name = "libp2p-secio" version = "0.13.1" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", + "aes-ctr", + "bytes", + "ctr", + "futures", + "hmac", + "js-sys", + "lazy_static", + "libp2p-core", + "log 0.4.8", + "parity-send-wrapper", + "protobuf", + "rand 0.6.5", + "ring", + "rw-stream-sink", + "sha2", + "tokio-codec", + "tokio-io", + "twofish", + "untrusted", + "wasm-bindgen", + "wasm-bindgen-futures 0.3.27", + "web-sys", ] [[package]] @@ -2239,12 +2391,12 @@ name = "libp2p-swarm" version = "0.3.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "libp2p-core", + "smallvec 0.6.13", + "tokio-io", + "void", + "wasm-timer", ] [[package]] @@ -2252,15 +2404,15 @@ name = "libp2p-tcp" version = "0.13.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ipnet 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "get_if_addrs", + "ipnet", + "libp2p-core", + "log 0.4.8", + "tokio-io", + "tokio-tcp", + "tokio-timer 0.2.13", ] [[package]] @@ -2268,10 +2420,10 @@ name = "libp2p-uds" version = "0.13.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "libp2p-core", + "log 0.4.8", + "tokio-uds 0.2.6", ] [[package]] @@ -2279,13 +2431,13 @@ name = "libp2p-wasm-ext" version = "0.6.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "js-sys", + "libp2p-core", + "parity-send-wrapper", + "tokio-io", + "wasm-bindgen", + "wasm-bindgen-futures 0.3.27", ] [[package]] @@ -2293,17 +2445,17 @@ name = "libp2p-websocket" version = "0.13.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rw-stream-sink 0.1.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "soketto 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-rustls 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki-roots 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "libp2p-core", + "log 0.4.8", + "rw-stream-sink", + "soketto", + "tokio-codec", + "tokio-io", + "tokio-rustls", + "url 2.1.1", + "webpki-roots", ] [[package]] @@ -2311,11 +2463,11 @@ name = "libp2p-yamux" version = "0.13.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "yamux 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "libp2p-core", + "log 0.4.8", + "tokio-io", + "yamux", ] [[package]] @@ -2323,282 +2475,301 @@ name = "libsecp256k1" version = "0.3.1" source = "git+https://github.com/SigP/libsecp256k1?branch=ecdh_generalise#5858db8d1b280417f5866582df2cd0c63983d928" dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac-drbg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref", + "digest", + "hmac-drbg", + "rand 0.6.5", + "sha2", + "subtle 2.2.2", + "typenum", ] [[package]] name = "libsecp256k1" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962" dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hmac-drbg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref", + "crunchy 0.2.2", + "digest", + "hmac-drbg", + "rand 0.7.3", + "sha2", + "subtle 2.2.2", + "typenum", ] [[package]] name = "libz-sys" version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" dependencies = [ - "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "pkg-config", + "vcpkg", ] [[package]] name = "lighthouse" -version = "0.1.1" +version = "0.2.0" dependencies = [ - "account_manager 0.0.1", - "beacon_node 0.1.0", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "environment 0.1.0", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "logging 0.1.0", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-term 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sloggers 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "types 0.1.0", - "validator_client 0.1.0", + "account_manager", + "beacon_node", + "clap", + "env_logger 0.6.2", + "environment", + "futures", + "logging", + "slog", + "slog-async", + "slog-term", + "sloggers", + "tokio", + "types", + "validator_client", ] [[package]] name = "lighthouse_bootstrap" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "eth2-libp2p 0.1.0", - "eth2_config 0.1.0", - "reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "types 0.1.0", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "eth2-libp2p", + "eth2_config", + "reqwest", + "serde", + "slog", + "types", + "url 1.7.2", ] [[package]] name = "lighthouse_metrics" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "prometheus 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "prometheus", ] [[package]] name = "linked-hash-map" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" [[package]] name = "lock_api" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" dependencies = [ - "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref", + "scopeguard 0.3.3", ] [[package]] name = "lock_api" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff" dependencies = [ - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.1.0", ] [[package]] name = "lock_api" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" dependencies = [ - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.1.0", ] [[package]] name = "log" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8", ] [[package]] name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "logging" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lighthouse_metrics 0.1.0", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-term 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "lighthouse_metrics", + "slog", + "slog-term", ] [[package]] name = "lru" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d8f669d42c72d18514dfca8115689c5f6370a17d980cb5bd777a67f404594c8" dependencies = [ - "hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.5.0", ] [[package]] name = "lru" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0609345ddee5badacf857d4f547e0e5a2e987db77085c24cd887f73573a04237" dependencies = [ - "hashbrown 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "hashbrown 0.6.3", ] [[package]] name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "maybe-uninit" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.3.0" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" [[package]] name = "memoffset" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0", ] [[package]] name = "merkle_proof" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "eth2_hashing 0.1.1", - "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck_macros 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "eth2_hashing", + "ethereum-types 0.8.0", + "lazy_static", + "quickcheck", + "quickcheck_macros", ] [[package]] name = "milagro_bls" -version = "1.0.0" -source = "git+https://github.com/sigp/milagro_bls?branch=eth2.0-v0.10#52fab41dd086951ade699894b690e95ede1efafd" +version = "1.0.1" +source = "git+https://github.com/sigp/milagro_bls?branch=eth2.0-v0.10#9f946ca454ad1da4cd1344bd632b7306704bc904" dependencies = [ - "amcl 0.2.0 (git+https://github.com/sigp/milagro_bls?branch=eth2.0-v0.10)", - "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "amcl", + "hex 0.4.2", + "lazy_static", + "rand 0.7.3", + "yaml-rust", + "zeroize 1.1.0", ] [[package]] name = "mime" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9", ] [[package]] name = "mime" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "mime_guess" -version = "2.0.1" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212" dependencies = [ - "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.3.16", + "unicase 2.6.0", ] [[package]] name = "miniz_oxide" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa679ff6578b1cddee93d7e82e263b94a575e0bfced07284eb0c037c1d2416a5" dependencies = [ - "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "adler32", ] [[package]] name = "mio" version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log 0.4.8", + "miow", + "net2", + "slab 0.4.2", + "winapi 0.2.8", ] [[package]] name = "mio-extras" version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" dependencies = [ - "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell", + "log 0.4.8", + "mio", + "slab 0.4.2", ] [[package]] name = "mio-uds" version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" dependencies = [ - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec", + "libc", + "mio", ] [[package]] name = "miow" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", ] [[package]] @@ -2606,217 +2777,232 @@ name = "multistream-select" version = "0.6.1" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "log 0.4.8", + "smallvec 0.6.13", + "tokio-io", + "unsigned-varint", ] [[package]] name = "native-tls" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b0d88c06fe90d5ee94048ba40409ef1d9315d86f6f38c2efdaad4fb50c58b2d" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.53 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "libc", + "log 0.4.8", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", ] [[package]] name = "net2" version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "winapi 0.3.8", ] [[package]] name = "network" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "beacon_chain 0.1.0", - "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", - "eth2-libp2p 0.1.0", - "eth2_ssz 0.1.2", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "genesis 0.1.0", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rlp 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sloggers 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "store 0.1.0", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tree_hash 0.1.1", - "types 0.1.0", + "beacon_chain", + "error-chain", + "eth2-libp2p", + "eth2_ssz", + "fnv", + "futures", + "genesis", + "hashmap_delay", + "hex 0.3.2", + "parking_lot 0.9.0", + "rand 0.7.3", + "rest_types", + "rlp", + "slog", + "sloggers", + "slot_clock", + "smallvec 1.2.0", + "store", + "tempdir", + "tokio", + "tree_hash", + "types", ] [[package]] name = "nix" -version = "0.14.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "cc", + "cfg-if", + "libc", + "void", ] [[package]] name = "node_test_rig" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "beacon_node 0.1.0", - "environment 0.1.0", - "eth2_config 0.1.0", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "genesis 0.1.0", - "remote_beacon_node 0.1.0", - "reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "types 0.1.0", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "validator_client 0.1.0", + "beacon_node", + "environment", + "eth2_config", + "futures", + "genesis", + "remote_beacon_node", + "reqwest", + "serde", + "tempdir", + "types", + "url 1.7.2", + "validator_client", ] [[package]] name = "nodrop" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" [[package]] name = "nohash-hasher" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "nom" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "721a2bf1c26159ebf17e0a980bc4ce61f4b2fec5ec3b42d42fddd7a84a9e538f" [[package]] name = "num-bigint" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0", + "num-integer", + "num-traits", ] [[package]] name = "num-integer" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0", + "num-traits", ] [[package]] name = "num-traits" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0", ] [[package]] name = "num_cpus" -version = "1.11.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" dependencies = [ - "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", ] +[[package]] +name = "oorandom" +version = "11.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcec7c9c2a95cacc7cd0ecb89d8a8454eca13906f6deb55258ffff0adeb9405" + [[package]] name = "opaque-debug" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" [[package]] name = "openssl" -version = "0.10.26" +version = "0.10.28" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "973293749822d7dd6370d6da1e523b0d1db19f06c459134c658b2a4261378b52" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.53 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "cfg-if", + "foreign-types", + "lazy_static", + "libc", + "openssl-sys", ] [[package]] name = "openssl-probe" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" -version = "0.9.53" +version = "0.9.54" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1024c0a59774200a555087a6da3f253a9095a5f344e353b212ac4c8b8e450986" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0", + "cc", + "libc", + "pkg-config", + "vcpkg", ] [[package]] name = "operation_pool" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "eth2_ssz 0.1.2", - "eth2_ssz_derive 0.1.0", - "int_to_bytes 0.1.0", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "state_processing 0.1.0", - "store 0.1.0", - "types 0.1.0", + "eth2_ssz", + "eth2_ssz_derive", + "int_to_bytes", + "parking_lot 0.9.0", + "rand 0.7.3", + "serde", + "serde_derive", + "state_processing", + "store", + "types", ] [[package]] name = "owning_ref" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" dependencies = [ - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "stable_deref_trait", ] [[package]] name = "parity-codec" version = "3.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b9df1283109f542d8852cd6b30e9341acc2137481eb6157d2e62af68b0afec9" dependencies = [ - "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12", + "serde", ] [[package]] @@ -2824,16 +3010,16 @@ name = "parity-multiaddr" version = "0.6.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-multihash 0.2.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)", - "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref", + "bs58 0.3.0", + "byteorder 1.3.4", + "bytes", + "data-encoding", + "parity-multihash", + "percent-encoding 2.1.0", + "serde", + "unsigned-varint", + "url 2.1.1", ] [[package]] @@ -2841,680 +3027,775 @@ name = "parity-multihash" version = "0.2.0" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "blake2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2", + "bytes", + "rand 0.6.5", + "sha-1", + "sha2", + "sha3", + "unsigned-varint", ] [[package]] name = "parity-scale-codec" -version = "1.1.2" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f509c5e67ca0605ee17dcd3f91ef41cadd685c75a298fb6261b781a5acb3f910" dependencies = [ - "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bitvec 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-slice-cast 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.5.1", + "bitvec", + "byte-slice-cast", + "serde", ] [[package]] name = "parity-send-wrapper" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" [[package]] name = "parking_lot" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" dependencies = [ - "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.1.5", + "parking_lot_core 0.4.0", ] [[package]] name = "parking_lot" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7" dependencies = [ - "lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.2.0", + "parking_lot_core 0.5.0", + "rustc_version", ] [[package]] name = "parking_lot" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" dependencies = [ - "lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.3.3", + "parking_lot_core 0.6.2", + "rustc_version", +] + +[[package]] +name = "parking_lot" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" +dependencies = [ + "lock_api 0.3.3", + "parking_lot_core 0.7.0", ] [[package]] name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand 0.6.5", + "rustc_version", + "smallvec 0.6.13", + "winapi 0.3.8", ] [[package]] name = "parking_lot_core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "cloudabi", + "libc", + "rand 0.6.5", + "redox_syscall", + "rustc_version", + "smallvec 0.6.13", + "winapi 0.3.8", ] [[package]] name = "parking_lot_core" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "rustc_version", + "smallvec 0.6.13", + "winapi 0.3.8", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "smallvec 1.2.0", + "winapi 0.3.8", ] [[package]] name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" [[package]] name = "percent-encoding" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pkg-config" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" + +[[package]] +name = "plotters" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3bb8da247d27ae212529352020f3e5ee16e83c0c258061d27b08ab92675eeb" +dependencies = [ + "js-sys", + "num-traits", + "wasm-bindgen", + "web-sys", +] [[package]] name = "ppv-lite86" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" [[package]] name = "primitive-types" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2288eb2a39386c4bc817974cc413afe173010dc80e470fcb1e9a35580869f024" dependencies = [ - "fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-rlp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fixed-hash 0.3.2", + "impl-codec 0.2.0", + "impl-rlp", + "impl-serde 0.2.3", + "uint 0.7.1", ] [[package]] name = "primitive-types" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4336f4f5d5524fa60bcbd6fe626f9223d8142a50e7053e979acdf0da41ab975" dependencies = [ - "fixed-hash 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-codec 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-rlp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "impl-serde 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "uint 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fixed-hash 0.5.2", + "impl-codec 0.4.2", + "impl-rlp", + "impl-serde 0.3.0", + "uint 0.8.2", ] [[package]] name = "proc-macro-hack" version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" dependencies = [ - "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9", + "quote 1.0.3", + "syn 1.0.16", ] [[package]] name = "proc-macro2" version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0", ] [[package]] name = "proc-macro2" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0", ] [[package]] name = "prometheus" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5567486d5778e2c6455b1b90ff1c558f29e751fc018130fa182e15828e728af1" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "fnv", + "lazy_static", + "protobuf", + "quick-error", + "spin", ] [[package]] name = "proto_array_fork_choice" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "eth2_ssz 0.1.2", - "eth2_ssz_derive 0.1.0", - "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", - "types 0.1.0", + "eth2_ssz", + "eth2_ssz_derive", + "itertools", + "parking_lot 0.9.0", + "serde", + "serde_derive", + "serde_yaml", + "types", ] [[package]] name = "protobuf" version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40361836defdd5871ff7e84096c6f6444af7fc157f8ef1789f54f147687caa20" [[package]] name = "publicsuffix" version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" dependencies = [ - "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", - "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain", + "idna 0.2.0", + "lazy_static", + "regex", + "url 2.1.1", ] [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quickcheck" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44883e74aa97ad63db83c4bf8ca490f02b2fc02f92575e720c8551e843c945f" dependencies = [ - "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.1", + "log 0.4.8", + "rand 0.7.3", + "rand_core 0.5.1", ] [[package]] name = "quickcheck_macros" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7dfc1c4a1e048f5cc7d36a4c4118dfcf31d217c79f4b9a61bad65d68185752c" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", ] [[package]] name = "quote" version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", ] [[package]] name = "quote" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" dependencies = [ - "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9", ] [[package]] name = "rand" version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand 0.4.6", ] [[package]] name = "rand" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi 0.3.8", ] [[package]] name = "rand" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "winapi 0.3.8", ] [[package]] name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc 0.1.0", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift 0.1.1", + "winapi 0.3.8", ] [[package]] name = "rand" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", ] [[package]] name = "rand_chacha" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7", + "rand_core 0.3.1", ] [[package]] name = "rand_chacha" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ - "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core 0.5.1", ] [[package]] name = "rand_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" dependencies = [ - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2", ] [[package]] name = "rand_core" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", ] [[package]] name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1", ] [[package]] name = "rand_isaac" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1", ] [[package]] name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand_core 0.4.2", + "winapi 0.3.8", ] [[package]] name = "rand_os" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_os" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi 0.3.8", ] [[package]] name = "rand_pcg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7", + "rand_core 0.4.2", ] [[package]] name = "rand_xorshift" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1", ] [[package]] name = "rand_xorshift" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_xoshiro" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1", ] [[package]] name = "rayon" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098" dependencies = [ - "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque", + "either", + "rayon-core", ] [[package]] name = "rayon-core" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9" dependencies = [ - "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque", + "crossbeam-queue", + "crossbeam-utils 0.7.2", + "lazy_static", + "num_cpus", ] [[package]] name = "rdrand" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1", ] [[package]] name = "redox_syscall" version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" [[package]] name = "redox_users" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" dependencies = [ - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "redox_syscall", + "rust-argon2", ] [[package]] name = "regex" -version = "1.3.3" +version = "1.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8900ebc1363efa7ea1c399ccc32daed870b4002651e0bed86e72d501ebbe0048" dependencies = [ - "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", ] [[package]] name = "regex-automata" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", ] [[package]] name = "regex-syntax" -version = "0.6.13" +version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" [[package]] name = "remote_beacon_node" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "eth2_config 0.1.0", - "eth2_ssz 0.1.2", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "operation_pool 0.1.0", - "proto_array_fork_choice 0.1.0", - "reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "rest_api 0.1.0", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "types 0.1.0", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "eth2_config", + "eth2_ssz", + "futures", + "hex 0.3.2", + "operation_pool", + "proto_array_fork_choice", + "reqwest", + "rest_types", + "serde", + "serde_json", + "types", + "url 1.7.2", ] [[package]] name = "remove_dir_all" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8", ] [[package]] name = "reqwest" version = "0.9.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f88643aea3c1343c804950d7bf983bd2067f5ab59db6d613a08e05572f2714ab" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.10.1", + "bytes", + "cookie", + "cookie_store", + "encoding_rs", + "flate2", + "futures", + "http", + "hyper 0.12.35", + "hyper-tls", + "log 0.4.8", + "mime 0.3.16", + "mime_guess", + "native-tls", + "serde", + "serde_json", + "serde_urlencoded", + "time", + "tokio", + "tokio-executor", + "tokio-io", + "tokio-threadpool", + "tokio-timer 0.2.13", + "url 1.7.2", + "uuid", + "winreg", ] [[package]] name = "rest_api" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "beacon_chain 0.1.0", - "bls 0.1.0", - "eth2-libp2p 0.1.0", - "eth2_config 0.1.0", - "eth2_ssz 0.1.2", - "eth2_ssz_derive 0.1.0", - "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lighthouse_metrics 0.1.0", - "network 0.1.0", - "node_test_rig 0.1.0", - "operation_pool 0.1.0", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "remote_beacon_node 0.1.0", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-term 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slot_clock 0.1.0", - "state_processing 0.1.0", - "store 0.1.0", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tree_hash 0.1.1", - "types 0.1.0", - "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "version 0.1.0", + "beacon_chain", + "bls", + "eth2-libp2p", + "eth2_config", + "eth2_ssz", + "eth2_ssz_derive", + "futures", + "hex 0.3.2", + "http", + "hyper 0.12.35", + "lazy_static", + "lighthouse_metrics", + "network", + "node_test_rig", + "operation_pool", + "parking_lot 0.9.0", + "rayon", + "remote_beacon_node", + "rest_types", + "serde", + "serde_json", + "serde_yaml", + "slog", + "slog-async", + "slog-term", + "slot_clock", + "state_processing", + "store", + "tokio", + "tree_hash", + "types", + "url 2.1.1", + "version", +] + +[[package]] +name = "rest_types" +version = "0.2.0" +dependencies = [ + "bls", + "eth2_hashing", + "eth2_ssz", + "eth2_ssz_derive", + "rayon", + "serde", + "tree_hash", + "types", ] [[package]] name = "ring" -version = "0.16.9" +version = "0.16.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "741ba1704ae21999c00942f9f5944f801e977f54302af346b596287599ad1862" dependencies = [ - "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "lazy_static", + "libc", + "spin", + "untrusted", + "web-sys", + "winapi 0.3.8", ] [[package]] name = "rle-decode-fast" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" [[package]] name = "rlp" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a7d3f9bed94764eac15b8f14af59fac420c236adaff743b7bcc88e265cb4345" dependencies = [ - "rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex", ] [[package]] name = "rust-argon2" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.11.0", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils 0.7.2", ] [[package]] name = "rustc-demangle" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" [[package]] name = "rustc-hex" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" [[package]] name = "rustc_version" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver", ] [[package]] name = "rustls" version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b25a18b1bf7387f0145e7f8324e700805aade3842dd3db2e74e4cdeb4677c09e" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)", - "sct 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.10.1", + "log 0.4.8", + "ring", + "sct", + "webpki", ] [[package]] @@ -3522,2051 +3803,1721 @@ name = "rw-stream-sink" version = "0.1.2" source = "git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5#49c95c4c4242f1c9f08558a3daac5e9ecac290d5" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "tokio-io", ] [[package]] name = "ryu" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" [[package]] name = "safemem" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ - "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util", ] [[package]] name = "schannel" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507a9e6e8ffe0a4e0ebb9a10293e62fdf7657c06f1b8bb07a8fcf697d2abf295" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", + "winapi 0.3.8", ] [[package]] name = "scoped-tls" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" [[package]] name = "scoped-tls" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" [[package]] name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" [[package]] name = "scopeguard" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "sct" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c" dependencies = [ - "ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ring", + "untrusted", ] [[package]] name = "security-framework" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97bbedbe81904398b6ebb054b3e912f99d55807125790f3198ac990d98def5b0" dependencies = [ - "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1", + "core-foundation", + "core-foundation-sys", + "security-framework-sys", ] [[package]] name = "security-framework-sys" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06fd2f23e31ef68dd2328cc383bd493142e46107a3a0e24f7d734e3f3b80fe4c" dependencies = [ - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys", + "libc", ] [[package]] name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver-parser", ] [[package]] name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "send_wrapper" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eddf2e8f50ced781f288c19f18621fa72a3779e3cb58dbf23b07469b0abeb4" [[package]] name = "serde" version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" dependencies = [ - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" dependencies = [ - "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9", + "quote 1.0.3", + "syn 1.0.16", ] [[package]] name = "serde_hex" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2", + "serde", ] [[package]] name = "serde_json" -version = "1.0.44" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25" dependencies = [ - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "ryu", + "serde", ] [[package]] name = "serde_repr" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573" dependencies = [ - "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9", + "quote 1.0.3", + "syn 1.0.16", ] [[package]] name = "serde_urlencoded" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" dependencies = [ - "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dtoa", + "itoa", + "serde", + "url 1.7.2", ] [[package]] name = "serde_yaml" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" dependencies = [ - "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "dtoa", + "linked-hash-map", + "serde", + "yaml-rust", ] [[package]] name = "sha-1" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", ] [[package]] name = "sha1" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" [[package]] name = "sha2" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0" dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", ] [[package]] name = "sha3" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" dependencies = [ - "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-buffer", + "byte-tools", + "digest", + "keccak", + "opaque-debug", ] [[package]] name = "simple_logger" -version = "1.4.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0c4611f32f4c2bac73754f22dca1f57e6c1945e0590dae4e5f2a077b92367" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "chrono", + "colored", + "log 0.4.8", + "winapi 0.3.8", ] [[package]] name = "simulator" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "eth1_test_rig 0.1.0", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "node_test_rig 0.1.0", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "types 0.1.0", - "validator_client 0.1.0", + "clap", + "env_logger 0.7.1", + "eth1_test_rig", + "futures", + "node_test_rig", + "parking_lot 0.9.0", + "tokio", + "types", + "validator_client", ] [[package]] name = "slab" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" [[package]] name = "slab" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "slog" version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cc9c640a4adbfbcc11ffb95efe5aa7af7309e002adab54b185507dbf2377b99" [[package]] name = "slog-async" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca925b180da88ccc595cbe4a3d378d79cb49fe5906c2cbc2488eaf700913ee" dependencies = [ - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.9", + "slog", + "take_mut", + "thread_local", ] [[package]] name = "slog-json" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc0d2aff1f8f325ef660d9a0eb6e6dcd20b30b3f581a5897f58bf42d061c37a" dependencies = [ - "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono", + "serde", + "serde_json", + "slog", ] [[package]] name = "slog-kvfilter" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae939ed7d169eed9699f4f5cd440f046f5dc5dfc27c19e3cd311619594c175e0" dependencies = [ - "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex", + "slog", ] [[package]] name = "slog-scope" version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c44c89dd8b0ae4537d1ae318353eaf7840b4869c536e31c41e963d1ea523ee6" dependencies = [ - "arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "arc-swap", + "lazy_static", + "slog", ] [[package]] name = "slog-stdlog" version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1c469573d1e3f36f9eee66cd132206caf47b50c94b1f6c6e7b4d8235e9ecf01" dependencies = [ - "crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-scope 4.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam 0.2.12", + "log 0.3.9", + "slog", + "slog-scope", ] [[package]] name = "slog-stdlog" version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d87903baf655da2d82bc3ac3f7ef43868c58bf712b3a661fda72009304c23" dependencies = [ - "crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-scope 4.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam 0.7.3", + "log 0.4.8", + "slog", + "slog-scope", ] [[package]] name = "slog-term" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "124501187c410b6a46fe8a47a48435ae462fae4e02d03c558d358f40b17308cb" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "chrono", + "slog", + "term", + "thread_local", ] [[package]] name = "sloggers" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d41aa58f9a02e205e21117ffa08e94c37f06e1f1009be2639b621f351a75796d" dependencies = [ - "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libflate 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-kvfilter 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-scope 4.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-stdlog 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-term 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "trackable 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono", + "libflate", + "regex", + "serde", + "serde_derive", + "slog", + "slog-async", + "slog-kvfilter", + "slog-scope", + "slog-stdlog 3.0.5", + "slog-term", + "trackable", ] [[package]] name = "slot_clock" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lighthouse_metrics 0.1.0", - "types 0.1.0", + "lazy_static", + "lighthouse_metrics", + "parking_lot 0.9.0", + "types", ] [[package]] name = "smallvec" version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" dependencies = [ - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "maybe-uninit", ] [[package]] name = "smallvec" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" [[package]] name = "snow" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb767eee7d257ba202f0b9b08673bc13b22281632ef45267b19f13100accd2f" dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref", + "rand_core 0.5.1", + "ring", + "rustc_version", + "subtle 2.2.2", ] [[package]] name = "soketto" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bceb1a3a15232d013d9a3b7cac9e5ce8e2313f348f01d4bc1097e5e53aa07095" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.10.1", + "bytes", + "flate2", + "futures", + "http", + "httparse", + "log 0.4.8", + "rand 0.6.5", + "sha1", + "smallvec 0.6.13", + "tokio-codec", + "tokio-io", ] -[[package]] -name = "sourcefile" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "spin" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "stable_deref_trait" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" [[package]] name = "state_processing" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "beacon_chain 0.1.0", - "bls 0.1.0", - "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "eth2_hashing 0.1.1", - "eth2_ssz 0.1.2", - "eth2_ssz_types 0.2.0", - "int_to_bytes 0.1.0", - "integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "merkle_proof 0.1.0", - "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", - "store 0.1.0", - "tree_hash 0.1.1", - "tree_hash_derive 0.2.0", - "types 0.1.0", + "beacon_chain", + "bls", + "criterion", + "env_logger 0.7.1", + "eth2_hashing", + "eth2_ssz", + "eth2_ssz_types", + "int_to_bytes", + "integer-sqrt", + "itertools", + "lazy_static", + "log 0.4.8", + "merkle_proof", + "rayon", + "serde", + "serde_derive", + "serde_yaml", + "store", + "tree_hash", + "tree_hash_derive", + "types", ] [[package]] name = "static_assertions" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "store" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "db-key 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "eth2_ssz 0.1.2", - "eth2_ssz_derive 0.1.0", - "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "leveldb 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", - "lighthouse_metrics 0.1.0", - "lru 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sloggers 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "state_processing 0.1.0", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tree_hash 0.1.1", - "types 0.1.0", + "criterion", + "db-key", + "eth2_ssz", + "eth2_ssz_derive", + "itertools", + "lazy_static", + "leveldb", + "lighthouse_metrics", + "lru 0.4.3", + "parking_lot 0.9.0", + "rayon", + "serde", + "serde_derive", + "slog", + "sloggers", + "state_processing", + "tempfile", + "tree_hash", + "types", ] [[package]] name = "stream-cipher" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c" dependencies = [ - "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array", ] [[package]] name = "string" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", ] [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "subtle" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" [[package]] name = "subtle" version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941" [[package]] name = "swap_or_not_shuffle" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "eth2_hashing 0.1.1", - "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion", + "eth2_hashing", + "ethereum-types 0.8.0", + "hex 0.3.2", + "yaml-rust", ] [[package]] name = "syn" version = "0.15.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", ] [[package]] name = "syn" -version = "1.0.13" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" dependencies = [ - "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9", + "quote 1.0.3", + "unicode-xid 0.2.0", ] [[package]] name = "synstructure" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" dependencies = [ - "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9", + "quote 1.0.3", + "syn 1.0.16", + "unicode-xid 0.2.0", ] [[package]] name = "take_mut" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" [[package]] name = "target_info" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe" [[package]] name = "tempdir" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" dependencies = [ - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6", + "remove_dir_all", ] [[package]] name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "rand 0.7.3", + "redox_syscall", + "remove_dir_all", + "winapi 0.3.8", ] [[package]] name = "term" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" dependencies = [ - "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs", + "winapi 0.3.8", ] [[package]] name = "termcolor" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" dependencies = [ - "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util", ] [[package]] name = "test_random_derive" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13", + "syn 0.15.44", ] [[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ - "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width", ] [[package]] name = "thread_local" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", ] [[package]] name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "redox_syscall", + "winapi 0.3.8", +] + +[[package]] +name = "timer" +version = "0.2.0" +dependencies = [ + "beacon_chain", + "futures", + "parking_lot 0.10.0", + "slog", + "slot_clock", + "tokio", + "types", ] [[package]] name = "tiny-keccak" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d8a021c69bb74a44ccedb824a046447e2c84a01df9e5c20779750acb38e11b2" dependencies = [ - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.2.2", ] [[package]] name = "tinytemplate" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a3c6667d3e65eb1bc3aed6fd14011c6cbc3a0665218ab7f5daf040b9ec371a" dependencies = [ - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", + "serde_json", ] [[package]] name = "tokio" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "mio", + "num_cpus", + "tokio-codec", + "tokio-current-thread", + "tokio-executor", + "tokio-fs", + "tokio-io", + "tokio-reactor", + "tokio-sync", + "tokio-tcp", + "tokio-threadpool", + "tokio-timer 0.2.13", + "tokio-udp", + "tokio-uds 0.2.6", ] [[package]] name = "tokio-buf" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "either", + "futures", ] [[package]] name = "tokio-codec" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "tokio-io", ] [[package]] name = "tokio-core" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "iovec", + "log 0.4.8", + "mio", + "scoped-tls 0.1.2", + "tokio", + "tokio-executor", + "tokio-io", + "tokio-reactor", + "tokio-timer 0.2.13", ] [[package]] name = "tokio-current-thread" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "tokio-executor", ] [[package]] name = "tokio-dns-unofficial" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c65483db54eb91b4ef3a9389a3364558590faf30ce473141707c0e16fda975" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "futures-cpupool", + "lazy_static", + "tokio", ] [[package]] name = "tokio-executor" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" dependencies = [ - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2", + "futures", ] [[package]] name = "tokio-fs" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "tokio-io", + "tokio-threadpool", ] [[package]] name = "tokio-io" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "log 0.4.8", ] [[package]] name = "tokio-io-timeout" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ce81f15cfd7982fac684f9057a1299eebeb79e98a8a709969b9aa51123129" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "tokio-io", + "tokio-timer 0.2.13", ] [[package]] name = "tokio-reactor" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" dependencies = [ - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2", + "futures", + "lazy_static", + "log 0.4.8", + "mio", + "num_cpus", + "parking_lot 0.9.0", + "slab 0.4.2", + "tokio-executor", + "tokio-io", + "tokio-sync", ] [[package]] name = "tokio-rustls" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d7cf08f990090abd6c6a73cab46fed62f85e8aef8b99e4b918a9f4a637f0676" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rustls 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "iovec", + "rustls", + "tokio-io", + "webpki", ] [[package]] name = "tokio-sync" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" dependencies = [ - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv", + "futures", ] [[package]] name = "tokio-tcp" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "iovec", + "mio", + "tokio-io", + "tokio-reactor", ] [[package]] name = "tokio-threadpool" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" dependencies = [ - "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque", + "crossbeam-queue", + "crossbeam-utils 0.7.2", + "futures", + "lazy_static", + "log 0.4.8", + "num_cpus", + "slab 0.4.2", + "tokio-executor", ] [[package]] name = "tokio-timer" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6131e780037787ff1b3f8aad9da83bca02438b72277850dd6ad0d455e0e20efc" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "slab 0.3.0", ] [[package]] name = "tokio-timer" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" dependencies = [ - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2", + "futures", + "slab 0.4.2", + "tokio-executor", ] [[package]] name = "tokio-tls" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "354b8cd83825b3c20217a9dc174d6a0c67441a2fae5c41bcb1ea6679f6ae0f7c" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "native-tls", + "tokio-io", ] [[package]] name = "tokio-udp" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "log 0.4.8", + "mio", + "tokio-codec", + "tokio-io", + "tokio-reactor", ] [[package]] name = "tokio-uds" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65ae5d255ce739e8537221ed2942e0445f4b3b813daebac1c0050ddaaa3587f9" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "iovec", + "libc", + "log 0.3.9", + "mio", + "mio-uds", + "tokio-core", + "tokio-io", ] [[package]] name = "tokio-uds" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5076db410d6fdc6523df7595447629099a1fdc47b3d9f896220780fa48faf798" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "iovec", + "libc", + "log 0.4.8", + "mio", + "mio-uds", + "tokio-codec", + "tokio-io", + "tokio-reactor", ] [[package]] name = "toml" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" dependencies = [ - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] name = "trackable" version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11475c3c53b075360eac9794965822cb053996046545f91cf61d90e00b72efa5" dependencies = [ - "trackable_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "trackable_derive", ] [[package]] name = "trackable_derive" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcf0b9b2caa5f4804ef77aeee1b929629853d806117c48258f402b69737e65c" dependencies = [ - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3", + "syn 1.0.16", ] [[package]] name = "traitobject" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" [[package]] name = "tree_hash" version = "0.1.1" dependencies = [ - "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "eth2_hashing 0.1.1", - "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tree_hash_derive 0.2.0", - "types 0.1.0", + "criterion", + "eth2_hashing", + "ethereum-types 0.8.0", + "lazy_static", + "rand 0.7.3", + "smallvec 1.2.0", + "tree_hash_derive", + "types", ] [[package]] name = "tree_hash_derive" version = "0.2.0" dependencies = [ - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13", + "syn 0.15.44", ] [[package]] name = "try-lock" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" [[package]] name = "try_from" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "twofish" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712d261e83e727c8e2dbb75dacac67c36e35db36a958ee504f2164fc052434e1" dependencies = [ - "block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "block-cipher-trait", + "byteorder 1.3.4", + "opaque-debug", ] [[package]] name = "typeable" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" [[package]] name = "typenum" version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" [[package]] name = "types" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "bls 0.1.0", - "cached_tree_hash 0.1.0", - "compare_fields 0.1.0", - "compare_fields_derive 0.1.0", - "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "eth2_hashing 0.1.1", - "eth2_interop_keypairs 0.1.0", - "eth2_ssz 0.1.2", - "eth2_ssz_derive 0.1.0", - "eth2_ssz_types 0.2.0", - "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "int_to_bytes 0.1.0", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "merkle_proof 0.1.0", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "swap_or_not_shuffle 0.1.0", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "test_random_derive 0.1.0", - "tree_hash 0.1.1", - "tree_hash_derive 0.2.0", + "bls", + "cached_tree_hash", + "compare_fields", + "compare_fields_derive", + "criterion", + "derivative", + "dirs", + "env_logger 0.7.1", + "eth2_hashing", + "eth2_interop_keypairs", + "eth2_ssz", + "eth2_ssz_derive", + "eth2_ssz_types", + "ethereum-types 0.8.0", + "hex 0.3.2", + "int_to_bytes", + "log 0.4.8", + "merkle_proof", + "rand 0.7.3", + "rand_xorshift 0.2.0", + "rayon", + "serde", + "serde_derive", + "serde_json", + "serde_yaml", + "slog", + "swap_or_not_shuffle", + "tempfile", + "test_random_derive", + "tree_hash", + "tree_hash_derive", ] [[package]] name = "uint" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2143cded94692b156c356508d92888acc824db5bffc0b4089732264c6fcf86d4" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", + "crunchy 0.2.2", + "heapsize", + "rustc-hex", ] [[package]] name = "uint" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e75a4cdd7b87b28840dba13c483b9a88ee6bbf16ba5c951ee1ecfcf723078e0d" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", + "crunchy 0.2.2", + "rustc-hex", + "static_assertions 1.1.0", ] [[package]] name = "unicase" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" dependencies = [ - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5", ] [[package]] name = "unicase" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" dependencies = [ - "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.9.1", ] [[package]] name = "unicode-bidi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", ] [[package]] name = "unicode-normalization" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" dependencies = [ - "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.2.0", ] -[[package]] -name = "unicode-segmentation" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" [[package]] name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" [[package]] name = "unsigned-varint" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f0023a96687fe169081e8adce3f65e3874426b7886e9234d490af2dc077959" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "tokio-codec", ] [[package]] name = "untrusted" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60369ef7a31de49bcb3f6ca728d4ba7300d9a1658f94c727d4cab8c8d9f4aece" [[package]] name = "url" version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" dependencies = [ - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5", + "matches", + "percent-encoding 1.0.1", ] [[package]] name = "url" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" dependencies = [ - "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.2.0", + "matches", + "percent-encoding 2.1.0", ] [[package]] name = "uuid" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" dependencies = [ - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5", ] [[package]] name = "validator_client" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bls 0.1.0", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "deposit_contract 0.1.0", - "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "environment 0.1.0", - "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", - "eth2_config 0.1.0", - "eth2_interop_keypairs 0.1.0", - "eth2_ssz 0.1.2", - "eth2_ssz_derive 0.1.0", - "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "lighthouse_bootstrap 0.1.0", - "logging 0.1.0", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "remote_beacon_node 0.1.0", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slog-term 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slot_clock 0.1.0", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tree_hash 0.1.1", - "types 0.1.0", + "bincode", + "bls", + "clap", + "deposit_contract", + "dirs", + "environment", + "error-chain", + "eth2_config", + "eth2_interop_keypairs", + "eth2_ssz", + "eth2_ssz_derive", + "exit-future", + "futures", + "hex 0.3.2", + "libc", + "lighthouse_bootstrap", + "logging", + "parking_lot 0.7.1", + "rayon", + "remote_beacon_node", + "rest_types", + "serde", + "serde_derive", + "serde_json", + "slog", + "slog-async", + "slog-term", + "slot_clock", + "tempdir", + "tokio", + "tokio-timer 0.2.13", + "tree_hash", + "types", ] [[package]] name = "vcpkg" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" [[package]] name = "vec_map" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" [[package]] name = "version" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "target_info", ] [[package]] name = "version_check" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" [[package]] name = "version_check" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" [[package]] name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "walkdir" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" dependencies = [ - "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file", + "winapi 0.3.8", + "winapi-util", ] [[package]] name = "want" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "log 0.4.8", + "try-lock", ] [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasm-bindgen" -version = "0.2.58" +version = "0.2.59" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3557c397ab5a8e347d434782bcd31fc1483d927a6826804cec05cc792ee2519d" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.58" +version = "0.2.59" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0da9c9a19850d3af6df1cb9574970b566d617ecfaf36eb0b706b6f3ef9bd2f8" dependencies = [ - "bumpalo 3.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "bumpalo", + "lazy_static", + "log 0.4.8", + "proc-macro2 1.0.9", + "quote 1.0.3", + "syn 1.0.16", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83420b37346c311b9ed822af41ec2e82839bfe99867ec6c54e2da43b7538771c" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "futures", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "457414a91863c0ec00090dba537f88ab955d93ca6555862c29b6d860990b8a8a" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.58" +version = "0.2.59" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f6fde1d36e75a714b5fe0cffbb78978f222ea6baebb726af13c78869fdb4205" dependencies = [ - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro-support 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3", + "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.58" +version = "0.2.59" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25bda4168030a6412ea8a047e27238cadf56f0e53516e1e83fec0a8b7c786f6d" dependencies = [ - "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9", + "quote 1.0.3", + "syn 1.0.16", + "wasm-bindgen-backend", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.58" +version = "0.2.59" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc9f36ad51f25b0219a3d4d13b90eb44cd075dff8b6280cca015775d7acaddd8" [[package]] name = "wasm-bindgen-test" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "449aeba7035e4a4710cd263bbac33519fa3828bff1c6f642fa8896601e7016ad" dependencies = [ - "console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-futures 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-test-macro 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "console_error_panic_hook", + "js-sys", + "scoped-tls 1.0.0", + "wasm-bindgen", + "wasm-bindgen-futures 0.4.9", + "wasm-bindgen-test-macro", ] [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49449f8dcedc192bd0cf11b5711982decdd4dbad1029f92370e2b1215031dd59" dependencies = [ - "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "wasm-bindgen-webidl" -version = "0.2.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9", + "quote 1.0.3", ] [[package]] name = "wasm-timer" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa3e01d234bb71760e685cfafa5e2c96f8ad877c161a721646356651069e26ac" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", - "send_wrapper 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "js-sys", + "send_wrapper", + "tokio-timer 0.2.13", + "wasm-bindgen", + "web-sys", ] [[package]] name = "web-sys" -version = "0.3.35" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721c6263e2c66fd44501cc5efbfa2b7dfa775d13e4ea38c46299646ed1f9c70a" dependencies = [ - "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", - "sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-webidl 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys", + "wasm-bindgen", ] [[package]] name = "web3" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076f34ed252d74a8521e3b013254b1a39f94a98f23aae7cfc85cda6e7b395664" dependencies = [ - "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethabi 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethereum-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "websocket 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12", + "base64 0.10.1", + "derive_more", + "ethabi 8.0.1", + "ethereum-types 0.6.0", + "futures", + "hyper 0.12.35", + "hyper-tls", + "jsonrpc-core", + "log 0.4.8", + "native-tls", + "parking_lot 0.8.0", + "rustc-hex", + "serde", + "serde_json", + "tokio-core", + "tokio-io", + "tokio-timer 0.1.2", + "tokio-uds 0.1.7", + "url 1.7.2", + "websocket", ] [[package]] name = "webpki" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f50e1972865d6b1adb54167d1c8ed48606004c2c9d0ea5f1eeb34d95e863ef" dependencies = [ - "ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ring", + "untrusted", ] [[package]] name = "webpki-roots" version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cd5736df7f12a964a5067a12c62fa38e1bd8080aff1f80bc29be7c80d19ab4" dependencies = [ - "webpki 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki", ] [[package]] name = "websocket" version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9faed2bff8af2ea6b9f8b917d3d00b467583f6781fe3def174a9e33c879703" dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.9.3", + "bitflags 0.9.1", + "byteorder 1.3.4", + "bytes", + "futures", + "hyper 0.10.16", + "native-tls", + "rand 0.5.6", + "sha1", + "tokio-core", + "tokio-io", + "tokio-tls", + "unicase 1.4.2", + "url 1.7.2", ] [[package]] name = "websocket_server" -version = "0.1.0" +version = "0.2.0" dependencies = [ - "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "types 0.1.0", - "ws 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "weedle" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "serde", + "serde_derive", + "serde_json", + "slog", + "tokio", + "types", + "ws", ] [[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" [[package]] name = "winapi" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winreg" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8", ] [[package]] name = "ws" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51a2c47b5798ccc774ffb93ff536aec7c4275d722fd9c740c83cdd1af1f2d94" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-extras 2.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4", + "bytes", + "httparse", + "log 0.4.8", + "mio", + "mio-extras", + "rand 0.7.3", + "sha-1", + "slab 0.4.2", + "url 2.1.1", ] [[package]] name = "ws2_32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8", + "winapi-build", ] [[package]] name = "x25519-dalek" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee1585dc1484373cbc1cee7aafda26634665cf449436fd6e24bfd1fad230538" dependencies = [ - "clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clear_on_drop", + "curve25519-dalek 1.2.3", + "rand_core 0.3.1", ] [[package]] name = "yaml-rust" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" dependencies = [ - "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map", ] [[package]] name = "yamux" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2758f29014c1cb7a6e74c1b1160ac8c8203be342d35b73462fc6a13cc6385423" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "nohash-hasher 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "log 0.4.8", + "nohash-hasher", + "parking_lot 0.9.0", + "quick-error", + "rand 0.7.3", + "tokio-codec", + "tokio-io", ] [[package]] name = "zeroize" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e68403b858b6af538b11614e62dfe9ab2facba9f13a0cafb974855cfb495ec95" dependencies = [ - "zeroize_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zeroize_derive", ] [[package]] name = "zeroize" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8" [[package]] name = "zeroize_derive" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3f07490820219949839d0027b965ffdd659d75be9220c00798762e36c6cd281" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", ] - -[metadata] -"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" -"checksum aes-ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2e5b0458ea3beae0d1d8c0f3946564f8e10f90646cf78c06b4351052058d1ee" -"checksum aes-soft 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" -"checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" -"checksum ahash 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6f33b5018f120946c1dcf279194f238a9f146725593ead1c08fa47ff22b0b5d3" -"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" -"checksum amcl 0.2.0 (git+https://github.com/sigp/milagro_bls?branch=eth2.0-v0.10)" = "" -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c" -"checksum arc-swap 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b8a9123b8027467bce0099fe556c628a53c8d83df0507084c31e9ba2e39aff" -"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" -"checksum asn1_der 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6fce6b6a0ffdafebd82c87e79e3f40e8d2c523e5fea5566ff6b90509bf98d638" -"checksum asn1_der_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d0864d84b8e07b145449be9a8537db86bf9de5ce03b913214694643b4743502" -"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -"checksum backtrace 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)" = "a4ed64ae6d9ebfd9893193c4b2532b1292ec97bd8271c9d7d0fa90cd78a34cba" -"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" -"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" -"checksum bigint 4.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebecac13b3c745150d7b6c3ea7572d372f09d627c2077e893bf26c5c7f70d282" -"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf" -"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum bitvec 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a993f74b4c99c1908d156b8d2e0fb6277736b0ecbd833982fd1241d39b2766a6" -"checksum blake2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330" -"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" -"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -"checksum block-cipher-trait 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" -"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -"checksum bs58 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c95ee6bba9d950218b6cc910cf62bc9e0a171d0f4537e3627b0f54d08549b188" -"checksum bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b170cd256a3f9fa6b9edae3e44a7dfdfc77e8124dbc3e2612d75f9c3e2396dae" -"checksum bstr 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3ede750122d9d1f87919570cb2cccee38c84fbc8c5599b25c289af40625b7030" -"checksum bumpalo 3.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb8038c1ddc0a5f73787b130f4cc75151e96ed33e417fde765eb5a81e3532f4" -"checksum byte-slice-cast 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" -"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" -"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" -"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" -"checksum c_linked_list 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4964518bd3b4a8190e832886cdc0da9794f12e8e6c1613a9e90ff331c4c8724b" -"checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" -"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" -"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" -"checksum clear_on_drop 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "97276801e127ffb46b66ce23f35cc96bd454fa311294bced4bbace7baa8b1d17" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8815e2ab78f3a59928fc32e141fbeece88320a240e43f47b2fd64ea3a88a5b3d" -"checksum console_error_panic_hook 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211" -"checksum const-random 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7b641a8c9867e341f3295564203b1c250eb8ce6cb6126e007941f78c4d2ed7fe" -"checksum const-random-macro 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c750ec12b83377637110d5a57f5ae08e895b06c4b16e2bdbf1a94ef717428c59" -"checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" -"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" -"checksum cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c" -"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" -"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" -"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" -"checksum criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "938703e165481c8d612ea3479ac8342e5615185db37765162e762ec3523e2fc6" -"checksum criterion-plot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eccdc6ce8bbe352ca89025bee672aa6d24f4eb8c53e3a8b5d1bc58011da072a2" -"checksum crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be" -"checksum crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e" -"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c" -"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" -"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" -"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" -"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" -"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" -"checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" -"checksum crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -"checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" -"checksum csv 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "11f8cbd084b9a431d52dfac0b8428a26b68f1061138a7bea18aa56b9cdf55266" -"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" -"checksum ctr 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "022cd691704491df67d25d006fe8eca083098253c4d43516c2206479c58c6736" -"checksum ctrlc 3.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7dfd2d8b4c82121dfdff120f818e09fc4380b0b7e17a742081a89b94853e87f" -"checksum cuckoofilter 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd43f7cfaffe0a386636a10baea2ee05cc50df3b77bea4a456c9572a939bf1f" -"checksum curve25519-dalek 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8b7dcd30ba50cdf88b55b033456138b7c0ac4afdc436d82e1b79f370f24cc66d" -"checksum curve25519-dalek 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "26778518a7f6cffa1d25a44b602b62b979bd88adb9e99ffec546998cf3404839" -"checksum data-encoding 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4f47ca1860a761136924ddd2422ba77b2ea54fe8cc75b9040804a0d9d32ad97" -"checksum db-key 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b72465f46d518f6015d9cf07f7f3013a95dd6b9c2747c3d65ae0cce43929d14f" -"checksum derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "942ca430eef7a3806595a6737bc388bf51adb888d3fc0dd1b50f1c170167ee3a" -"checksum derive_more 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a141330240c921ec6d074a3e188a7c7ef95668bb95e7d44fa0e5778ec2a7afe" -"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" -"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" -"checksum dns-parser 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d33be9473d06f75f58220f71f7a9317aca647dc061dbd3c361b0bef505fbea" -"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" -"checksum ed25519-dalek 1.0.0-pre.3 (registry+https://github.com/rust-lang/crates.io-index)" = "978710b352437433c97b2bff193f2fb1dfd58a093f863dd95e225a19baa599a2" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" -"checksum encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28" -"checksum enr 0.1.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" -"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -"checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" -"checksum ethabi 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebdeeea85a6d217b9fcc862906d7e283c047e04114165c433756baf5dce00a6c" -"checksum ethabi 9.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "965126c64662832991f5a748893577630b558e47fa94e7f35aefcd20d737cef7" -"checksum ethbloom 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3932e82d64d347a045208924002930dc105a138995ccdc1479d0f05f0359f17c" -"checksum ethbloom 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "32cfe1c169414b709cf28aa30c74060bdb830a03a8ba473314d079ac79d80a5f" -"checksum ethereum-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "62d1bc682337e2c5ec98930853674dd2b4bd5d0d246933a9e98e5280f7c76c5f" -"checksum ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba744248e3553a393143d5ebb68939fc3a4ec0c22a269682535f5ffe7fed728c" -"checksum exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8013f441e38e31c670e7f34ec8f1d5d3a2bd9d303c1ff83976ca886005e8f48" -"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" -"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" -"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" -"checksum fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d1a683d1234507e4f3bf2736eeddf0de1dc65996dc0164d57eba0a74bcf29489" -"checksum fixed-hash 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3367952ceb191f4ab95dd5685dc163ac539e36202f9fcfd0cb22f9f9c542fefc" -"checksum flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd6d6f4752952feb71363cffc9ebac9411b75b87c6ab6058c40c8900cf43c0f" -"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" -"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" -"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abddb55a898d32925f3148bd281174a68eeb68bbfd9a5938a57b18f506ee4ef7" -"checksum get_if_addrs-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0d04f9fb746cf36b191c00f3ede8bde9c8e64f9f4b05ae2694a9ccf5e3f5ab48" -"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" -"checksum hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353" -"checksum hashbrown 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead" -"checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461" -"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" -"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" -"checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e" -"checksum hkdf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fa08a006102488bd9cd5b8013aabe84955cf5ae22e304c2caf655b633aefae3" -"checksum hmac 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" -"checksum hmac-drbg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c6e570451493f10f6581b48cdd530413b63ea9e780f544bfd3bdcaa0d89d1a7b" -"checksum http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" -"checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" -"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" -"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -"checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" -"checksum hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)" = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" -"checksum hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" -"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" -"checksum impl-codec 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2050d823639fbeae26b2b5ba09aca8907793117324858070ade0673c49f793b" -"checksum impl-codec 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1be51a921b067b0eaca2fad532d9400041561aa922221cc65f95a85641c6bf53" -"checksum impl-rlp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f7a72f11830b52333f36e3b09a288333888bf54380fd0ac0790a3c31ab0f3c5" -"checksum impl-serde 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "58e3cae7e99c7ff5a995da2cf78dd0a5383740eda71d98cf7b1910c301ac69b8" -"checksum impl-serde 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bbe9ea9b182f0fb1cabbd61f4ff9b7b7b9197955e95a7e4c27de5055eb29ff8" -"checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2" -"checksum integer-sqrt 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ea155abb3ba6f382a75f1418988c05fe82959ed9ce727de427f9cfd425b0c903" -"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -"checksum ipnet 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f4b06b21db0228860c8dfd17d2106c49c7c6bd07477a4036985347d84def04" -"checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" -"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" -"checksum js-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "7889c7c36282151f6bf465be4700359318aef36baa951462382eae49e9577cf9" -"checksum jsonrpc-core 11.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97b83fdc5e0218128d0d270f2f2e7a5ea716f3240c8518a58bc89e6716ba8581" -"checksum keccak 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" -"checksum leveldb 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8438a36a31c982ac399c4477d7e3c62cc7a6bf91bb6f42837b7e1033359fcbad" -"checksum leveldb-sys 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71f46429bb70612c3e939aaeed27ffd31a24a773d21728a1a426e4089d6778d2" -"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" -"checksum libflate 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "d9135df43b1f5d0e333385cb6e7897ecd1a43d7d11b91ac003f4d2c2d2401fdd" -"checksum libp2p 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-core 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-core-derive 0.13.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-deflate 0.5.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-discv5 0.1.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-dns 0.13.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-floodsub 0.13.1 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-gossipsub 0.1.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-identify 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-kad 0.13.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-mdns 0.13.1 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-mplex 0.13.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-noise 0.11.1 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-ping 0.13.1 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-plaintext 0.13.1 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-secio 0.13.1 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-swarm 0.3.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-tcp 0.13.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-uds 0.13.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-wasm-ext 0.6.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-websocket 0.13.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libp2p-yamux 0.13.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum libsecp256k1 0.3.1 (git+https://github.com/SigP/libsecp256k1?branch=ecdh_generalise)" = "" -"checksum libsecp256k1 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "df6edf84fd62aad1c93932b39324eaeda3912c1d26bc18dfaee6293848e49a50" -"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" -"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" -"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" -"checksum lock_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed946d4529956a20f2d63ebe1b69996d5a2137c91913fe3ebbeff957f5bca7ff" -"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" -"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum lru 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "5d8f669d42c72d18514dfca8115689c5f6370a17d980cb5bd777a67f404594c8" -"checksum lru 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0609345ddee5badacf857d4f547e0e5a2e987db77085c24cd887f73573a04237" -"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" -"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" -"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" -"checksum milagro_bls 1.0.0 (git+https://github.com/sigp/milagro_bls?branch=eth2.0-v0.10)" = "" -"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" -"checksum mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" -"checksum mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a0ed03949aef72dbdf3116a383d7b38b4768e6f960528cd6a6044aa9ed68599" -"checksum miniz_oxide 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6f3f74f726ae935c3f514300cc6773a0c9492abc5e972d42ba0c0ebb88757625" -"checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" -"checksum mio-extras 2.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" -"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum multistream-select 0.6.1 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e" -"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" -"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" -"checksum nohash-hasher 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4e657a6ec97f9a3ba46f6f7034ea6db9fcd5b71d25ef1074b7bc03da49be0e8e" -"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" -"checksum num-bigint 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f115de20ad793e857f76da2563ff4a09fbcfd6fe93cca0c5d996ab5f3ee38d" -"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" -"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" -"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" -"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" -"checksum openssl 0.10.26 (registry+https://github.com/rust-lang/crates.io-index)" = "3a3cc5799d98e1088141b8e01ff760112bbd9f19d850c124500566ca6901a585" -"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -"checksum openssl-sys 0.9.53 (registry+https://github.com/rust-lang/crates.io-index)" = "465d16ae7fc0e313318f7de5cecf57b2fbe7511fd213978b457e1c96ff46736f" -"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" -"checksum parity-codec 3.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2b9df1283109f542d8852cd6b30e9341acc2137481eb6157d2e62af68b0afec9" -"checksum parity-multiaddr 0.6.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum parity-multihash 0.2.0 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum parity-scale-codec 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f747c06d9f3b2ad387ac881b9667298c81b1243aa9833f086e05996937c35507" -"checksum parity-send-wrapper 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aa9777aa91b8ad9dd5aaa04a9b6bcb02c7f1deb952fca5a66034d5e63afc5c6f" -"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" -"checksum parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7767817701cce701d5585b9c4db3cdd02086398322c1d7e8bf5094a96a2ce7" -"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" -"checksum parking_lot_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb88cb1cb3790baa6776844f968fea3be44956cf184fa1be5a03341f5491278c" -"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" -"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" -"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" -"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum primitive-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2288eb2a39386c4bc817974cc413afe173010dc80e470fcb1e9a35580869f024" -"checksum primitive-types 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4336f4f5d5524fa60bcbd6fe626f9223d8142a50e7053e979acdf0da41ab975" -"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc" -"checksum prometheus 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5567486d5778e2c6455b1b90ff1c558f29e751fc018130fa182e15828e728af1" -"checksum protobuf 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40361836defdd5871ff7e84096c6f6444af7fc157f8ef1789f54f147687caa20" -"checksum publicsuffix 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" -"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -"checksum quickcheck 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a44883e74aa97ad63db83c4bf8ca490f02b2fc02f92575e720c8551e843c945f" -"checksum quickcheck_macros 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7dfc1c4a1e048f5cc7d36a4c4118dfcf31d217c79f4b9a61bad65d68185752c" -"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_os 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a788ae3edb696cfcba1c19bfd388cc4b8c21f8a408432b199c072825084da58a" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" -"checksum rand_xoshiro 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e18c91676f670f6f0312764c759405f13afb98d5d73819840cf72a518487bff" -"checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098" -"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d" -"checksum regex 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87" -"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" -"checksum regex-syntax 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90" -"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "f88643aea3c1343c804950d7bf983bd2067f5ab59db6d613a08e05572f2714ab" -"checksum ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6747f8da1f2b1fabbee1aaa4eb8a11abf9adef0bf58a41cee45db5d59cecdfac" -"checksum rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" -"checksum rlp 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3a44d5ae8afcb238af8b75640907edc6c931efcfab2c854e81ed35fa080f84cd" -"checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" -"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" -"checksum rustc-hex 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustls 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b25a18b1bf7387f0145e7f8324e700805aade3842dd3db2e74e4cdeb4677c09e" -"checksum rw-stream-sink 0.1.2 (git+https://github.com/SigP/rust-libp2p/?rev=49c95c4c4242f1c9f08558a3daac5e9ecac290d5)" = "" -"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" -"checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" -"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -"checksum schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "87f550b06b6cba9c8b8be3ee73f391990116bf527450d2556e9b9ce263b9a021" -"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" -"checksum scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" -"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum sct 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c" -"checksum security-framework 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8ef2429d7cefe5fd28bd1d2ed41c944547d4ff84776f5935b456da44593a16df" -"checksum security-framework-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e31493fc37615debb8c5090a7aeb4a9730bc61e77ab10b9af59f1a202284f895" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum send_wrapper 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0eddf2e8f50ced781f288c19f18621fa72a3779e3cb58dbf23b07469b0abeb4" -"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" -"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" -"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7" -"checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573" -"checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" -"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" -"checksum sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -"checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" -"checksum sha2 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "27044adfd2e1f077f649f59deb9490d3941d674002f7d062870a60ebe9bd47a0" -"checksum sha3 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf" -"checksum simple_logger 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "109facdf91db4b79de557313b5e031f0f8a86373e316bf01158190aa68bcc74e" -"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" -"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1cc9c640a4adbfbcc11ffb95efe5aa7af7309e002adab54b185507dbf2377b99" -"checksum slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e544d16c6b230d84c866662fe55e31aacfca6ae71e6fc49ae9a311cb379bfc2f" -"checksum slog-json 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc0d2aff1f8f325ef660d9a0eb6e6dcd20b30b3f581a5897f58bf42d061c37a" -"checksum slog-kvfilter 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ae939ed7d169eed9699f4f5cd440f046f5dc5dfc27c19e3cd311619594c175e0" -"checksum slog-scope 4.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c44c89dd8b0ae4537d1ae318353eaf7840b4869c536e31c41e963d1ea523ee6" -"checksum slog-stdlog 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f1c469573d1e3f36f9eee66cd132206caf47b50c94b1f6c6e7b4d8235e9ecf01" -"checksum slog-stdlog 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "be4d87903baf655da2d82bc3ac3f7ef43868c58bf712b3a661fda72009304c23" -"checksum slog-term 2.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "54b50e85b73c2bd42ceb97b6ded235576d405bd1e974242ccfe634fa269f6da7" -"checksum sloggers 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d41aa58f9a02e205e21117ffa08e94c37f06e1f1009be2639b621f351a75796d" -"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" -"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" -"checksum snow 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "afb767eee7d257ba202f0b9b08673bc13b22281632ef45267b19f13100accd2f" -"checksum soketto 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bceb1a3a15232d013d9a3b7cac9e5ce8e2313f348f01d4bc1097e5e53aa07095" -"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" -"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" -"checksum static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -"checksum stream-cipher 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8131256a5896cabcf5eb04f4d6dacbe1aefda854b0d9896e09cb58829ec5638c" -"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" -"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" -"checksum subtle 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c65d530b10ccaeac294f349038a597e435b18fb456aadd0840a623f83b9e941" -"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -"checksum syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8" -"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" -"checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" -"checksum target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c63f48baada5c52e65a29eef93ab4f8982681b67f9e8d29c7b05abcfec2b9ffe" -"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" -"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" -"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8a021c69bb74a44ccedb824a046447e2c84a01df9e5c20779750acb38e11b2" -"checksum tinytemplate 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "57a3c6667d3e65eb1bc3aed6fd14011c6cbc3a0665218ab7f5daf040b9ec371a" -"checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" -"checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" -"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" -"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" -"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443" -"checksum tokio-dns-unofficial 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82c65483db54eb91b4ef3a9389a3364558590faf30ce473141707c0e16fda975" -"checksum tokio-executor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ca6df436c42b0c3330a82d855d2ef017cd793090ad550a6bc2184f4b933532ab" -"checksum tokio-fs 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe6dc22b08d6993916647d108a1a7d15b9cd29c4f4496c62b92c45b5041b7af" -"checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" -"checksum tokio-io-timeout 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "135ce81f15cfd7982fac684f9057a1299eebeb79e98a8a709969b9aa51123129" -"checksum tokio-reactor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "6732fe6b53c8d11178dcb77ac6d9682af27fc6d4cb87789449152e5377377146" -"checksum tokio-rustls 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2d7cf08f990090abd6c6a73cab46fed62f85e8aef8b99e4b918a9f4a637f0676" -"checksum tokio-sync 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d06554cce1ae4a50f42fba8023918afa931413aded705b560e29600ccf7c6d76" -"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" -"checksum tokio-threadpool 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c32ffea4827978e9aa392d2f743d973c1dfa3730a2ed3f22ce1e6984da848c" -"checksum tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6131e780037787ff1b3f8aad9da83bca02438b72277850dd6ad0d455e0e20efc" -"checksum tokio-timer 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "1739638e364e558128461fc1ad84d997702c8e31c2e6b18fb99842268199e827" -"checksum tokio-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "354b8cd83825b3c20217a9dc174d6a0c67441a2fae5c41bcb1ea6679f6ae0f7c" -"checksum tokio-udp 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f02298505547f73e60f568359ef0d016d5acd6e830ab9bc7c4a5b3403440121b" -"checksum tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "65ae5d255ce739e8537221ed2942e0445f4b3b813daebac1c0050ddaaa3587f9" -"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" -"checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf" -"checksum trackable 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)" = "11475c3c53b075360eac9794965822cb053996046545f91cf61d90e00b72efa5" -"checksum trackable_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0f4062d54dd240bde289717d6b4af18048c3dd552f01a0fd93824f5fc4d2d084" -"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" -"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" -"checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b" -"checksum twofish 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d261e83e727c8e2dbb75dacac67c36e35db36a958ee504f2164fc052434e1" -"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" -"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" -"checksum uint 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2143cded94692b156c356508d92888acc824db5bffc0b4089732264c6fcf86d4" -"checksum uint 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e75a4cdd7b87b28840dba13c483b9a88ee6bbf16ba5c951ee1ecfcf723078e0d" -"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" -"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf" -"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" -"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum unsigned-varint 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f0023a96687fe169081e8adce3f65e3874426b7886e9234d490af2dc077959" -"checksum untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60369ef7a31de49bcb3f6ca728d4ba7300d9a1658f94c727d4cab8c8d9f4aece" -"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -"checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" -"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" -"checksum vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" -"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" -"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" -"checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" -"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum wasm-bindgen 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "5205e9afdf42282b192e2310a5b463a6d1c1d774e30dc3c791ac37ab42d2616c" -"checksum wasm-bindgen-backend 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "11cdb95816290b525b32587d76419facd99662a07e59d3cdb560488a819d9a45" -"checksum wasm-bindgen-futures 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "83420b37346c311b9ed822af41ec2e82839bfe99867ec6c54e2da43b7538771c" -"checksum wasm-bindgen-futures 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8bbdd49e3e28b40dec6a9ba8d17798245ce32b019513a845369c641b275135d9" -"checksum wasm-bindgen-macro 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "574094772ce6921576fb6f2e3f7497b8a76273b6db092be18fc48a082de09dc3" -"checksum wasm-bindgen-macro-support 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "e85031354f25eaebe78bb7db1c3d86140312a911a106b2e29f9cc440ce3e7668" -"checksum wasm-bindgen-shared 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "f5e7e61fc929f4c0dddb748b102ebf9f632e2b8d739f2016542b4de2965a9601" -"checksum wasm-bindgen-test 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "98fd0ec352c44d1726b6c2bec524612b1c81e34a7d858f597a6c71f8e018c82e" -"checksum wasm-bindgen-test-macro 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "97837a6e83ab24a4b3a38d44a257e13335b54f4b4548b2c9d71edd0bf570cb4f" -"checksum wasm-bindgen-webidl 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "ef012a0d93fc0432df126a8eaf547b2dce25a8ce9212e1d3cbeef5c11157975d" -"checksum wasm-timer 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aa3e01d234bb71760e685cfafa5e2c96f8ad877c161a721646356651069e26ac" -"checksum web-sys 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf97caf6aa8c2b1dac90faf0db529d9d63c93846cca4911856f78a83cebf53b" -"checksum web3 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "076f34ed252d74a8521e3b013254b1a39f94a98f23aae7cfc85cda6e7b395664" -"checksum webpki 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7e664e770ac0110e2384769bcc59ed19e329d81f555916a6e072714957b81b4" -"checksum webpki-roots 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91cd5736df7f12a964a5067a12c62fa38e1bd8080aff1f80bc29be7c80d19ab4" -"checksum websocket 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c9faed2bff8af2ea6b9f8b917d3d00b467583f6781fe3def174a9e33c879703" -"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" -"checksum ws 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a2c47b5798ccc774ffb93ff536aec7c4275d722fd9c740c83cdd1af1f2d94" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -"checksum x25519-dalek 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ee1585dc1484373cbc1cee7aafda26634665cf449436fd6e24bfd1fad230538" -"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" -"checksum yamux 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2758f29014c1cb7a6e74c1b1160ac8c8203be342d35b73462fc6a13cc6385423" -"checksum zeroize 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e68403b858b6af538b11614e62dfe9ab2facba9f13a0cafb974855cfb495ec95" -"checksum zeroize 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8" -"checksum zeroize_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3f07490820219949839d0027b965ffdd659d75be9220c00798762e36c6cd281" diff --git a/Cargo.toml b/Cargo.toml index 172fcb036..37f255026 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,12 +13,14 @@ members = [ "eth2/utils/eth2_testnet_config", "eth2/utils/logging", "eth2/utils/eth2_hashing", + "eth2/utils/hashmap_delay", "eth2/utils/lighthouse_metrics", "eth2/utils/lighthouse_bootstrap", "eth2/utils/merkle_proof", "eth2/utils/int_to_bytes", "eth2/utils/serde_hex", "eth2/utils/slot_clock", + "eth2/utils/rest_types", "eth2/utils/ssz", "eth2/utils/ssz_derive", "eth2/utils/ssz_types", @@ -28,14 +30,15 @@ members = [ "eth2/utils/tree_hash_derive", "eth2/utils/test_random_derive", "beacon_node", - "beacon_node/store", - "beacon_node/client", - "beacon_node/rest_api", - "beacon_node/network", - "beacon_node/eth2-libp2p", - "beacon_node/version", - "beacon_node/eth1", "beacon_node/beacon_chain", + "beacon_node/client", + "beacon_node/eth1", + "beacon_node/eth2-libp2p", + "beacon_node/network", + "beacon_node/rest_api", + "beacon_node/store", + "beacon_node/timer", + "beacon_node/version", "beacon_node/websocket_server", "tests/simulator", "tests/ef_tests", diff --git a/beacon_node/Cargo.toml b/beacon_node/Cargo.toml index 83d77a3c9..664f94560 100644 --- a/beacon_node/Cargo.toml +++ b/beacon_node/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "beacon_node" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner ", "Age Manning ", "Age Manning "] edition = "2018" @@ -33,10 +33,10 @@ eth2_ssz_derive = "0.1.0" state_processing = { path = "../../eth2/state_processing" } tree_hash = "0.1.0" types = { path = "../../eth2/types" } +tokio = "0.1.22" eth1 = { path = "../eth1" } websocket_server = { path = "../websocket_server" } futures = "0.1.25" -exit-future = "0.1.3" genesis = { path = "../genesis" } integer-sqrt = "0.1" rand = "0.7.2" diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 1109dd2ab..d36a08fae 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -1,5 +1,8 @@ -use crate::checkpoint::CheckPoint; -use crate::errors::{BeaconChainError as Error, BlockProductionError}; +use crate::block_verification::{ + check_block_relevancy, get_block_root, signature_verify_chain_segment, BlockError, + FullyVerifiedBlock, GossipVerifiedBlock, IntoFullyVerifiedBlock, +}; +use crate::errors::{AttestationDropReason, BeaconChainError as Error, BlockProductionError}; use crate::eth1_chain::{Eth1Chain, Eth1ChainBackend}; use crate::events::{EventHandler, EventKind}; use crate::fork_choice::{Error as ForkChoiceError, ForkChoice}; @@ -7,32 +10,29 @@ use crate::head_tracker::HeadTracker; use crate::metrics; use crate::persisted_beacon_chain::PersistedBeaconChain; use crate::shuffling_cache::ShufflingCache; +use crate::snapshot_cache::SnapshotCache; use crate::timeout_rw_lock::TimeoutRwLock; use crate::validator_pubkey_cache::ValidatorPubkeyCache; +use crate::BeaconSnapshot; use operation_pool::{OperationPool, PersistedOperationPool}; -use slog::{debug, error, info, trace, warn, Logger}; +use slog::{crit, debug, error, info, trace, warn, Logger}; use slot_clock::SlotClock; -use ssz::Encode; use state_processing::per_block_processing::errors::{ AttestationValidationError, AttesterSlashingValidationError, ExitValidationError, ProposerSlashingValidationError, }; use state_processing::{ common::get_indexed_attestation, per_block_processing, per_slot_processing, - signature_sets::indexed_attestation_signature_set_from_pubkeys, BlockProcessingError, - BlockSignatureStrategy, + signature_sets::indexed_attestation_signature_set_from_pubkeys, BlockSignatureStrategy, }; use std::borrow::Cow; use std::cmp::Ordering; -use std::fs; -use std::io::prelude::*; use std::sync::Arc; use std::time::{Duration, Instant}; use store::iter::{ BlockRootsIterator, ReverseBlockRootIterator, ReverseStateRootIterator, StateRootsIterator, }; -use store::{Error as DBError, Migrate, StateBatch, Store}; -use tree_hash::TreeHash; +use store::{Error as DBError, Migrate, Store}; use types::*; // Text included in blocks. @@ -41,63 +41,26 @@ use types::*; // |-------must be this long------| pub const GRAFFITI: &str = "sigp/lighthouse-0.1.1-prerelease"; -/// If true, everytime a block is processed the pre-state, post-state and block are written to SSZ -/// files in the temp directory. -/// -/// Only useful for testing. -const WRITE_BLOCK_PROCESSING_SSZ: bool = cfg!(feature = "write_ssz_files"); - -/// Maximum block slot number. Block with slots bigger than this constant will NOT be processed. -const MAXIMUM_BLOCK_SLOT_NUMBER: u64 = 4_294_967_296; // 2^32 - /// The time-out before failure during an operation to take a read/write RwLock on the canonical /// head. const HEAD_LOCK_TIMEOUT: Duration = Duration::from_secs(1); +/// The time-out before failure during an operation to take a read/write RwLock on the block +/// processing cache. +pub const BLOCK_PROCESSING_CACHE_LOCK_TIMEOUT: Duration = Duration::from_secs(1); /// The time-out before failure during an operation to take a read/write RwLock on the /// attestation cache. const ATTESTATION_CACHE_LOCK_TIMEOUT: Duration = Duration::from_secs(1); /// The time-out before failure during an operation to take a read/write RwLock on the /// validator pubkey cache. -const VALIDATOR_PUBKEY_CACHE_LOCK_TIMEOUT: Duration = Duration::from_secs(1); +pub const VALIDATOR_PUBKEY_CACHE_LOCK_TIMEOUT: Duration = Duration::from_secs(1); pub const BEACON_CHAIN_DB_KEY: [u8; 32] = [0; 32]; pub const OP_POOL_DB_KEY: [u8; 32] = [0; 32]; pub const ETH1_CACHE_DB_KEY: [u8; 32] = [0; 32]; pub const FORK_CHOICE_DB_KEY: [u8; 32] = [0; 32]; -#[derive(Debug, PartialEq)] -pub enum BlockProcessingOutcome { - /// Block was valid and imported into the block graph. - Processed { block_root: Hash256 }, - /// The parent block was unknown. - ParentUnknown { - parent: Hash256, - reference_location: &'static str, - }, - /// The block slot is greater than the present slot. - FutureSlot { - present_slot: Slot, - block_slot: Slot, - }, - /// The block state_root does not match the generated state. - StateRootMismatch { block: Hash256, local: Hash256 }, - /// The block was a genesis block, these blocks cannot be re-imported. - GenesisBlock, - /// The slot is finalized, no need to import. - WouldRevertFinalizedSlot { - block_slot: Slot, - finalized_slot: Slot, - }, - /// Block is already known, no need to re-import. - BlockIsAlreadyKnown, - /// The block slot exceeds the MAXIMUM_BLOCK_SLOT_NUMBER. - BlockSlotLimitReached, - /// The block could not be applied to the state, it is invalid. - PerBlockProcessingError(BlockProcessingError), -} - #[derive(Debug, PartialEq)] pub enum AttestationProcessingOutcome { Processed, @@ -146,6 +109,7 @@ pub enum StateSkipConfig { WithoutStateRoots, } +#[derive(Debug, PartialEq)] pub struct HeadInfo { pub slot: Slot, pub block_root: Hash256, @@ -180,7 +144,7 @@ pub struct BeaconChain { /// Provides information from the Ethereum 1 (PoW) chain. pub eth1_chain: Option>, /// Stores a "snapshot" of the chain at the time the head-of-the-chain block was received. - pub(crate) canonical_head: TimeoutRwLock>, + pub(crate) canonical_head: TimeoutRwLock>, /// The root of the genesis block. pub genesis_block_root: Hash256, /// A state-machine that is updated with information from the network and chooses a canonical @@ -190,6 +154,8 @@ pub struct BeaconChain { pub event_handler: T::EventHandler, /// Used to track the heads of the beacon chain. pub(crate) head_tracker: HeadTracker, + /// A cache dedicated to block processing. + pub(crate) snapshot_cache: TimeoutRwLock>, /// Caches the shuffling for a given epoch and state root. pub(crate) shuffling_cache: TimeoutRwLock, /// Caches a map of `validator_index -> validator_pubkey`. @@ -442,34 +408,13 @@ impl BeaconChain { Ok(self.store.get_state(state_root, slot)?) } - /// Returns the state at the given root, if any. - /// - /// The return state does not contain any caches other than the committee caches. This method - /// is much faster than `Self::get_state` because it does not clone the tree hash cache - /// when the state is found in the cache. - /// - /// ## Errors - /// - /// May return a database error. - pub fn get_state_caching_only_with_committee_caches( - &self, - state_root: &Hash256, - slot: Option, - ) -> Result>, Error> { - Ok(self.store.get_state_with( - state_root, - slot, - types::beacon_state::CloneConfig::committee_caches_only(), - )?) - } - /// Returns a `Checkpoint` representing the head block and state. Contains the "best block"; /// the head of the canonical `BeaconChain`. /// /// 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) -> Result, Error> { + pub fn head(&self) -> Result, Error> { self.canonical_head .try_read_for(HEAD_LOCK_TIMEOUT) .ok_or_else(|| Error::CanonicalHeadLockTimeout) @@ -605,14 +550,44 @@ impl BeaconChain { /// Returns the validator index (if any) for the given public key. /// - /// Information is retrieved from the present `beacon_state.validators`. + /// ## Notes + /// + /// This query uses the `validator_pubkey_cache` which contains _all_ validators ever seen, + /// even if those validators aren't included in the head state. It is important to remember + /// that just because a validator exists here, it doesn't necessarily exist in all + /// `BeaconStates`. + /// + /// ## Errors + /// + /// May return an error if acquiring a read-lock on the `validator_pubkey_cache` times out. pub fn validator_index(&self, pubkey: &PublicKeyBytes) -> Result, Error> { - for (i, validator) in self.head()?.beacon_state.validators.iter().enumerate() { - if validator.pubkey == *pubkey { - return Ok(Some(i)); - } - } - Ok(None) + let pubkey_cache = self + .validator_pubkey_cache + .try_read_for(VALIDATOR_PUBKEY_CACHE_LOCK_TIMEOUT) + .ok_or_else(|| Error::ValidatorPubkeyCacheLockTimeout)?; + + Ok(pubkey_cache.get_index(pubkey)) + } + + /// Returns the validator pubkey (if any) for the given validator index. + /// + /// ## Notes + /// + /// This query uses the `validator_pubkey_cache` which contains _all_ validators ever seen, + /// even if those validators aren't included in the head state. It is important to remember + /// that just because a validator exists here, it doesn't necessarily exist in all + /// `BeaconStates`. + /// + /// ## Errors + /// + /// May return an error if acquiring a read-lock on the `validator_pubkey_cache` times out. + pub fn validator_pubkey(&self, validator_index: usize) -> Result, Error> { + let pubkey_cache = self + .validator_pubkey_cache + .try_read_for(VALIDATOR_PUBKEY_CACHE_LOCK_TIMEOUT) + .ok_or_else(|| Error::ValidatorPubkeyCacheLockTimeout)?; + + Ok(pubkey_cache.get(validator_index).cloned()) } /// Returns the block canonical root of the current canonical chain at a given slot. @@ -656,7 +631,72 @@ impl BeaconChain { .map_err(Into::into) } - /// Produce an `Attestation` that is valid for the given `slot` and `index`. + /// Returns the attestation slot and committee index for a given validator index. + /// + /// Information is read from the current state, so only information from the present and prior + /// epoch is available. + pub fn validator_attestation_slot_and_index( + &self, + validator_index: usize, + epoch: Epoch, + ) -> Result, Error> { + let as_epoch = |slot: Slot| slot.epoch(T::EthSpec::slots_per_epoch()); + let head_state = &self.head()?.beacon_state; + + let mut state = if epoch == as_epoch(head_state.slot) { + self.head()?.beacon_state + } else { + // The block proposer shuffling is not affected by the state roots, so we don't need to + // calculate them. + self.state_at_slot( + epoch.start_slot(T::EthSpec::slots_per_epoch()), + StateSkipConfig::WithoutStateRoots, + )? + }; + + state.build_committee_cache(RelativeEpoch::Current, &self.spec)?; + + if as_epoch(state.slot) != epoch { + return Err(Error::InvariantViolated(format!( + "Epochs in consistent in attestation duties lookup: state: {}, requested: {}", + as_epoch(state.slot), + epoch + ))); + } + + if let Some(attestation_duty) = + state.get_attestation_duties(validator_index, RelativeEpoch::Current)? + { + Ok(Some((attestation_duty.slot, attestation_duty.index))) + } else { + Ok(None) + } + } + + /// Produce an aggregate attestation that has been collected for this slot and committee. + // TODO: Check and optimize + pub fn return_aggregate_attestation( + &self, + slot: Slot, + index: CommitteeIndex, + ) -> Result, Error> { + let epoch = |slot: Slot| slot.epoch(T::EthSpec::slots_per_epoch()); + let head_state = &self.head()?.beacon_state; + + let state = if epoch(slot) == epoch(head_state.slot) { + self.head()?.beacon_state + } else { + // The block proposer shuffling is not affected by the state roots, so we don't need to + // calculate them. + self.state_at_slot(slot, StateSkipConfig::WithoutStateRoots)? + }; + + self.op_pool + .get_raw_aggregated_attestations(&slot, &index, &state, &self.spec) + .map_err(Error::from) + } + + /// Produce a raw unsigned `Attestation` that is valid for the given `slot` and `index`. /// /// Always attests to the canonical chain. pub fn produce_attestation( @@ -699,7 +739,7 @@ impl BeaconChain { drop(head); let mut state = self - .get_state_caching_only_with_committee_caches(&state_root, Some(slot))? + .get_state(&state_root, Some(slot))? .ok_or_else(|| Error::MissingBeaconState(state_root))?; state.build_committee_cache(RelativeEpoch::Current, &self.spec)?; @@ -772,14 +812,21 @@ impl BeaconChain { /// /// - Whilst the `attestation` is added to fork choice, the head is not updated. That must be /// done separately. + /// + /// The `store_raw` parameter determines if this attestation is to be stored in the operation + /// pool. `None` indicates the attestation is not stored in the operation pool (we don't have a + /// validator required to aggregate these attestations). `Some(true)` indicates we are storing a + /// raw un-aggregated attestation from a subnet into the `op_pool` which is short-lived and `Some(false)` + /// indicates that we are storing an aggregate attestation in the `op_pool`. pub fn process_attestation( &self, attestation: Attestation, + store_raw: Option, ) -> Result { metrics::inc_counter(&metrics::ATTESTATION_PROCESSING_REQUESTS); let timer = metrics::start_timer(&metrics::ATTESTATION_PROCESSING_TIMES); - let outcome = self.process_attestation_internal(attestation.clone()); + let outcome = self.process_attestation_internal(attestation.clone(), store_raw); match &outcome { Ok(outcome) => match outcome { @@ -833,6 +880,7 @@ impl BeaconChain { pub fn process_attestation_internal( &self, attestation: Attestation, + store_raw: Option, ) -> Result { let initial_validation_timer = metrics::start_timer(&metrics::ATTESTATION_PROCESSING_INITIAL_VALIDATION_TIMES); @@ -963,10 +1011,7 @@ impl BeaconChain { metrics::start_timer(&metrics::ATTESTATION_PROCESSING_STATE_READ_TIMES); let mut state = self - .get_state_caching_only_with_committee_caches( - &target_block_state_root, - Some(target_block_slot), - )? + .get_state(&target_block_state_root, Some(target_block_slot))? .ok_or_else(|| Error::MissingBeaconState(target_block_state_root))?; metrics::stop_timer(state_read_timer); @@ -1021,16 +1066,6 @@ impl BeaconChain { .try_read_for(VALIDATOR_PUBKEY_CACHE_LOCK_TIMEOUT) .ok_or_else(|| Error::ValidatorPubkeyCacheLockTimeout)?; - let pubkeys = indexed_attestation - .attesting_indices - .iter() - .map(|i| { - pubkey_cache - .get(*i as usize) - .ok_or_else(|| Error::ValidatorPubkeyCacheIncomplete(*i as usize)) - }) - .collect::, Error>>()?; - let fork = self .canonical_head .try_read_for(HEAD_LOCK_TIMEOUT) @@ -1038,7 +1073,11 @@ impl BeaconChain { .map(|head| head.beacon_state.fork.clone())?; let signature_set = indexed_attestation_signature_set_from_pubkeys( - pubkeys, + |validator_index| { + pubkey_cache + .get(validator_index) + .map(|pk| Cow::Borrowed(pk.as_point())) + }, &attestation.signature, &indexed_attestation, &fork, @@ -1055,6 +1094,8 @@ impl BeaconChain { metrics::stop_timer(signature_verification_timer); + drop(pubkey_cache); + if signature_is_valid { // Provide the attestation to fork choice, updating the validator latest messages but // _without_ finding and updating the head. @@ -1072,11 +1113,30 @@ impl BeaconChain { } // Provide the valid attestation to op pool, which may choose to retain the - // attestation for inclusion in a future block. + // attestation for inclusion in a future block. If we receive an attestation from a + // subnet without a validator responsible for aggregating it, we don't store it in the + // op pool. if self.eth1_chain.is_some() { - self.op_pool - .insert_attestation(attestation, &fork, &self.spec)?; - }; + if let Some(is_raw) = store_raw { + if is_raw { + // This is a raw un-aggregated attestation received from a subnet with a + // connected validator required to aggregate and publish these attestations + self.op_pool + .insert_raw_attestation(attestation, &fork, &self.spec)?; + } else { + // This an aggregate attestation received from the aggregate attestation + // channel + self.op_pool.insert_aggregate_attestation( + attestation, + &fork, + &self.spec, + )?; + } + } + } + + // Update the metrics. + metrics::inc_counter(&metrics::ATTESTATION_PROCESSING_SUCCESSES); Ok(AttestationProcessingOutcome::Processed) } else { @@ -1084,6 +1144,90 @@ impl BeaconChain { } } + /// Check that the `aggregator_index` in an aggregate attestation is as it should be. + // TODO: Check for optimisation/relevance + fn check_attestation_aggregator( + &self, + signed_aggregate_and_proof: &SignedAggregateAndProof, + indexed_attestation: &IndexedAttestation, + state: &BeaconState, + ) -> Result<(), AttestationDropReason> { + let aggregate_and_proof = &signed_aggregate_and_proof.message; + let attestation = &aggregate_and_proof.aggregate; + + // Check that aggregator index is part of the committee attesting (quick). + if !indexed_attestation + .attesting_indices + .contains(&aggregate_and_proof.aggregator_index) + { + return Err(AttestationDropReason::AggregatorNotInAttestingIndices); + } + // Check that the aggregator is allowed to be aggregating (medium, one hash). + else if !state + .is_aggregator( + attestation.data.slot, + attestation.data.index, + &aggregate_and_proof.selection_proof, + &self.spec, + ) + .unwrap_or(false) + { + return Err(AttestationDropReason::AggregatorNotSelected); + } + // Check that the signature is valid and the aggregator's selection proof is valid (slow-ish). Two sig verifications + if let Ok(Some(pubkey)) = + self.validator_pubkey(aggregate_and_proof.aggregator_index as usize) + { + if !signed_aggregate_and_proof.is_valid(&pubkey, &state.fork) { + Err(AttestationDropReason::AggregatorSignatureInvalid) + } else { + Ok(()) + } + } else { + Err(AttestationDropReason::AggregatorNotInAttestingIndices) + } + } + + /// Check that an attestation's slot doesn't make it ineligible for gossip. + fn check_attestation_slot_for_gossip( + &self, + attestation: &Attestation, + ) -> Result<(), AttestationDropReason> { + // `now_low_slot` is the slot of the current time minus MAXIMUM_GOSSIP_CLOCK_DISPARITY + // `now_high_slot` is the slot of the current time plus MAXIMUM_GOSSIP_CLOCK_DISPARITY + let (now_low_slot, now_high_slot) = self + .slot_clock + .now_duration() + .and_then(|now| { + let maximum_clock_disparity = + Duration::from_millis(self.spec.maximum_gossip_clock_disparity_millis); + let now_low_duration = now.checked_sub(maximum_clock_disparity)?; + let now_high_duration = now.checked_add(maximum_clock_disparity)?; + Some(( + self.slot_clock.slot_of(now_low_duration)?, + self.slot_clock.slot_of(now_high_duration)?, + )) + }) + .ok_or_else(|| AttestationDropReason::SlotClockError)?; + + let min_slot = attestation.data.slot; + let max_slot = min_slot + self.spec.attestation_propagation_slot_range; + + if now_high_slot < min_slot { + Err(AttestationDropReason::TooNew { + attestation_slot: min_slot, + now: now_high_slot, + }) + } else if now_low_slot > max_slot { + Err(AttestationDropReason::TooOld { + attestation_slot: min_slot, + now: now_low_slot, + }) + } else { + Ok(()) + } + } + /// Accept some exit and queue it for inclusion in an appropriate block. pub fn process_voluntary_exit( &self, @@ -1161,238 +1305,229 @@ impl BeaconChain { } } - /// Accept some block and attempt to add it to block DAG. + /// Attempt to verify and import a chain of blocks to `self`. /// - /// Will accept blocks from prior slots, however it will reject any block from a future slot. - pub fn process_block( + /// The provided blocks _must_ each reference the previous block via `block.parent_root` (i.e., + /// be a chain). An error will be returned if this is not the case. + /// + /// This operation is not atomic; if one of the blocks in the chain is invalid then some prior + /// blocks might be imported. + /// + /// This method is generally much more efficient than importing each block using + /// `Self::process_block`. + pub fn process_chain_segment( + &self, + chain_segment: Vec>, + ) -> Result, BlockError> { + let mut filtered_chain_segment = Vec::with_capacity(chain_segment.len()); + + // Produce a list of the parent root and slot of the child of each block. + // + // E.g., `children[0] == (chain_segment[1].parent_root(), chain_segment[1].slot())` + let children = chain_segment + .iter() + .skip(1) + .map(|block| (block.parent_root(), block.slot())) + .collect::>(); + + for (i, block) in chain_segment.into_iter().enumerate() { + let block_root = get_block_root(&block); + + if let Some((child_parent_root, child_slot)) = children.get(i) { + // If this block has a child in this chain segment, ensure that its parent root matches + // the root of this block. + // + // Without this check it would be possible to have a block verified using the + // incorrect shuffling. That would be bad, mmkay. + if block_root != *child_parent_root { + return Err(BlockError::NonLinearParentRoots); + } + + // Ensure that the slots are strictly increasing throughout the chain segement. + if *child_slot <= block.slot() { + return Err(BlockError::NonLinearSlots); + } + } + + match check_block_relevancy(&block, Some(block_root), self) { + // If the block is relevant, add it to the filtered chain segment. + Ok(_) => filtered_chain_segment.push((block_root, block)), + // If the block is already known, simply ignore this block. + Err(BlockError::BlockIsAlreadyKnown) => continue, + // If the block is the genesis block, simply ignore this block. + Err(BlockError::GenesisBlock) => continue, + // If there was an error whilst determining if the block was invalid, return that + // error. + Err(BlockError::BeaconChainError(e)) => { + return Err(BlockError::BeaconChainError(e)) + } + // If the block was decided to be irrelevant for any other reason, don't include + // this block or any of it's children in the filtered chain segment. + _ => break, + } + } + + let mut roots = Vec::with_capacity(filtered_chain_segment.len()); + + while !filtered_chain_segment.is_empty() { + // Determine the epoch of the first block in the remaining segment. + let start_epoch = filtered_chain_segment + .first() + .map(|(_root, block)| block) + .expect("chain_segment cannot be empty") + .slot() + .epoch(T::EthSpec::slots_per_epoch()); + + // The `last_index` indicates the position of the last block that is in the current + // epoch of `start_epoch`. + let last_index = filtered_chain_segment + .iter() + .position(|(_root, block)| { + block.slot().epoch(T::EthSpec::slots_per_epoch()) > start_epoch + }) + .unwrap_or_else(|| filtered_chain_segment.len()); + + // Split off the first section blocks that are all either within the current epoch of + // the first block. These blocks can all be signature-verified with the same + // `BeaconState`. + let mut blocks = filtered_chain_segment.split_off(last_index); + std::mem::swap(&mut blocks, &mut filtered_chain_segment); + + // Verify the signature of the blocks, returning early if the signature is invalid. + let signature_verified_blocks = signature_verify_chain_segment(blocks, self)?; + + // Import the blocks into the chain. + for signature_verified_block in signature_verified_blocks { + roots.push(self.process_block(signature_verified_block)?); + } + } + + Ok(roots) + } + + /// Returns `Ok(GossipVerifiedBlock)` if the supplied `block` should be forwarded onto the + /// gossip network. The block is not imported into the chain, it is just partially verified. + /// + /// The returned `GossipVerifiedBlock` should be provided to `Self::process_block` immediately + /// after it is returned, unless some other circumstance decides it should not be imported at + /// all. + /// + /// ## Errors + /// + /// Returns an `Err` if the given block was invalid, or an error was encountered during + pub fn verify_block_for_gossip( &self, block: SignedBeaconBlock, - ) -> Result { - let outcome = self.process_block_internal(block.clone()); + ) -> Result, BlockError> { + GossipVerifiedBlock::new(block, self) + } - match &outcome { - Ok(outcome) => match outcome { - BlockProcessingOutcome::Processed { block_root } => { - trace!( - self.log, - "Beacon block imported"; - "block_root" => format!("{:?}", block_root), - "block_slot" => format!("{:?}", block.slot().as_u64()), - ); - let _ = self.event_handler.register(EventKind::BeaconBlockImported { - block_root: *block_root, - block: Box::new(block), - }); - } - other => { - trace!( - self.log, - "Beacon block rejected"; - "reason" => format!("{:?}", other), - ); - let _ = self.event_handler.register(EventKind::BeaconBlockRejected { - reason: format!("Invalid block: {:?}", other), - block: Box::new(block), - }); - } - }, - Err(e) => { - error!( + /// Returns `Ok(block_root)` if the given `unverified_block` was successfully verified and + /// imported into the chain. + /// + /// Items that implement `IntoFullyVerifiedBlock` include: + /// + /// - `SignedBeaconBlock` + /// - `GossipVerifiedBlock` + /// + /// ## Errors + /// + /// Returns an `Err` if the given block was invalid, or an error was encountered during + /// verification. + pub fn process_block>( + &self, + unverified_block: B, + ) -> Result { + // Start the Prometheus timer. + let full_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_TIMES); + + // Increment the Prometheus counter for block processing requests. + metrics::inc_counter(&metrics::BLOCK_PROCESSING_REQUESTS); + + // Clone the block so we can provide it to the event handler. + let block = unverified_block.block().clone(); + + // A small closure to group the verification and import errors. + let import_block = |unverified_block: B| -> Result { + let fully_verified = unverified_block.into_fully_verified_block(self)?; + self.import_block(fully_verified) + }; + + // Verify and import the block. + let result = match import_block(unverified_block) { + // The block was successfully verified and imported. Yay. + Ok(block_root) => { + trace!( + self.log, + "Beacon block imported"; + "block_root" => format!("{:?}", block_root), + "block_slot" => format!("{:?}", block.slot().as_u64()), + ); + + // Increment the Prometheus counter for block processing successes. + metrics::inc_counter(&metrics::BLOCK_PROCESSING_SUCCESSES); + + let _ = self.event_handler.register(EventKind::BeaconBlockImported { + block_root: block_root, + block: Box::new(block), + }); + + Ok(block_root) + } + // There was an error whilst attempting to verify and import the block. The block might + // be partially verified or partially imported. + Err(BlockError::BeaconChainError(e)) => { + crit!( self.log, "Beacon block processing error"; "error" => format!("{:?}", e), ); + let _ = self.event_handler.register(EventKind::BeaconBlockRejected { reason: format!("Internal error: {:?}", e), block: Box::new(block), }); + + Err(BlockError::BeaconChainError(e)) } - } + // The block failed verification. + Err(other) => { + trace!( + self.log, + "Beacon block rejected"; + "reason" => format!("{:?}", other), + ); - outcome - } - - /// Accept some block and attempt to add it to block DAG. - /// - /// Will accept blocks from prior slots, however it will reject any block from a future slot. - fn process_block_internal( - &self, - signed_block: SignedBeaconBlock, - ) -> Result { - metrics::inc_counter(&metrics::BLOCK_PROCESSING_REQUESTS); - let full_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_TIMES); - - let block = &signed_block.message; - - let finalized_slot = self - .head_info()? - .finalized_checkpoint - .epoch - .start_slot(T::EthSpec::slots_per_epoch()); - - if block.slot == 0 { - return Ok(BlockProcessingOutcome::GenesisBlock); - } - - if block.slot >= MAXIMUM_BLOCK_SLOT_NUMBER { - return Ok(BlockProcessingOutcome::BlockSlotLimitReached); - } - - if block.slot <= finalized_slot { - return Ok(BlockProcessingOutcome::WouldRevertFinalizedSlot { - block_slot: block.slot, - finalized_slot, - }); - } - - // Reject any block if its parent is not known to fork choice. - // - // A block that is not in fork choice is either: - // - // - Not yet imported: we should reject this block because we should only import a child - // after its parent has been fully imported. - // - Pre-finalized: if the parent block is _prior_ to finalization, we should ignore it - // because it will revert finalization. Note that the finalized block is stored in fork - // choice, so we will not reject any child of the finalized block (this is relevant during - // genesis). - if !self.fork_choice.contains_block(&block.parent_root) { - return Ok(BlockProcessingOutcome::ParentUnknown { - parent: block.parent_root, - reference_location: "fork_choice", - }); - } - - let block_root_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_BLOCK_ROOT); - - let block_root = block.canonical_root(); - - metrics::stop_timer(block_root_timer); - - if block_root == self.genesis_block_root { - return Ok(BlockProcessingOutcome::GenesisBlock); - } - - let present_slot = self.slot()?; - - if block.slot > present_slot { - return Ok(BlockProcessingOutcome::FutureSlot { - present_slot, - block_slot: block.slot, - }); - } - - // Check if the block is already known. We know it is post-finalization, so it is - // sufficient to check the fork choice. - if self.fork_choice.contains_block(&block_root) { - return Ok(BlockProcessingOutcome::BlockIsAlreadyKnown); - } - - // Records the time taken to load the block and state from the database during block - // processing. - let db_read_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_DB_READ); - - // Load the blocks parent block from the database, returning invalid if that block is not - // found. - let parent_block = match self.get_block(&block.parent_root)? { - Some(block) => block, - None => { - return Ok(BlockProcessingOutcome::ParentUnknown { - parent: block.parent_root, - reference_location: "database", + let _ = self.event_handler.register(EventKind::BeaconBlockRejected { + reason: format!("Invalid block: {:?}", other), + block: Box::new(block), }); + + Err(other) } }; - // Load the parent blocks state from the database, returning an error if it is not found. - // It is an error because if we know the parent block we should also know the parent state. - let parent_state_root = parent_block.state_root(); - let parent_state = self - .get_state(&parent_state_root, Some(parent_block.slot()))? - .ok_or_else(|| { - Error::DBInconsistent(format!("Missing state {:?}", parent_state_root)) - })?; + // Stop the Prometheus timer. + metrics::stop_timer(full_timer); - metrics::stop_timer(db_read_timer); + result + } - write_block(&block, block_root, &self.log); - - let catchup_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_CATCHUP_STATE); - - // Keep a batch of any states that were "skipped" (block-less) in between the parent state - // slot and the block slot. These will be stored in the database. - let mut intermediate_states = StateBatch::new(); - - // Transition the parent state to the block slot. - let mut state: BeaconState = parent_state; - let distance = block.slot.as_u64().saturating_sub(state.slot.as_u64()); - for i in 0..distance { - let state_root = if i == 0 { - parent_block.state_root() - } else { - // This is a new state we've reached, so stage it for storage in the DB. - // Computing the state root here is time-equivalent to computing it during slot - // processing, but we get early access to it. - let state_root = state.update_tree_hash_cache()?; - intermediate_states.add_state(state_root, &state)?; - state_root - }; - - per_slot_processing(&mut state, Some(state_root), &self.spec)?; - } - - metrics::stop_timer(catchup_timer); - - let committee_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_COMMITTEE); - - state.build_committee_cache(RelativeEpoch::Previous, &self.spec)?; - state.build_committee_cache(RelativeEpoch::Current, &self.spec)?; - - metrics::stop_timer(committee_timer); - - write_state( - &format!("state_pre_block_{}", block_root), - &state, - &self.log, - ); - - let core_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_CORE); - - // Apply the received block to its parent state (which has been transitioned into this - // slot). - match per_block_processing( - &mut state, - &signed_block, - Some(block_root), - BlockSignatureStrategy::VerifyBulk, - &self.spec, - ) { - Err(BlockProcessingError::BeaconStateError(e)) => { - return Err(Error::BeaconStateError(e)) - } - Err(e) => return Ok(BlockProcessingOutcome::PerBlockProcessingError(e)), - _ => {} - } - - metrics::stop_timer(core_timer); - - let state_root_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_STATE_ROOT); - - let state_root = state.update_tree_hash_cache()?; - - metrics::stop_timer(state_root_timer); - - write_state( - &format!("state_post_block_{}", block_root), - &state, - &self.log, - ); - - if block.state_root != state_root { - return Ok(BlockProcessingOutcome::StateRootMismatch { - block: block.state_root, - local: state_root, - }); - } + /// Accepts a fully-verified block and imports it into the chain without performing any + /// additional verification. + /// + /// An error is returned if the block was unable to be imported. It may be partially imported + /// (i.e., this function is not atomic). + fn import_block( + &self, + fully_verified_block: FullyVerifiedBlock, + ) -> Result { + let signed_block = fully_verified_block.block; + let block = &signed_block.message; + let block_root = fully_verified_block.block_root; + let state = fully_verified_block.state; + let parent_block = fully_verified_block.parent_block; + let intermediate_states = fully_verified_block.intermediate_states; let fork_choice_register_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_FORK_CHOICE_REGISTER); @@ -1435,7 +1570,7 @@ impl BeaconChain { // Register the new block with the fork choice service. if let Err(e) = self .fork_choice - .process_block(self, &state, &block, block_root) + .process_block(self, &state, block, block_root) { error!( self.log, @@ -1465,16 +1600,33 @@ impl BeaconChain { // solution would be to use a database transaction (once our choice of database and API // settles down). // See: https://github.com/sigp/lighthouse/issues/692 - self.store.put_state(&state_root, state)?; - self.store.put_block(&block_root, signed_block)?; + self.store.put_state(&block.state_root, &state)?; + self.store.put_block(&block_root, signed_block.clone())?; + + self.snapshot_cache + .try_write_for(BLOCK_PROCESSING_CACHE_LOCK_TIMEOUT) + .map(|mut snapshot_cache| { + snapshot_cache.insert(BeaconSnapshot { + beacon_state: state, + beacon_state_root: signed_block.state_root(), + beacon_block: signed_block, + beacon_block_root: block_root, + }); + }) + .unwrap_or_else(|| { + error!( + self.log, + "Failed to obtain cache write lock"; + "lock" => "snapshot_cache", + "task" => "process block" + ); + }); metrics::stop_timer(db_write_timer); metrics::inc_counter(&metrics::BLOCK_PROCESSING_SUCCESSES); - metrics::stop_timer(full_timer); - - Ok(BlockProcessingOutcome::Processed { block_root }) + Ok(block_root) } /// Produce a new block at the given `slot`. @@ -1597,134 +1749,184 @@ impl BeaconChain { /// Execute the fork choice algorithm and enthrone the result as the canonical head. pub fn fork_choice(&self) -> Result<(), Error> { metrics::inc_counter(&metrics::FORK_CHOICE_REQUESTS); + let overall_timer = metrics::start_timer(&metrics::FORK_CHOICE_TIMES); - // Start fork choice metrics timer. - let timer = metrics::start_timer(&metrics::FORK_CHOICE_TIMES); - - // Determine the root of the block that is the head of the chain. - let beacon_block_root = self.fork_choice.find_head(&self)?; - - // If a new head was chosen. - let result = if beacon_block_root != self.head_info()?.block_root { - metrics::inc_counter(&metrics::FORK_CHOICE_CHANGED_HEAD); - - let beacon_block = self - .get_block(&beacon_block_root)? - .ok_or_else(|| Error::MissingBeaconBlock(beacon_block_root))?; - - let beacon_state_root = beacon_block.state_root(); - let beacon_state: BeaconState = self - .get_state(&beacon_state_root, Some(beacon_block.slot()))? - .ok_or_else(|| Error::MissingBeaconState(beacon_state_root))?; - - let previous_slot = self.head_info()?.slot; - let new_slot = beacon_block.slot(); - - // Note: this will declare a re-org if we skip `SLOTS_PER_HISTORICAL_ROOT` blocks - // between calls to fork choice without swapping between chains. This seems like an - // extreme-enough scenario that a warning is fine. - let is_reorg = self.head_info()?.block_root - != beacon_state - .get_block_root(self.head_info()?.slot) - .map(|root| *root) - .unwrap_or_else(|_| Hash256::random()); - - // If we switched to a new chain (instead of building atop the present chain). - if is_reorg { - metrics::inc_counter(&metrics::FORK_CHOICE_REORG_COUNT); - warn!( - self.log, - "Beacon chain re-org"; - "previous_head" => format!("{}", self.head_info()?.block_root), - "previous_slot" => previous_slot, - "new_head_parent" => format!("{}", beacon_block.parent_root()), - "new_head" => format!("{}", beacon_block_root), - "new_slot" => new_slot - ); - } else { - debug!( - self.log, - "Head beacon block"; - "justified_root" => format!("{}", beacon_state.current_justified_checkpoint.root), - "justified_epoch" => beacon_state.current_justified_checkpoint.epoch, - "finalized_root" => format!("{}", beacon_state.finalized_checkpoint.root), - "finalized_epoch" => beacon_state.finalized_checkpoint.epoch, - "root" => format!("{}", beacon_block_root), - "slot" => new_slot, - ); - }; - - let old_finalized_epoch = self.head_info()?.finalized_checkpoint.epoch; - let new_finalized_epoch = beacon_state.finalized_checkpoint.epoch; - let finalized_root = beacon_state.finalized_checkpoint.root; - - // Never revert back past a finalized epoch. - if new_finalized_epoch < old_finalized_epoch { - Err(Error::RevertedFinalizedEpoch { - previous_epoch: old_finalized_epoch, - new_epoch: new_finalized_epoch, - }) - } else { - let previous_head_beacon_block_root = self - .canonical_head - .try_read_for(HEAD_LOCK_TIMEOUT) - .ok_or_else(|| Error::CanonicalHeadLockTimeout)? - .beacon_block_root; - let current_head_beacon_block_root = beacon_block_root; - - let mut new_head = CheckPoint { - beacon_block, - beacon_block_root, - beacon_state, - beacon_state_root, - }; - - new_head.beacon_state.build_all_caches(&self.spec)?; - - let timer = metrics::start_timer(&metrics::UPDATE_HEAD_TIMES); - - // Update the checkpoint that stores the head of the chain at the time it received the - // block. - *self - .canonical_head - .try_write_for(HEAD_LOCK_TIMEOUT) - .ok_or_else(|| Error::CanonicalHeadLockTimeout)? = new_head; - - metrics::stop_timer(timer); - - if previous_slot.epoch(T::EthSpec::slots_per_epoch()) - < new_slot.epoch(T::EthSpec::slots_per_epoch()) - || is_reorg - { - self.persist_head_and_fork_choice()?; - } - - let _ = self.event_handler.register(EventKind::BeaconHeadChanged { - reorg: is_reorg, - previous_head_beacon_block_root, - current_head_beacon_block_root, - }); - - if new_finalized_epoch != old_finalized_epoch { - self.after_finalization(old_finalized_epoch, finalized_root)?; - } - - Ok(()) - } - } else { - Ok(()) - }; - - // End fork choice metrics timer. - metrics::stop_timer(timer); + let result = self.fork_choice_internal(); if result.is_err() { metrics::inc_counter(&metrics::FORK_CHOICE_ERRORS); } + metrics::stop_timer(overall_timer); + result } + fn fork_choice_internal(&self) -> Result<(), Error> { + // Determine the root of the block that is the head of the chain. + let beacon_block_root = self.fork_choice.find_head(&self)?; + + let current_head = self.head_info()?; + + if beacon_block_root == current_head.block_root { + return Ok(()); + } + + // At this point we know that the new head block is not the same as the previous one + metrics::inc_counter(&metrics::FORK_CHOICE_CHANGED_HEAD); + + // Try and obtain the snapshot for `beacon_block_root` from the snapshot cache, falling + // back to a database read if that fails. + let new_head = self + .snapshot_cache + .try_read_for(BLOCK_PROCESSING_CACHE_LOCK_TIMEOUT) + .and_then(|snapshot_cache| snapshot_cache.get_cloned(beacon_block_root)) + .map::, _>(|snapshot| Ok(snapshot)) + .unwrap_or_else(|| { + let beacon_block = self + .get_block(&beacon_block_root)? + .ok_or_else(|| Error::MissingBeaconBlock(beacon_block_root))?; + + let beacon_state_root = beacon_block.state_root(); + let beacon_state: BeaconState = self + .get_state(&beacon_state_root, Some(beacon_block.slot()))? + .ok_or_else(|| Error::MissingBeaconState(beacon_state_root))?; + + Ok(BeaconSnapshot { + beacon_block, + beacon_block_root, + beacon_state, + beacon_state_root, + }) + }) + .and_then(|mut snapshot| { + // Regardless of where we got the state from, attempt to build the committee + // caches. + snapshot + .beacon_state + .build_all_committee_caches(&self.spec) + .map_err(Into::into) + .map(|()| snapshot) + })?; + + // Attempt to detect if the new head is not on the same chain as the previous block + // (i.e., a re-org). + // + // Note: this will declare a re-org if we skip `SLOTS_PER_HISTORICAL_ROOT` blocks + // between calls to fork choice without swapping between chains. This seems like an + // extreme-enough scenario that a warning is fine. + let is_reorg = current_head.block_root + != new_head + .beacon_state + .get_block_root(current_head.slot) + .map(|root| *root) + .unwrap_or_else(|_| Hash256::random()); + + if is_reorg { + metrics::inc_counter(&metrics::FORK_CHOICE_REORG_COUNT); + warn!( + self.log, + "Beacon chain re-org"; + "previous_head" => format!("{}", current_head.block_root), + "previous_slot" => current_head.slot, + "new_head_parent" => format!("{}", new_head.beacon_block.parent_root()), + "new_head" => format!("{}", beacon_block_root), + "new_slot" => new_head.beacon_block.slot() + ); + } else { + debug!( + self.log, + "Head beacon block"; + "justified_root" => format!("{}", new_head.beacon_state.current_justified_checkpoint.root), + "justified_epoch" => new_head.beacon_state.current_justified_checkpoint.epoch, + "finalized_root" => format!("{}", new_head.beacon_state.finalized_checkpoint.root), + "finalized_epoch" => new_head.beacon_state.finalized_checkpoint.epoch, + "root" => format!("{}", beacon_block_root), + "slot" => new_head.beacon_block.slot(), + ); + }; + + let old_finalized_epoch = current_head.finalized_checkpoint.epoch; + let new_finalized_epoch = new_head.beacon_state.finalized_checkpoint.epoch; + let finalized_root = new_head.beacon_state.finalized_checkpoint.root; + + // It is an error to try to update to a head with a lesser finalized epoch. + if new_finalized_epoch < old_finalized_epoch { + return Err(Error::RevertedFinalizedEpoch { + previous_epoch: old_finalized_epoch, + new_epoch: new_finalized_epoch, + }); + } + + if current_head.slot.epoch(T::EthSpec::slots_per_epoch()) + < new_head + .beacon_state + .slot + .epoch(T::EthSpec::slots_per_epoch()) + || is_reorg + { + self.persist_head_and_fork_choice()?; + } + + let update_head_timer = metrics::start_timer(&metrics::UPDATE_HEAD_TIMES); + + // Update the snapshot that stores the head of the chain at the time it received the + // block. + *self + .canonical_head + .try_write_for(HEAD_LOCK_TIMEOUT) + .ok_or_else(|| Error::CanonicalHeadLockTimeout)? = new_head; + + metrics::stop_timer(update_head_timer); + + self.snapshot_cache + .try_write_for(BLOCK_PROCESSING_CACHE_LOCK_TIMEOUT) + .map(|mut snapshot_cache| { + snapshot_cache.update_head(beacon_block_root); + }) + .unwrap_or_else(|| { + error!( + self.log, + "Failed to obtain cache write lock"; + "lock" => "snapshot_cache", + "task" => "update head" + ); + }); + + if new_finalized_epoch != old_finalized_epoch { + self.after_finalization(old_finalized_epoch, finalized_root)?; + } + + let _ = self.event_handler.register(EventKind::BeaconHeadChanged { + reorg: is_reorg, + previous_head_beacon_block_root: current_head.block_root, + current_head_beacon_block_root: beacon_block_root, + }); + + Ok(()) + } + + /// Called by the timer on every slot. + /// + /// Performs slot-based pruning. + pub fn per_slot_task(&self) { + trace!(self.log, "Running beacon chain per slot tasks"); + if let Some(slot) = self.slot_clock.now() { + self.op_pool.prune_committee_attestations(&slot) + } + } + + /// Called by the timer on every epoch. + /// + /// Performs epoch-based pruning. + pub fn per_epoch_task(&self) { + trace!(self.log, "Running beacon chain per epoch tasks"); + if let Some(slot) = self.slot_clock.now() { + let current_epoch = slot.epoch(T::EthSpec::slots_per_epoch()); + self.op_pool.prune_attestations(¤t_epoch); + } + } + /// Called after `self` has had a new block finalized. /// /// Performs pruning and finality-based optimizations. @@ -1749,11 +1951,22 @@ impl BeaconChain { } else { self.fork_choice.prune()?; + self.snapshot_cache + .try_write_for(BLOCK_PROCESSING_CACHE_LOCK_TIMEOUT) + .map(|mut snapshot_cache| { + snapshot_cache.prune(new_finalized_epoch); + }) + .unwrap_or_else(|| { + error!( + self.log, + "Failed to obtain cache write lock"; + "lock" => "snapshot_cache", + "task" => "prune" + ); + }); + let finalized_state = self - .get_state_caching_only_with_committee_caches( - &finalized_block.state_root, - Some(finalized_block.slot), - )? + .get_state(&finalized_block.state_root, Some(finalized_block.slot))? .ok_or_else(|| Error::MissingBeaconState(finalized_block.state_root))?; self.op_pool.prune_all(&finalized_state, &self.spec); @@ -1786,10 +1999,10 @@ impl BeaconChain { /// /// 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 { + let mut last_slot = BeaconSnapshot { beacon_block: self.head()?.beacon_block, beacon_block_root: self.head()?.beacon_block_root, beacon_state: self.head()?.beacon_state, @@ -1816,7 +2029,7 @@ impl BeaconChain { Error::DBInconsistent(format!("Missing state {:?}", beacon_state_root)) })?; - let slot = CheckPoint { + let slot = BeaconSnapshot { beacon_block, beacon_block_root, beacon_state, @@ -1856,49 +2069,6 @@ impl Drop for BeaconChain { } } -fn write_state(prefix: &str, state: &BeaconState, log: &Logger) { - if WRITE_BLOCK_PROCESSING_SSZ { - let root = state.tree_hash_root(); - let filename = format!("{}_slot_{}_root_{}.ssz", prefix, state.slot, root); - let mut path = std::env::temp_dir().join("lighthouse"); - let _ = fs::create_dir_all(path.clone()); - path = path.join(filename); - - match fs::File::create(path.clone()) { - Ok(mut file) => { - let _ = file.write_all(&state.as_ssz_bytes()); - } - Err(e) => error!( - log, - "Failed to log state"; - "path" => format!("{:?}", path), - "error" => format!("{:?}", e) - ), - } - } -} - -fn write_block(block: &BeaconBlock, root: Hash256, log: &Logger) { - if WRITE_BLOCK_PROCESSING_SSZ { - let filename = format!("block_slot_{}_root{}.ssz", block.slot, root); - let mut path = std::env::temp_dir().join("lighthouse"); - let _ = fs::create_dir_all(path.clone()); - path = path.join(filename); - - match fs::File::create(path.clone()) { - Ok(mut file) => { - let _ = file.write_all(&block.as_ssz_bytes()); - } - Err(e) => error!( - log, - "Failed to log block"; - "path" => format!("{:?}", path), - "error" => format!("{:?}", e) - ), - } - } -} - impl From for Error { fn from(e: DBError) -> Error { Error::DBError(e) diff --git a/beacon_node/beacon_chain/src/checkpoint.rs b/beacon_node/beacon_chain/src/beacon_snapshot.rs similarity index 95% rename from beacon_node/beacon_chain/src/checkpoint.rs rename to beacon_node/beacon_chain/src/beacon_snapshot.rs index 79d0f94b7..377850b3a 100644 --- a/beacon_node/beacon_chain/src/checkpoint.rs +++ b/beacon_node/beacon_chain/src/beacon_snapshot.rs @@ -5,14 +5,14 @@ use types::{BeaconState, EthSpec, Hash256, SignedBeaconBlock}; /// Represents some block and its associated state. Generally, this will be used for tracking the /// head, justified head and finalized head. #[derive(Clone, Serialize, PartialEq, Debug, Encode, Decode)] -pub struct CheckPoint { +pub struct BeaconSnapshot { pub beacon_block: SignedBeaconBlock, pub beacon_block_root: Hash256, pub beacon_state: BeaconState, pub beacon_state_root: Hash256, } -impl CheckPoint { +impl BeaconSnapshot { /// Create a new checkpoint. pub fn new( beacon_block: SignedBeaconBlock, diff --git a/beacon_node/beacon_chain/src/block_verification.rs b/beacon_node/beacon_chain/src/block_verification.rs new file mode 100644 index 000000000..cd4a8db52 --- /dev/null +++ b/beacon_node/beacon_chain/src/block_verification.rs @@ -0,0 +1,801 @@ +//! Provides `SignedBeaconBlock` verification logic. +//! +//! Specifically, it provides the following: +//! +//! - Verification for gossip blocks (i.e., should we gossip some block from the network). +//! - Verification for normal blocks (e.g., some block received on the RPC during a parent lookup). +//! - Verification for chain segments (e.g., some chain of blocks received on the RPC during a +//! sync). +//! +//! The primary source of complexity here is that we wish to avoid doing duplicate work as a block +//! moves through the verification process. For example, if some block is verified for gossip, we +//! do not wish to re-verify the block proposal signature or re-hash the block. Or, if we've +//! verified the signatures of a block during a chain segment import, we do not wish to verify each +//! signature individually again. +//! +//! The incremental processing steps (e.g., signatures verified but not the state transition) is +//! represented as a sequence of wrapper-types around the block. There is a linear progression of +//! types, starting at a `SignedBeaconBlock` and finishing with a `Fully VerifiedBlock` (see +//! diagram below). +//! +//! ```ignore +//! START +//! | +//! â–¼ +//! SignedBeaconBlock +//! |--------------- +//! | | +//! | â–¼ +//! | GossipVerifiedBlock +//! | | +//! |--------------- +//! | +//! â–¼ +//! SignatureVerifiedBlock +//! | +//! â–¼ +//! FullyVerifiedBlock +//! | +//! â–¼ +//! END +//! +//! ``` +use crate::validator_pubkey_cache::ValidatorPubkeyCache; +use crate::{ + beacon_chain::{BLOCK_PROCESSING_CACHE_LOCK_TIMEOUT, VALIDATOR_PUBKEY_CACHE_LOCK_TIMEOUT}, + metrics, BeaconChain, BeaconChainError, BeaconChainTypes, BeaconSnapshot, +}; +use parking_lot::RwLockReadGuard; +use state_processing::{ + block_signature_verifier::{ + BlockSignatureVerifier, Error as BlockSignatureVerifierError, G1Point, + }, + per_block_processing, per_slot_processing, BlockProcessingError, BlockSignatureStrategy, + SlotProcessingError, +}; +use std::borrow::Cow; +use store::{Error as DBError, StateBatch}; +use types::{ + BeaconBlock, BeaconState, BeaconStateError, ChainSpec, CloneConfig, EthSpec, Hash256, + RelativeEpoch, SignedBeaconBlock, Slot, +}; + +mod block_processing_outcome; + +pub use block_processing_outcome::BlockProcessingOutcome; + +/// Maximum block slot number. Block with slots bigger than this constant will NOT be processed. +const MAXIMUM_BLOCK_SLOT_NUMBER: u64 = 4_294_967_296; // 2^32 + +/// Returned when a block was not verified. A block is not verified for two reasons: +/// +/// - The block is malformed/invalid (indicated by all results other than `BeaconChainError`. +/// - We encountered an error whilst trying to verify the block (a `BeaconChainError`). +#[derive(Debug, PartialEq)] +pub enum BlockError { + /// The parent block was unknown. + ParentUnknown(Hash256), + /// The block slot is greater than the present slot. + FutureSlot { + present_slot: Slot, + block_slot: Slot, + }, + /// The block state_root does not match the generated state. + StateRootMismatch { block: Hash256, local: Hash256 }, + /// The block was a genesis block, these blocks cannot be re-imported. + GenesisBlock, + /// The slot is finalized, no need to import. + WouldRevertFinalizedSlot { + block_slot: Slot, + finalized_slot: Slot, + }, + /// Block is already known, no need to re-import. + BlockIsAlreadyKnown, + /// The block slot exceeds the MAXIMUM_BLOCK_SLOT_NUMBER. + BlockSlotLimitReached, + /// The proposal signature in invalid. + ProposalSignatureInvalid, + /// A signature in the block is invalid (exactly which is unknown). + InvalidSignature, + /// The provided block is from an earlier slot than its parent. + BlockIsNotLaterThanParent { block_slot: Slot, state_slot: Slot }, + /// At least one block in the chain segement did not have it's parent root set to the root of + /// the prior block. + NonLinearParentRoots, + /// The slots of the blocks in the chain segment were not strictly increasing. I.e., a child + /// had lower slot than a parent. + NonLinearSlots, + /// The block failed the specification's `per_block_processing` function, it is invalid. + PerBlockProcessingError(BlockProcessingError), + /// There was an error whilst processing the block. It is not necessarily invalid. + BeaconChainError(BeaconChainError), +} + +impl From for BlockError { + fn from(e: BlockSignatureVerifierError) -> Self { + BlockError::BeaconChainError(BeaconChainError::BlockSignatureVerifierError(e)) + } +} + +impl From for BlockError { + fn from(e: BeaconChainError) -> Self { + BlockError::BeaconChainError(e) + } +} + +impl From for BlockError { + fn from(e: BeaconStateError) -> Self { + BlockError::BeaconChainError(BeaconChainError::BeaconStateError(e)) + } +} + +impl From for BlockError { + fn from(e: SlotProcessingError) -> Self { + BlockError::BeaconChainError(BeaconChainError::SlotProcessingError(e)) + } +} + +impl From for BlockError { + fn from(e: DBError) -> Self { + BlockError::BeaconChainError(BeaconChainError::DBError(e)) + } +} + +/// Verify all signatures (except deposit signatures) on all blocks in the `chain_segment`. If all +/// signatures are valid, the `chain_segment` is mapped to a `Vec` that can +/// later be transformed into a `FullyVerifiedBlock` without re-checking the signatures. If any +/// signature in the block is invalid, an `Err` is returned (it is not possible to known _which_ +/// signature was invalid). +/// +/// ## Errors +/// +/// The given `chain_segement` must span no more than two epochs, otherwise an error will be +/// returned. +pub fn signature_verify_chain_segment( + chain_segment: Vec<(Hash256, SignedBeaconBlock)>, + chain: &BeaconChain, +) -> Result>, BlockError> { + let (mut parent, slot) = if let Some(block) = chain_segment.first().map(|(_, block)| block) { + let parent = load_parent(&block.message, chain)?; + (parent, block.slot()) + } else { + return Ok(vec![]); + }; + + let highest_slot = chain_segment + .last() + .map(|(_, block)| block.slot()) + .unwrap_or_else(|| slot); + + let state = cheap_state_advance_to_obtain_committees( + &mut parent.beacon_state, + highest_slot, + &chain.spec, + )?; + + let pubkey_cache = get_validator_pubkey_cache(chain)?; + let mut signature_verifier = get_signature_verifier(&state, &pubkey_cache, &chain.spec); + + for (block_root, block) in &chain_segment { + signature_verifier.include_all_signatures(block, Some(*block_root))?; + } + + if signature_verifier.verify().is_err() { + return Err(BlockError::InvalidSignature); + } + + drop(pubkey_cache); + + let mut signature_verified_blocks = chain_segment + .into_iter() + .map(|(block_root, block)| SignatureVerifiedBlock { + block, + block_root, + parent: None, + }) + .collect::>(); + + if let Some(signature_verified_block) = signature_verified_blocks.first_mut() { + signature_verified_block.parent = Some(parent); + } + + Ok(signature_verified_blocks) +} + +/// A wrapper around a `SignedBeaconBlock` that indicates it has been approved for re-gossiping on +/// the p2p network. +pub struct GossipVerifiedBlock { + block: SignedBeaconBlock, + block_root: Hash256, + parent: BeaconSnapshot, +} + +/// A wrapper around a `SignedBeaconBlock` that indicates that all signatures (except the deposit +/// signatures) have been verified. +pub struct SignatureVerifiedBlock { + block: SignedBeaconBlock, + block_root: Hash256, + parent: Option>, +} + +/// A wrapper around a `SignedBeaconBlock` that indicates that this block is fully verified and +/// ready to import into the `BeaconChain`. The validation includes: +/// +/// - Parent is known +/// - Signatures +/// - State root check +/// - Per block processing +/// +/// Note: a `FullyVerifiedBlock` is not _forever_ valid to be imported, it may later become invalid +/// due to finality or some other event. A `FullyVerifiedBlock` should be imported into the +/// `BeaconChain` immediately after it is instantiated. +pub struct FullyVerifiedBlock { + pub block: SignedBeaconBlock, + pub block_root: Hash256, + pub state: BeaconState, + pub parent_block: SignedBeaconBlock, + pub intermediate_states: StateBatch, +} + +/// Implemented on types that can be converted into a `FullyVerifiedBlock`. +/// +/// Used to allow functions to accept blocks at various stages of verification. +pub trait IntoFullyVerifiedBlock { + fn into_fully_verified_block( + self, + chain: &BeaconChain, + ) -> Result, BlockError>; + + fn block(&self) -> &SignedBeaconBlock; +} + +impl GossipVerifiedBlock { + /// Instantiates `Self`, a wrapper that indicates the given `block` is safe to be re-gossiped + /// on the p2p network. + /// + /// Returns an error if the block is invalid, or if the block was unable to be verified. + pub fn new( + block: SignedBeaconBlock, + chain: &BeaconChain, + ) -> Result { + // Do not gossip or process blocks from future slots. + // + // TODO: adjust this to allow for clock disparity tolerance. + let present_slot = chain.slot()?; + if block.slot() > present_slot { + return Err(BlockError::FutureSlot { + present_slot, + block_slot: block.slot(), + }); + } + + // Do not gossip a block from a finalized slot. + // + // TODO: adjust this to allow for clock disparity tolerance. + check_block_against_finalized_slot(&block.message, chain)?; + + // TODO: add check for the `(block.proposer_index, block.slot)` tuple once we have v0.11.0 + + let mut parent = load_parent(&block.message, chain)?; + let block_root = get_block_root(&block); + + let state = cheap_state_advance_to_obtain_committees( + &mut parent.beacon_state, + block.slot(), + &chain.spec, + )?; + + let pubkey_cache = get_validator_pubkey_cache(chain)?; + + let mut signature_verifier = get_signature_verifier(&state, &pubkey_cache, &chain.spec); + + signature_verifier.include_block_proposal(&block, Some(block_root))?; + + if signature_verifier.verify().is_ok() { + Ok(Self { + block, + block_root, + parent, + }) + } else { + Err(BlockError::ProposalSignatureInvalid) + } + } +} + +impl IntoFullyVerifiedBlock for GossipVerifiedBlock { + /// Completes verification of the wrapped `block`. + fn into_fully_verified_block( + self, + chain: &BeaconChain, + ) -> Result, BlockError> { + let fully_verified = SignatureVerifiedBlock::from_gossip_verified_block(self, chain)?; + fully_verified.into_fully_verified_block(chain) + } + + fn block(&self) -> &SignedBeaconBlock { + &self.block + } +} + +impl SignatureVerifiedBlock { + /// Instantiates `Self`, a wrapper that indicates that all signatures (except the deposit + /// signatures) are valid (i.e., signed by the correct public keys). + /// + /// Returns an error if the block is invalid, or if the block was unable to be verified. + pub fn new( + block: SignedBeaconBlock, + chain: &BeaconChain, + ) -> Result { + let mut parent = load_parent(&block.message, chain)?; + let block_root = get_block_root(&block); + + let state = cheap_state_advance_to_obtain_committees( + &mut parent.beacon_state, + block.slot(), + &chain.spec, + )?; + + let pubkey_cache = get_validator_pubkey_cache(chain)?; + + let mut signature_verifier = get_signature_verifier(&state, &pubkey_cache, &chain.spec); + + signature_verifier.include_all_signatures(&block, Some(block_root))?; + + if signature_verifier.verify().is_ok() { + Ok(Self { + block, + block_root, + parent: Some(parent), + }) + } else { + Err(BlockError::InvalidSignature) + } + } + + /// Finishes signature verification on the provided `GossipVerifedBlock`. Does not re-verify + /// the proposer signature. + pub fn from_gossip_verified_block( + from: GossipVerifiedBlock, + chain: &BeaconChain, + ) -> Result { + let mut parent = from.parent; + let block = from.block; + + let state = cheap_state_advance_to_obtain_committees( + &mut parent.beacon_state, + block.slot(), + &chain.spec, + )?; + + let pubkey_cache = get_validator_pubkey_cache(chain)?; + + let mut signature_verifier = get_signature_verifier(&state, &pubkey_cache, &chain.spec); + + signature_verifier.include_all_signatures_except_proposal(&block)?; + + if signature_verifier.verify().is_ok() { + Ok(Self { + block, + block_root: from.block_root, + parent: Some(parent), + }) + } else { + Err(BlockError::InvalidSignature) + } + } +} + +impl IntoFullyVerifiedBlock for SignatureVerifiedBlock { + /// Completes verification of the wrapped `block`. + fn into_fully_verified_block( + self, + chain: &BeaconChain, + ) -> Result, BlockError> { + let block = self.block; + let parent = self + .parent + .map(Result::Ok) + .unwrap_or_else(|| load_parent(&block.message, chain))?; + + FullyVerifiedBlock::from_signature_verified_components( + block, + self.block_root, + parent, + chain, + ) + } + + fn block(&self) -> &SignedBeaconBlock { + &self.block + } +} + +impl IntoFullyVerifiedBlock for SignedBeaconBlock { + /// Verifies the `SignedBeaconBlock` by first transforming it into a `SignatureVerifiedBlock` + /// and then using that implementation of `IntoFullyVerifiedBlock` to complete verification. + fn into_fully_verified_block( + self, + chain: &BeaconChain, + ) -> Result, BlockError> { + SignatureVerifiedBlock::new(self, chain)?.into_fully_verified_block(chain) + } + + fn block(&self) -> &SignedBeaconBlock { + &self + } +} + +impl FullyVerifiedBlock { + /// Instantiates `Self`, a wrapper that indicates that the given `block` is fully valid. See + /// the struct-level documentation for more information. + /// + /// Note: this function does not verify block signatures, it assumes they are valid. Signature + /// verification must be done upstream (e.g., via a `SignatureVerifiedBlock` + /// + /// Returns an error if the block is invalid, or if the block was unable to be verified. + pub fn from_signature_verified_components( + block: SignedBeaconBlock, + block_root: Hash256, + parent: BeaconSnapshot, + chain: &BeaconChain, + ) -> Result { + // Reject any block if its parent is not known to fork choice. + // + // A block that is not in fork choice is either: + // + // - Not yet imported: we should reject this block because we should only import a child + // after its parent has been fully imported. + // - Pre-finalized: if the parent block is _prior_ to finalization, we should ignore it + // because it will revert finalization. Note that the finalized block is stored in fork + // choice, so we will not reject any child of the finalized block (this is relevant during + // genesis). + if !chain.fork_choice.contains_block(&block.parent_root()) { + return Err(BlockError::ParentUnknown(block.parent_root())); + } + + /* + * Perform cursory checks to see if the block is even worth processing. + */ + + check_block_relevancy(&block, Some(block_root), chain)?; + + /* + * Advance the given `parent.beacon_state` to the slot of the given `block`. + */ + + let catchup_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_CATCHUP_STATE); + + // Keep a batch of any states that were "skipped" (block-less) in between the parent state + // slot and the block slot. These will be stored in the database. + let mut intermediate_states = StateBatch::new(); + + // The block must have a higher slot than its parent. + if block.slot() <= parent.beacon_state.slot { + return Err(BlockError::BlockIsNotLaterThanParent { + block_slot: block.slot(), + state_slot: parent.beacon_state.slot, + }); + } + + // Transition the parent state to the block slot. + let mut state = parent.beacon_state; + let distance = block.slot().as_u64().saturating_sub(state.slot.as_u64()); + for i in 0..distance { + let state_root = if i == 0 { + parent.beacon_block.state_root() + } else { + // This is a new state we've reached, so stage it for storage in the DB. + // Computing the state root here is time-equivalent to computing it during slot + // processing, but we get early access to it. + let state_root = state.update_tree_hash_cache()?; + intermediate_states.add_state(state_root, &state)?; + state_root + }; + + per_slot_processing(&mut state, Some(state_root), &chain.spec)?; + } + + metrics::stop_timer(catchup_timer); + + /* + * Build the committee caches on the state. + */ + + let committee_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_COMMITTEE); + + state.build_committee_cache(RelativeEpoch::Previous, &chain.spec)?; + state.build_committee_cache(RelativeEpoch::Current, &chain.spec)?; + + metrics::stop_timer(committee_timer); + + /* + * Perform `per_block_processing` on the block and state, returning early if the block is + * invalid. + */ + + let core_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_CORE); + + if let Err(err) = per_block_processing( + &mut state, + &block, + Some(block_root), + // Signatures were verified earlier in this function. + BlockSignatureStrategy::NoVerification, + &chain.spec, + ) { + match err { + // Capture `BeaconStateError` so that we can easily distinguish between a block + // that's invalid and one that caused an internal error. + BlockProcessingError::BeaconStateError(e) => return Err(e.into()), + other => return Err(BlockError::PerBlockProcessingError(other)), + } + }; + + metrics::stop_timer(core_timer); + + /* + * Calculate the state root of the newly modified state + */ + + let state_root_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_STATE_ROOT); + + let state_root = state.update_tree_hash_cache()?; + + metrics::stop_timer(state_root_timer); + + /* + * Check to ensure the state root on the block matches the one we have calculated. + */ + + if block.state_root() != state_root { + return Err(BlockError::StateRootMismatch { + block: block.state_root(), + local: state_root, + }); + } + + Ok(Self { + block, + block_root, + state, + parent_block: parent.beacon_block, + intermediate_states, + }) + } +} + +/// Returns `Ok(())` if the block is later than the finalized slot on `chain`. +/// +/// Returns an error if the block is earlier or equal to the finalized slot, or there was an error +/// verifying that condition. +fn check_block_against_finalized_slot( + block: &BeaconBlock, + chain: &BeaconChain, +) -> Result<(), BlockError> { + let finalized_slot = chain + .head_info()? + .finalized_checkpoint + .epoch + .start_slot(T::EthSpec::slots_per_epoch()); + + if block.slot <= finalized_slot { + Err(BlockError::WouldRevertFinalizedSlot { + block_slot: block.slot, + finalized_slot, + }) + } else { + Ok(()) + } +} + +/// Performs simple, cheap checks to ensure that the block is relevant to imported. +/// +/// `Ok(block_root)` is returned if the block passes these checks and should progress with +/// verification (viz., it is relevant). +/// +/// Returns an error if the block fails one of these checks (viz., is not relevant) or an error is +/// experienced whilst attempting to verify. +pub fn check_block_relevancy( + signed_block: &SignedBeaconBlock, + block_root: Option, + chain: &BeaconChain, +) -> Result { + let block = &signed_block.message; + + // Do not process blocks from the future. + if block.slot > chain.slot()? { + return Err(BlockError::FutureSlot { + present_slot: chain.slot()?, + block_slot: block.slot, + }); + } + + // Do not re-process the genesis block. + if block.slot == 0 { + return Err(BlockError::GenesisBlock); + } + + // This is an artificial (non-spec) restriction that provides some protection from overflow + // abuses. + if block.slot >= MAXIMUM_BLOCK_SLOT_NUMBER { + return Err(BlockError::BlockSlotLimitReached); + } + + // Do not process a block from a finalized slot. + check_block_against_finalized_slot(block, chain)?; + + let block_root = block_root.unwrap_or_else(|| get_block_root(&signed_block)); + + // Check if the block is already known. We know it is post-finalization, so it is + // sufficient to check the fork choice. + if chain.fork_choice.contains_block(&block_root) { + return Err(BlockError::BlockIsAlreadyKnown); + } + + Ok(block_root) +} + +/// Returns the canonical root of the given `block`. +/// +/// Use this function to ensure that we report the block hashing time Prometheus metric. +pub fn get_block_root(block: &SignedBeaconBlock) -> Hash256 { + let block_root_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_BLOCK_ROOT); + + let block_root = block.canonical_root(); + + metrics::stop_timer(block_root_timer); + + block_root +} + +/// Load the parent snapshot (block and state) of the given `block`. +/// +/// Returns `Err(BlockError::ParentUnknown)` if the parent is not found, or if an error occurs +/// whilst attempting the operation. +fn load_parent( + block: &BeaconBlock, + chain: &BeaconChain, +) -> Result, BlockError> { + let db_read_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_DB_READ); + + // Reject any block if its parent is not known to fork choice. + // + // A block that is not in fork choice is either: + // + // - Not yet imported: we should reject this block because we should only import a child + // after its parent has been fully imported. + // - Pre-finalized: if the parent block is _prior_ to finalization, we should ignore it + // because it will revert finalization. Note that the finalized block is stored in fork + // choice, so we will not reject any child of the finalized block (this is relevant during + // genesis). + if !chain.fork_choice.contains_block(&block.parent_root) { + return Err(BlockError::ParentUnknown(block.parent_root)); + } + + // Load the parent block and state from disk, returning early if it's not available. + let result = chain + .snapshot_cache + .try_write_for(BLOCK_PROCESSING_CACHE_LOCK_TIMEOUT) + .and_then(|mut snapshot_cache| snapshot_cache.try_remove(block.parent_root)) + .map(|snapshot| Ok(Some(snapshot))) + .unwrap_or_else(|| { + // Load the blocks parent block from the database, returning invalid if that block is not + // found. + // + // We don't return a DBInconsistent error here since it's possible for a block to + // exist in fork choice but not in the database yet. In such a case we simply + // indicate that we don't yet know the parent. + let parent_block = if let Some(block) = chain.get_block(&block.parent_root)? { + block + } else { + return Ok(None); + }; + + // Load the parent blocks state from the database, returning an error if it is not found. + // It is an error because if we know the parent block we should also know the parent state. + let parent_state_root = parent_block.state_root(); + let parent_state = chain + .get_state(&parent_state_root, Some(parent_block.slot()))? + .ok_or_else(|| { + BeaconChainError::DBInconsistent(format!( + "Missing state {:?}", + parent_state_root + )) + })?; + + Ok(Some(BeaconSnapshot { + beacon_block: parent_block, + beacon_block_root: block.parent_root, + beacon_state: parent_state, + beacon_state_root: parent_state_root, + })) + }) + .map_err(BlockError::BeaconChainError)? + .ok_or_else(|| BlockError::ParentUnknown(block.parent_root)); + + metrics::stop_timer(db_read_timer); + + result +} + +/// Performs a cheap (time-efficient) state advancement so the committees for `slot` can be +/// obtained from `state`. +/// +/// The state advancement is "cheap" since it does not generate state roots. As a result, the +/// returned state might be holistically invalid but the committees will be correct (since they do +/// not rely upon state roots). +/// +/// If the given `state` can already serve the `slot`, the committees will be built on the `state` +/// and `Cow::Borrowed(state)` will be returned. Otherwise, the state will be cloned, cheaply +/// advanced and then returned as a `Cow::Owned`. The end result is that the given `state` is never +/// mutated to be invalid (in fact, it is never changed beyond a simple committee cache build). +fn cheap_state_advance_to_obtain_committees<'a, E: EthSpec>( + state: &'a mut BeaconState, + block_slot: Slot, + spec: &ChainSpec, +) -> Result>, BlockError> { + let block_epoch = block_slot.epoch(E::slots_per_epoch()); + + if state.current_epoch() == block_epoch { + state.build_committee_cache(RelativeEpoch::Current, spec)?; + + Ok(Cow::Borrowed(state)) + } else if state.slot > block_slot { + Err(BlockError::BlockIsNotLaterThanParent { + block_slot, + state_slot: state.slot, + }) + } else { + let mut state = state.clone_with(CloneConfig::committee_caches_only()); + + while state.current_epoch() < block_epoch { + // Don't calculate state roots since they aren't required for calculating + // shuffling (achieved by providing Hash256::zero()). + per_slot_processing(&mut state, Some(Hash256::zero()), spec).map_err(|e| { + BlockError::BeaconChainError(BeaconChainError::SlotProcessingError(e)) + })?; + } + + state.build_committee_cache(RelativeEpoch::Current, spec)?; + + Ok(Cow::Owned(state)) + } +} + +/// Obtains a read-locked `ValidatorPubkeyCache` from the `chain`. +fn get_validator_pubkey_cache( + chain: &BeaconChain, +) -> Result, BlockError> { + chain + .validator_pubkey_cache + .try_read_for(VALIDATOR_PUBKEY_CACHE_LOCK_TIMEOUT) + .ok_or_else(|| BeaconChainError::ValidatorPubkeyCacheLockTimeout) + .map_err(BlockError::BeaconChainError) +} + +/// Produces an _empty_ `BlockSignatureVerifier`. +/// +/// The signature verifier is empty because it does not yet have any of this block's signatures +/// added to it. Use `Self::apply_to_signature_verifier` to apply the signatures. +fn get_signature_verifier<'a, E: EthSpec>( + state: &'a BeaconState, + validator_pubkey_cache: &'a ValidatorPubkeyCache, + spec: &'a ChainSpec, +) -> BlockSignatureVerifier<'a, E, impl Fn(usize) -> Option> + Clone> { + BlockSignatureVerifier::new( + state, + move |validator_index| { + // Disallow access to any validator pubkeys that are not in the current beacon + // state. + if validator_index < state.validators.len() { + validator_pubkey_cache + .get(validator_index) + .map(|pk| Cow::Borrowed(pk.as_point())) + } else { + None + } + }, + spec, + ) +} diff --git a/beacon_node/beacon_chain/src/block_verification/block_processing_outcome.rs b/beacon_node/beacon_chain/src/block_verification/block_processing_outcome.rs new file mode 100644 index 000000000..cdfa35cab --- /dev/null +++ b/beacon_node/beacon_chain/src/block_verification/block_processing_outcome.rs @@ -0,0 +1,105 @@ +use crate::{BeaconChainError, BlockError}; +use state_processing::BlockProcessingError; +use types::{Hash256, Slot}; + +/// This is a legacy object that is being kept around to reduce merge conflicts. +/// +/// As soon as this is merged into master, it should be removed as soon as possible. +#[derive(Debug, PartialEq)] +pub enum BlockProcessingOutcome { + /// Block was valid and imported into the block graph. + Processed { + block_root: Hash256, + }, + InvalidSignature, + /// The proposal signature in invalid. + ProposalSignatureInvalid, + /// The parent block was unknown. + ParentUnknown(Hash256), + /// The block slot is greater than the present slot. + FutureSlot { + present_slot: Slot, + block_slot: Slot, + }, + /// The block state_root does not match the generated state. + StateRootMismatch { + block: Hash256, + local: Hash256, + }, + /// The block was a genesis block, these blocks cannot be re-imported. + GenesisBlock, + /// The slot is finalized, no need to import. + WouldRevertFinalizedSlot { + block_slot: Slot, + finalized_slot: Slot, + }, + /// Block is already known, no need to re-import. + BlockIsAlreadyKnown, + /// The block slot exceeds the MAXIMUM_BLOCK_SLOT_NUMBER. + BlockSlotLimitReached, + /// The provided block is from an earlier slot than its parent. + BlockIsNotLaterThanParent { + block_slot: Slot, + state_slot: Slot, + }, + /// At least one block in the chain segement did not have it's parent root set to the root of + /// the prior block. + NonLinearParentRoots, + /// The slots of the blocks in the chain segment were not strictly increasing. I.e., a child + /// had lower slot than a parent. + NonLinearSlots, + /// The block could not be applied to the state, it is invalid. + PerBlockProcessingError(BlockProcessingError), +} + +impl BlockProcessingOutcome { + pub fn shim( + result: Result, + ) -> Result { + match result { + Ok(block_root) => Ok(BlockProcessingOutcome::Processed { block_root }), + Err(BlockError::ParentUnknown(root)) => Ok(BlockProcessingOutcome::ParentUnknown(root)), + Err(BlockError::FutureSlot { + present_slot, + block_slot, + }) => Ok(BlockProcessingOutcome::FutureSlot { + present_slot, + block_slot, + }), + Err(BlockError::StateRootMismatch { block, local }) => { + Ok(BlockProcessingOutcome::StateRootMismatch { block, local }) + } + Err(BlockError::GenesisBlock) => Ok(BlockProcessingOutcome::GenesisBlock), + Err(BlockError::WouldRevertFinalizedSlot { + block_slot, + finalized_slot, + }) => Ok(BlockProcessingOutcome::WouldRevertFinalizedSlot { + block_slot, + finalized_slot, + }), + Err(BlockError::BlockIsAlreadyKnown) => Ok(BlockProcessingOutcome::BlockIsAlreadyKnown), + Err(BlockError::BlockSlotLimitReached) => { + Ok(BlockProcessingOutcome::BlockSlotLimitReached) + } + Err(BlockError::ProposalSignatureInvalid) => { + Ok(BlockProcessingOutcome::ProposalSignatureInvalid) + } + Err(BlockError::InvalidSignature) => Ok(BlockProcessingOutcome::InvalidSignature), + Err(BlockError::BlockIsNotLaterThanParent { + block_slot, + state_slot, + }) => Ok(BlockProcessingOutcome::BlockIsNotLaterThanParent { + block_slot, + state_slot, + }), + Err(BlockError::NonLinearParentRoots) => { + Ok(BlockProcessingOutcome::NonLinearParentRoots) + } + Err(BlockError::NonLinearSlots) => Ok(BlockProcessingOutcome::NonLinearSlots), + Err(BlockError::PerBlockProcessingError(e)) => { + Ok(BlockProcessingOutcome::PerBlockProcessingError(e)) + } + Err(BlockError::BeaconChainError(e)) => Err(e), + } + } +} diff --git a/beacon_node/beacon_chain/src/builder.rs b/beacon_node/beacon_chain/src/builder.rs index 9067965f7..72a61f542 100644 --- a/beacon_node/beacon_chain/src/builder.rs +++ b/beacon_node/beacon_chain/src/builder.rs @@ -7,10 +7,11 @@ use crate::fork_choice::SszForkChoice; use crate::head_tracker::HeadTracker; use crate::persisted_beacon_chain::PersistedBeaconChain; use crate::shuffling_cache::ShufflingCache; +use crate::snapshot_cache::{SnapshotCache, DEFAULT_SNAPSHOT_CACHE_SIZE}; use crate::timeout_rw_lock::TimeoutRwLock; use crate::validator_pubkey_cache::ValidatorPubkeyCache; use crate::{ - BeaconChain, BeaconChainTypes, CheckPoint, Eth1Chain, Eth1ChainBackend, EventHandler, + BeaconChain, BeaconChainTypes, BeaconSnapshot, Eth1Chain, Eth1ChainBackend, EventHandler, ForkChoice, }; use eth1::Config as Eth1Config; @@ -71,10 +72,10 @@ where pub struct BeaconChainBuilder { store: Option>, store_migrator: Option, - canonical_head: Option>, + canonical_head: Option>, /// The finalized checkpoint to anchor the chain. May be genesis or a higher /// checkpoint. - pub finalized_checkpoint: Option>, + pub finalized_snapshot: Option>, genesis_block_root: Option, op_pool: Option>, fork_choice: Option>, @@ -110,7 +111,7 @@ where store: None, store_migrator: None, canonical_head: None, - finalized_checkpoint: None, + finalized_snapshot: None, genesis_block_root: None, op_pool: None, fork_choice: None, @@ -247,14 +248,14 @@ where .map_err(|e| format!("DB error when reading finalized state: {:?}", e))? .ok_or_else(|| "Finalized state not found in store".to_string())?; - self.finalized_checkpoint = Some(CheckPoint { + self.finalized_snapshot = Some(BeaconSnapshot { beacon_block_root: finalized_block_root, beacon_block: finalized_block, beacon_state_root: finalized_state_root, beacon_state: finalized_state, }); - self.canonical_head = Some(CheckPoint { + self.canonical_head = Some(BeaconSnapshot { beacon_block_root: head_block_root, beacon_block: head_block, beacon_state_root: head_state_root, @@ -291,7 +292,7 @@ where self.genesis_block_root = Some(beacon_block_root); store - .put_state(&beacon_state_root, beacon_state.clone()) + .put_state(&beacon_state_root, &beacon_state) .map_err(|e| format!("Failed to store genesis state: {:?}", e))?; store .put(&beacon_block_root, &beacon_block) @@ -305,7 +306,7 @@ where ) })?; - self.finalized_checkpoint = Some(CheckPoint { + self.finalized_snapshot = Some(BeaconSnapshot { beacon_block_root, beacon_block, beacon_state_root, @@ -367,7 +368,7 @@ where let mut canonical_head = if let Some(head) = self.canonical_head { head } else { - self.finalized_checkpoint + self.finalized_snapshot .ok_or_else(|| "Cannot build without a state".to_string())? }; @@ -407,7 +408,7 @@ where .op_pool .ok_or_else(|| "Cannot build without op pool".to_string())?, eth1_chain: self.eth1_chain, - canonical_head: TimeoutRwLock::new(canonical_head), + canonical_head: TimeoutRwLock::new(canonical_head.clone()), genesis_block_root: self .genesis_block_root .ok_or_else(|| "Cannot build without a genesis block root".to_string())?, @@ -418,6 +419,10 @@ where .event_handler .ok_or_else(|| "Cannot build without an event handler".to_string())?, head_tracker: self.head_tracker.unwrap_or_default(), + snapshot_cache: TimeoutRwLock::new(SnapshotCache::new( + DEFAULT_SNAPSHOT_CACHE_SIZE, + canonical_head, + )), shuffling_cache: TimeoutRwLock::new(ShufflingCache::new()), validator_pubkey_cache: TimeoutRwLock::new(validator_pubkey_cache), log: log.clone(), @@ -469,30 +474,30 @@ where ForkChoice::from_ssz_container(persisted) .map_err(|e| format!("Unable to read persisted fork choice from disk: {:?}", e))? } else { - let finalized_checkpoint = &self - .finalized_checkpoint + let finalized_snapshot = &self + .finalized_snapshot .as_ref() - .ok_or_else(|| "fork_choice_backend requires a finalized_checkpoint")?; + .ok_or_else(|| "fork_choice_backend requires a finalized_snapshot")?; let genesis_block_root = self .genesis_block_root .ok_or_else(|| "fork_choice_backend requires a genesis_block_root")?; let backend = ProtoArrayForkChoice::new( - finalized_checkpoint.beacon_block.message.slot, - finalized_checkpoint.beacon_block.message.state_root, + finalized_snapshot.beacon_block.message.slot, + finalized_snapshot.beacon_block.message.state_root, // Note: here we set the `justified_epoch` to be the same as the epoch of the // finalized checkpoint. Whilst this finalized checkpoint may actually point to // a _later_ justified checkpoint, that checkpoint won't yet exist in the fork // choice. - finalized_checkpoint.beacon_state.current_epoch(), - finalized_checkpoint.beacon_state.current_epoch(), - finalized_checkpoint.beacon_block_root, + finalized_snapshot.beacon_state.current_epoch(), + finalized_snapshot.beacon_state.current_epoch(), + finalized_snapshot.beacon_block_root, )?; ForkChoice::new( backend, genesis_block_root, - &finalized_checkpoint.beacon_state, + &finalized_snapshot.beacon_state, ) }; @@ -563,7 +568,7 @@ where /// Requires the state to be initialized. pub fn testing_slot_clock(self, slot_duration: Duration) -> Result { let genesis_time = self - .finalized_checkpoint + .finalized_snapshot .as_ref() .ok_or_else(|| "testing_slot_clock requires an initialized state")? .beacon_state @@ -642,7 +647,7 @@ mod test { #[test] fn recent_genesis() { - let validator_count = 8; + let validator_count = 1; let genesis_time = 13_371_337; let log = get_logger(); diff --git a/beacon_node/beacon_chain/src/errors.rs b/beacon_node/beacon_chain/src/errors.rs index 1470d7c2a..2a3ca5f32 100644 --- a/beacon_node/beacon_chain/src/errors.rs +++ b/beacon_node/beacon_chain/src/errors.rs @@ -3,9 +3,11 @@ use crate::fork_choice::Error as ForkChoiceError; use operation_pool::OpPoolError; use ssz::DecodeError; use ssz_types::Error as SszTypesError; -use state_processing::per_block_processing::errors::AttestationValidationError; -use state_processing::BlockProcessingError; -use state_processing::SlotProcessingError; +use state_processing::{ + block_signature_verifier::Error as BlockSignatureVerifierError, + per_block_processing::errors::AttestationValidationError, + signature_sets::Error as SignatureSetError, BlockProcessingError, SlotProcessingError, +}; use std::time::Duration; use types::*; @@ -57,13 +59,18 @@ pub enum BeaconChainError { IncorrectStateForAttestation(RelativeEpochError), InvalidValidatorPubkeyBytes(DecodeError), ValidatorPubkeyCacheIncomplete(usize), - SignatureSetError(state_processing::signature_sets::Error), + SignatureSetError(SignatureSetError), + BlockSignatureVerifierError(state_processing::block_signature_verifier::Error), + DuplicateValidatorPublicKey, ValidatorPubkeyCacheFileError(String), + OpPoolError(OpPoolError), } easy_from_to!(SlotProcessingError, BeaconChainError); easy_from_to!(AttestationValidationError, BeaconChainError); easy_from_to!(SszTypesError, BeaconChainError); +easy_from_to!(OpPoolError, BeaconChainError); +easy_from_to!(BlockSignatureVerifierError, BeaconChainError); #[derive(Debug, PartialEq)] pub enum BlockProductionError { @@ -84,3 +91,27 @@ easy_from_to!(BlockProcessingError, BlockProductionError); easy_from_to!(BeaconStateError, BlockProductionError); easy_from_to!(SlotProcessingError, BlockProductionError); easy_from_to!(Eth1ChainError, BlockProductionError); + +/// A reason for not propagating an attestation (single or aggregate). +#[derive(Debug, PartialEq)] +pub enum AttestationDropReason { + SlotClockError, + TooNew { attestation_slot: Slot, now: Slot }, + TooOld { attestation_slot: Slot, now: Slot }, + NoValidationState(BeaconChainError), + BlockUnknown(Hash256), + BadIndexedAttestation(AttestationValidationError), + AggregatorNotInAttestingIndices, + AggregatorNotSelected, + AggregatorSignatureInvalid, + SignatureInvalid, +} + +/// A reason for not propagating a block. +#[derive(Debug, PartialEq)] +pub enum BlockDropReason { + SlotClockError, + TooNew { block_slot: Slot, now: Slot }, + // FIXME(sproul): add detail here + ValidationFailure, +} diff --git a/beacon_node/beacon_chain/src/eth1_chain.rs b/beacon_node/beacon_chain/src/eth1_chain.rs index 148e15630..663801532 100644 --- a/beacon_node/beacon_chain/src/eth1_chain.rs +++ b/beacon_node/beacon_chain/src/eth1_chain.rs @@ -1,7 +1,6 @@ use crate::metrics; use eth1::{Config as Eth1Config, Eth1Block, Service as HttpService}; use eth2_hashing::hash; -use exit_future::Exit; use futures::Future; use slog::{debug, error, trace, Logger}; use ssz::{Decode, Encode}; @@ -279,7 +278,10 @@ impl> CachingEth1Backend { } /// Starts the routine which connects to the external eth1 node and updates the caches. - pub fn start(&self, exit: Exit) -> impl Future { + pub fn start( + &self, + exit: tokio::sync::oneshot::Receiver<()>, + ) -> impl Future { self.core.auto_update(exit) } diff --git a/beacon_node/beacon_chain/src/fork_choice/checkpoint_manager.rs b/beacon_node/beacon_chain/src/fork_choice/checkpoint_manager.rs index fd4512ce3..d93ddeb0f 100644 --- a/beacon_node/beacon_chain/src/fork_choice/checkpoint_manager.rs +++ b/beacon_node/beacon_chain/src/fork_choice/checkpoint_manager.rs @@ -306,10 +306,7 @@ impl CheckpointManager { .ok_or_else(|| Error::UnknownJustifiedBlock(block_root))?; let state = chain - .get_state_caching_only_with_committee_caches( - &block.state_root(), - Some(block.slot()), - )? + .get_state(&block.state_root(), Some(block.slot()))? .ok_or_else(|| Error::UnknownJustifiedState(block.state_root()))?; Ok(get_effective_balances(&state)) diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index cc4a9b8f5..4ba36418a 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -3,8 +3,9 @@ extern crate lazy_static; mod beacon_chain; +mod beacon_snapshot; +mod block_verification; pub mod builder; -mod checkpoint; mod errors; pub mod eth1_chain; pub mod events; @@ -13,16 +14,17 @@ mod head_tracker; mod metrics; mod persisted_beacon_chain; mod shuffling_cache; +mod snapshot_cache; pub mod test_utils; mod timeout_rw_lock; mod validator_pubkey_cache; pub use self::beacon_chain::{ - AttestationProcessingOutcome, BeaconChain, BeaconChainTypes, BlockProcessingOutcome, - StateSkipConfig, + AttestationProcessingOutcome, BeaconChain, BeaconChainTypes, StateSkipConfig, }; -pub use self::checkpoint::CheckPoint; +pub use self::beacon_snapshot::BeaconSnapshot; pub use self::errors::{BeaconChainError, BlockProductionError}; +pub use block_verification::{BlockError, BlockProcessingOutcome}; pub use eth1_chain::{Eth1Chain, Eth1ChainBackend}; pub use events::EventHandler; pub use fork_choice::ForkChoice; diff --git a/beacon_node/beacon_chain/src/metrics.rs b/beacon_node/beacon_chain/src/metrics.rs index aee111f47..39cd234fb 100644 --- a/beacon_node/beacon_chain/src/metrics.rs +++ b/beacon_node/beacon_chain/src/metrics.rs @@ -32,6 +32,10 @@ lazy_static! { "beacon_block_processing_committee_building_seconds", "Time spent building/obtaining committees for block processing." ); + pub static ref BLOCK_PROCESSING_SIGNATURE: Result = try_create_histogram( + "beacon_block_processing_signature_seconds", + "Time spent doing signature verification for a block." + ); pub static ref BLOCK_PROCESSING_CORE: Result = try_create_histogram( "beacon_block_processing_core_seconds", "Time spent doing the core per_block_processing state processing." diff --git a/beacon_node/beacon_chain/src/snapshot_cache.rs b/beacon_node/beacon_chain/src/snapshot_cache.rs new file mode 100644 index 000000000..fffe715f9 --- /dev/null +++ b/beacon_node/beacon_chain/src/snapshot_cache.rs @@ -0,0 +1,217 @@ +use crate::BeaconSnapshot; +use std::cmp; +use types::{Epoch, EthSpec, Hash256}; + +/// The default size of the cache. +pub const DEFAULT_SNAPSHOT_CACHE_SIZE: usize = 4; + +/// Provides a cache of `BeaconSnapshot` that is intended primarily for block processing. +/// +/// ## Cache Queuing +/// +/// The cache has a non-standard queue mechanism (specifically, it is not LRU). +/// +/// The cache has a max number of elements (`max_len`). Until `max_len` is achieved, all snapshots +/// are simply added to the queue. Once `max_len` is achieved, adding a new snapshot will cause an +/// existing snapshot to be ejected. The ejected snapshot will: +/// +/// - Never be the `head_block_root`. +/// - Be the snapshot with the lowest `state.slot` (ties broken arbitrarily). +pub struct SnapshotCache { + max_len: usize, + head_block_root: Hash256, + snapshots: Vec>, +} + +impl SnapshotCache { + /// Instantiate a new cache which contains the `head` snapshot. + /// + /// Setting `max_len = 0` is equivalent to setting `max_len = 1`. + pub fn new(max_len: usize, head: BeaconSnapshot) -> Self { + Self { + max_len: cmp::max(max_len, 1), + head_block_root: head.beacon_block_root, + snapshots: vec![head], + } + } + + /// Insert a snapshot, potentially removing an existing snapshot if `self` is at capacity (see + /// struct-level documentation for more info). + pub fn insert(&mut self, snapshot: BeaconSnapshot) { + if self.snapshots.len() < self.max_len { + self.snapshots.push(snapshot); + } else { + let insert_at = self + .snapshots + .iter() + .enumerate() + .filter_map(|(i, snapshot)| { + if snapshot.beacon_block_root != self.head_block_root { + Some((i, snapshot.beacon_state.slot)) + } else { + None + } + }) + .min_by_key(|(_i, slot)| *slot) + .map(|(i, _slot)| i); + + if let Some(i) = insert_at { + self.snapshots[i] = snapshot; + } + } + } + + /// If there is a snapshot with `block_root`, remove and return it. + pub fn try_remove(&mut self, block_root: Hash256) -> Option> { + self.snapshots + .iter() + .position(|snapshot| snapshot.beacon_block_root == block_root) + .map(|i| self.snapshots.remove(i)) + } + + /// If there is a snapshot with `block_root`, clone it (with only the committee caches) and + /// return the clone. + pub fn get_cloned(&self, block_root: Hash256) -> Option> { + self.snapshots + .iter() + .find(|snapshot| snapshot.beacon_block_root == block_root) + .map(|snapshot| snapshot.clone_with_only_committee_caches()) + } + + /// Removes all snapshots from the queue that are less than or equal to the finalized epoch. + pub fn prune(&mut self, finalized_epoch: Epoch) { + self.snapshots.retain(|snapshot| { + snapshot.beacon_state.slot > finalized_epoch.start_slot(T::slots_per_epoch()) + }) + } + + /// Inform the cache that the head of the beacon chain has changed. + /// + /// The snapshot that matches this `head_block_root` will never be ejected from the cache + /// during `Self::insert`. + pub fn update_head(&mut self, head_block_root: Hash256) { + self.head_block_root = head_block_root + } +} + +#[cfg(test)] +mod test { + use super::*; + use types::{ + test_utils::{generate_deterministic_keypair, TestingBeaconStateBuilder}, + BeaconBlock, Epoch, MainnetEthSpec, Signature, SignedBeaconBlock, Slot, + }; + + const CACHE_SIZE: usize = 4; + + fn get_snapshot(i: u64) -> BeaconSnapshot { + let spec = MainnetEthSpec::default_spec(); + + let state_builder = TestingBeaconStateBuilder::from_deterministic_keypairs(1, &spec); + let (beacon_state, _keypairs) = state_builder.build(); + + BeaconSnapshot { + beacon_state, + beacon_state_root: Hash256::from_low_u64_be(i), + beacon_block: SignedBeaconBlock { + message: BeaconBlock::empty(&spec), + signature: Signature::new(&[42], &generate_deterministic_keypair(0).sk), + }, + beacon_block_root: Hash256::from_low_u64_be(i), + } + } + + #[test] + fn insert_get_prune_update() { + let mut cache = SnapshotCache::new(CACHE_SIZE, get_snapshot(0)); + + // Insert a bunch of entries in the cache. It should look like this: + // + // Index Root + // 0 0 <--head + // 1 1 + // 2 2 + // 3 3 + for i in 1..CACHE_SIZE as u64 { + let mut snapshot = get_snapshot(i); + + // Each snapshot should be one slot into an epoch, with each snapshot one epoch apart. + snapshot.beacon_state.slot = Slot::from(i * MainnetEthSpec::slots_per_epoch() + 1); + + cache.insert(snapshot); + + assert_eq!( + cache.snapshots.len(), + i as usize + 1, + "cache length should be as expected" + ); + assert_eq!(cache.head_block_root, Hash256::from_low_u64_be(0)); + } + + // Insert a new value in the cache. Afterwards it should look like: + // + // Index Root + // 0 0 <--head + // 1 42 + // 2 2 + // 3 3 + assert_eq!(cache.snapshots.len(), CACHE_SIZE); + cache.insert(get_snapshot(42)); + assert_eq!(cache.snapshots.len(), CACHE_SIZE); + + assert!( + cache.try_remove(Hash256::from_low_u64_be(1)).is_none(), + "the snapshot with the lowest slot should have been removed during the insert function" + ); + assert!(cache.get_cloned(Hash256::from_low_u64_be(1)).is_none()); + + assert!( + cache + .get_cloned(Hash256::from_low_u64_be(0)) + .expect("the head should still be in the cache") + .beacon_block_root + == Hash256::from_low_u64_be(0), + "get_cloned should get the correct snapshot" + ); + assert!( + cache + .try_remove(Hash256::from_low_u64_be(0)) + .expect("the head should still be in the cache") + .beacon_block_root + == Hash256::from_low_u64_be(0), + "try_remove should get the correct snapshot" + ); + + assert_eq!( + cache.snapshots.len(), + CACHE_SIZE - 1, + "try_remove should shorten the cache" + ); + + // Prune the cache. Afterwards it should look like: + // + // Index Root + // 0 2 + // 1 3 + cache.prune(Epoch::new(2)); + + assert_eq!(cache.snapshots.len(), 2); + + cache.update_head(Hash256::from_low_u64_be(2)); + + // Over-fill the cache so it needs to eject some old values on insert. + for i in 0..CACHE_SIZE as u64 { + cache.insert(get_snapshot(u64::max_value() - i)); + } + + // Ensure that the new head value was not removed from the cache. + assert!( + cache + .try_remove(Hash256::from_low_u64_be(2)) + .expect("the new head should still be in the cache") + .beacon_block_root + == Hash256::from_low_u64_be(2), + "try_remove should get the correct snapshot" + ); + } +} diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index 0edd26ce3..837cd0f0b 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -6,8 +6,7 @@ use crate::{ builder::{BeaconChainBuilder, Witness}, eth1_chain::CachingEth1Backend, events::NullEventHandler, - AttestationProcessingOutcome, BeaconChain, BeaconChainTypes, BlockProcessingOutcome, - StateSkipConfig, + AttestationProcessingOutcome, BeaconChain, BeaconChainTypes, StateSkipConfig, }; use genesis::interop_genesis_state; use rayon::prelude::*; @@ -256,20 +255,15 @@ where let (block, new_state) = self.build_block(state.clone(), slot, block_strategy); - let outcome = self + let block_root = self .chain .process_block(block) .expect("should not error during block processing"); self.chain.fork_choice().expect("should find head"); - if let BlockProcessingOutcome::Processed { block_root } = outcome { - head_block_root = Some(block_root); - - self.add_free_attestations(&attestation_strategy, &new_state, block_root, slot); - } else { - panic!("block should be successfully processed: {:?}", outcome); - } + head_block_root = Some(block_root); + self.add_free_attestations(&attestation_strategy, &new_state, block_root, slot); state = new_state; slot += 1; @@ -348,7 +342,7 @@ where .for_each(|attestation| { match self .chain - .process_attestation(attestation) + .process_attestation(attestation, Some(false)) .expect("should not error during attestation processing") { AttestationProcessingOutcome::Processed => (), diff --git a/beacon_node/beacon_chain/src/validator_pubkey_cache.rs b/beacon_node/beacon_chain/src/validator_pubkey_cache.rs index c62177921..732f4085f 100644 --- a/beacon_node/beacon_chain/src/validator_pubkey_cache.rs +++ b/beacon_node/beacon_chain/src/validator_pubkey_cache.rs @@ -1,10 +1,11 @@ use crate::errors::BeaconChainError; use ssz::{Decode, DecodeError, Encode}; +use std::collections::HashMap; use std::convert::TryInto; use std::fs::{File, OpenOptions}; use std::io::{self, Read, Write}; use std::path::Path; -use types::{BeaconState, EthSpec, PublicKey, PublicKeyBytes}; +use types::{BeaconState, EthSpec, PublicKey, PublicKeyBytes, Validator}; /// Provides a mapping of `validator_index -> validator_publickey`. /// @@ -19,6 +20,7 @@ use types::{BeaconState, EthSpec, PublicKey, PublicKeyBytes}; /// copy of itself. This allows it to be restored between process invocations. pub struct ValidatorPubkeyCache { pubkeys: Vec, + indices: HashMap, persitence_file: ValidatorPubkeyCacheFile, } @@ -47,6 +49,7 @@ impl ValidatorPubkeyCache { let mut cache = Self { persitence_file: ValidatorPubkeyCacheFile::create(persistence_path)?, pubkeys: vec![], + indices: HashMap::new(), }; cache.import_new_pubkeys(state)?; @@ -61,38 +64,57 @@ impl ValidatorPubkeyCache { &mut self, state: &BeaconState, ) -> Result<(), BeaconChainError> { - state - .validators - .iter() - .skip(self.pubkeys.len()) - .try_for_each(|v| { - let i = self.pubkeys.len(); + if state.validators.len() > self.pubkeys.len() { + self.import(&state.validators[self.pubkeys.len()..]) + } else { + Ok(()) + } + } - // The item is written to disk (the persistence file) _before_ it is written into - // the local struct. - // - // This means that a pubkey cache read from disk will always be equivalent to or - // _later than_ the cache that was running in the previous instance of Lighthouse. - // - // The motivation behind this ordering is that we do not want to have states that - // reference a pubkey that is not in our cache. However, it's fine to have pubkeys - // that are never referenced in a state. - self.persitence_file.append(i, &v.pubkey)?; + /// Adds zero or more validators to `self`. + fn import(&mut self, validators: &[Validator]) -> Result<(), BeaconChainError> { + self.pubkeys.reserve(validators.len()); + self.indices.reserve(validators.len()); - self.pubkeys.push( - (&v.pubkey) - .try_into() - .map_err(BeaconChainError::InvalidValidatorPubkeyBytes)?, - ); + for v in validators.iter() { + let i = self.pubkeys.len(); - Ok(()) - }) + if self.indices.contains_key(&v.pubkey) { + return Err(BeaconChainError::DuplicateValidatorPublicKey); + } + + // The item is written to disk (the persistence file) _before_ it is written into + // the local struct. + // + // This means that a pubkey cache read from disk will always be equivalent to or + // _later than_ the cache that was running in the previous instance of Lighthouse. + // + // The motivation behind this ordering is that we do not want to have states that + // reference a pubkey that is not in our cache. However, it's fine to have pubkeys + // that are never referenced in a state. + self.persitence_file.append(i, &v.pubkey)?; + + self.pubkeys.push( + (&v.pubkey) + .try_into() + .map_err(BeaconChainError::InvalidValidatorPubkeyBytes)?, + ); + + self.indices.insert(v.pubkey.clone(), i); + } + + Ok(()) } /// Get the public key for a validator with index `i`. pub fn get(&self, i: usize) -> Option<&PublicKey> { self.pubkeys.get(i) } + + /// Get the index of a validator with `pubkey`. + pub fn get_index(&self, pubkey: &PublicKeyBytes) -> Option { + self.indices.get(pubkey).copied() + } } /// Allows for maintaining an on-disk copy of the `ValidatorPubkeyCache`. The file is raw SSZ bytes @@ -168,12 +190,14 @@ impl ValidatorPubkeyCacheFile { let mut last = None; let mut pubkeys = Vec::with_capacity(list.len()); + let mut indices = HashMap::new(); for (index, pubkey) in list { let expected = last.map(|n| n + 1); if expected.map_or(true, |expected| index == expected) { last = Some(index); pubkeys.push((&pubkey).try_into().map_err(Error::SszError)?); + indices.insert(pubkey, index); } else { return Err(Error::InconsistentIndex { expected, @@ -184,6 +208,7 @@ impl ValidatorPubkeyCacheFile { Ok(ValidatorPubkeyCache { pubkeys, + indices, persitence_file: self, }) } @@ -221,6 +246,16 @@ mod test { if i < validator_count { let pubkey = cache.get(i).expect("pubkey should be present"); assert_eq!(pubkey, &keypairs[i].pk, "pubkey should match cache"); + + let pubkey_bytes: PublicKeyBytes = pubkey.clone().into(); + + assert_eq!( + i, + cache + .get_index(&pubkey_bytes) + .expect("should resolve index"), + "index should match cache" + ); } else { assert_eq!( cache.get(i), diff --git a/beacon_node/beacon_chain/tests/import_chain_segment_tests.rs b/beacon_node/beacon_chain/tests/import_chain_segment_tests.rs new file mode 100644 index 000000000..f83822b47 --- /dev/null +++ b/beacon_node/beacon_chain/tests/import_chain_segment_tests.rs @@ -0,0 +1,572 @@ +#![cfg(not(debug_assertions))] + +#[macro_use] +extern crate lazy_static; + +use beacon_chain::{ + test_utils::{AttestationStrategy, BeaconChainHarness, BlockStrategy, HarnessType}, + BeaconSnapshot, BlockError, +}; +use types::{ + test_utils::generate_deterministic_keypair, AggregateSignature, AttestationData, + AttesterSlashing, Checkpoint, Deposit, DepositData, Epoch, EthSpec, Hash256, + IndexedAttestation, Keypair, MainnetEthSpec, ProposerSlashing, Signature, SignedBeaconBlock, + SignedBeaconBlockHeader, SignedVoluntaryExit, Slot, VoluntaryExit, DEPOSIT_TREE_DEPTH, +}; + +type E = MainnetEthSpec; + +// Should ideally be divisible by 3. +pub const VALIDATOR_COUNT: usize = 24; +pub const CHAIN_SEGMENT_LENGTH: usize = 64 * 5; + +lazy_static! { + /// A cached set of keys. + static ref KEYPAIRS: Vec = types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT); + + /// A cached set of valid blocks + static ref CHAIN_SEGMENT: Vec> = get_chain_segment(); +} + +fn get_chain_segment() -> Vec> { + let harness = get_harness(VALIDATOR_COUNT); + + harness.extend_chain( + CHAIN_SEGMENT_LENGTH, + BlockStrategy::OnCanonicalHead, + AttestationStrategy::AllValidators, + ); + + harness + .chain + .chain_dump() + .expect("should dump chain") + .into_iter() + .skip(1) + .collect() +} + +fn get_harness(validator_count: usize) -> BeaconChainHarness> { + let harness = BeaconChainHarness::new(MainnetEthSpec, KEYPAIRS[0..validator_count].to_vec()); + + harness.advance_slot(); + + harness +} + +fn chain_segment_blocks() -> Vec> { + CHAIN_SEGMENT + .iter() + .map(|snapshot| snapshot.beacon_block.clone()) + .collect() +} + +fn junk_signature() -> Signature { + let kp = generate_deterministic_keypair(VALIDATOR_COUNT); + let message = &[42, 42]; + Signature::new(message, &kp.sk) +} + +fn junk_aggregate_signature() -> AggregateSignature { + let mut agg_sig = AggregateSignature::new(); + agg_sig.add(&junk_signature()); + agg_sig +} + +fn update_proposal_signatures( + snapshots: &mut [BeaconSnapshot], + harness: &BeaconChainHarness>, +) { + for snapshot in snapshots { + let spec = &harness.chain.spec; + let slot = snapshot.beacon_block.slot(); + let state = &snapshot.beacon_state; + let proposer_index = state + .get_beacon_proposer_index(slot, spec) + .expect("should find proposer index"); + let keypair = harness + .keypairs + .get(proposer_index) + .expect("proposer keypair should be available"); + + snapshot.beacon_block = + snapshot + .beacon_block + .message + .clone() + .sign(&keypair.sk, &state.fork, spec); + } +} + +fn update_parent_roots(snapshots: &mut [BeaconSnapshot]) { + for i in 0..snapshots.len() { + let root = snapshots[i].beacon_block.canonical_root(); + if let Some(child) = snapshots.get_mut(i + 1) { + child.beacon_block.message.parent_root = root + } + } +} + +#[test] +fn chain_segment_full_segment() { + let harness = get_harness(VALIDATOR_COUNT); + let blocks = chain_segment_blocks(); + + harness + .chain + .slot_clock + .set_slot(blocks.last().unwrap().slot().as_u64()); + + // Sneak in a little check to ensure we can process empty chain segments. + harness + .chain + .process_chain_segment(vec![]) + .expect("should import empty chain segment"); + + harness + .chain + .process_chain_segment(blocks.clone()) + .expect("should import chain segment"); + + harness.chain.fork_choice().expect("should run fork choice"); + + assert_eq!( + harness + .chain + .head_info() + .expect("should get harness b head") + .block_root, + blocks.last().unwrap().canonical_root(), + "harness should have last block as head" + ); +} + +#[test] +fn chain_segment_varying_chunk_size() { + for chunk_size in &[1, 2, 3, 5, 31, 32, 33, 42] { + let harness = get_harness(VALIDATOR_COUNT); + let blocks = chain_segment_blocks(); + + harness + .chain + .slot_clock + .set_slot(blocks.last().unwrap().slot().as_u64()); + + for chunk in blocks.chunks(*chunk_size) { + harness + .chain + .process_chain_segment(chunk.to_vec()) + .expect(&format!( + "should import chain segment of len {}", + chunk_size + )); + } + + harness.chain.fork_choice().expect("should run fork choice"); + + assert_eq!( + harness + .chain + .head_info() + .expect("should get harness b head") + .block_root, + blocks.last().unwrap().canonical_root(), + "harness should have last block as head" + ); + } +} + +#[test] +fn chain_segment_non_linear_parent_roots() { + let harness = get_harness(VALIDATOR_COUNT); + harness + .chain + .slot_clock + .set_slot(CHAIN_SEGMENT.last().unwrap().beacon_block.slot().as_u64()); + + /* + * Test with a block removed. + */ + let mut blocks = chain_segment_blocks(); + blocks.remove(2); + + assert_eq!( + harness.chain.process_chain_segment(blocks.clone()), + Err(BlockError::NonLinearParentRoots), + "should not import chain with missing parent" + ); + + /* + * Test with a modified parent root. + */ + let mut blocks = chain_segment_blocks(); + blocks[3].message.parent_root = Hash256::zero(); + + assert_eq!( + harness.chain.process_chain_segment(blocks.clone()), + Err(BlockError::NonLinearParentRoots), + "should not import chain with a broken parent root link" + ); +} + +#[test] +fn chain_segment_non_linear_slots() { + let harness = get_harness(VALIDATOR_COUNT); + harness + .chain + .slot_clock + .set_slot(CHAIN_SEGMENT.last().unwrap().beacon_block.slot().as_u64()); + + /* + * Test where a child is lower than the parent. + */ + + let mut blocks = chain_segment_blocks(); + blocks[3].message.slot = Slot::new(0); + + assert_eq!( + harness.chain.process_chain_segment(blocks.clone()), + Err(BlockError::NonLinearSlots), + "should not import chain with a parent that has a lower slot than its child" + ); + + /* + * Test where a child is equal to the parent. + */ + + let mut blocks = chain_segment_blocks(); + blocks[3].message.slot = blocks[2].message.slot; + + assert_eq!( + harness.chain.process_chain_segment(blocks.clone()), + Err(BlockError::NonLinearSlots), + "should not import chain with a parent that has an equal slot to its child" + ); +} + +#[test] +fn invalid_signatures() { + let mut checked_attestation = false; + + for &block_index in &[0, 1, 32, 64, 68 + 1, 129, CHAIN_SEGMENT.len() - 1] { + let harness = get_harness(VALIDATOR_COUNT); + harness + .chain + .slot_clock + .set_slot(CHAIN_SEGMENT.last().unwrap().beacon_block.slot().as_u64()); + + // Import all the ancestors before the `block_index` block. + let ancestor_blocks = CHAIN_SEGMENT + .iter() + .take(block_index) + .map(|snapshot| snapshot.beacon_block.clone()) + .collect(); + harness + .chain + .process_chain_segment(ancestor_blocks) + .expect("should import all blocks prior to the one being tested"); + + // For the given snapshots, test the following: + // + // - The `process_chain_segment` function returns `InvalidSignature`. + // - The `process_block` function returns `InvalidSignature` when importing the + // `SignedBeaconBlock` directly. + // - The `verify_block_for_gossip` function does _not_ return an error. + // - The `process_block` function returns `InvalidSignature` when verifying the + // GossipVerifiedBlock. + let assert_invalid_signature = |snapshots: &[BeaconSnapshot], item: &str| { + let blocks = snapshots + .iter() + .map(|snapshot| snapshot.beacon_block.clone()) + .collect(); + + // Ensure the block will be rejected if imported in a chain segment. + assert_eq!( + harness.chain.process_chain_segment(blocks), + Err(BlockError::InvalidSignature), + "should not import chain segment with an invalid {} signature", + item + ); + + // Ensure the block will be rejected if imported on its own (without gossip checking). + assert_eq!( + harness + .chain + .process_block(snapshots[block_index].beacon_block.clone()), + Err(BlockError::InvalidSignature), + "should not import individual block with an invalid {} signature", + item + ); + + let gossip_verified = harness + .chain + .verify_block_for_gossip(snapshots[block_index].beacon_block.clone()) + .expect("should obtain gossip verified block"); + assert_eq!( + harness.chain.process_block(gossip_verified), + Err(BlockError::InvalidSignature), + "should not import gossip verified block with an invalid {} signature", + item + ); + }; + + /* + * Block proposal + */ + let mut snapshots = CHAIN_SEGMENT.clone(); + snapshots[block_index].beacon_block.signature = junk_signature(); + let blocks = snapshots + .iter() + .map(|snapshot| snapshot.beacon_block.clone()) + .collect(); + // Ensure the block will be rejected if imported in a chain segment. + assert_eq!( + harness.chain.process_chain_segment(blocks), + Err(BlockError::InvalidSignature), + "should not import chain segment with an invalid gossip signature", + ); + // Ensure the block will be rejected if imported on its own (without gossip checking). + assert_eq!( + harness + .chain + .process_block(snapshots[block_index].beacon_block.clone()), + Err(BlockError::InvalidSignature), + "should not import individual block with an invalid gossip signature", + ); + + /* + * Randao reveal + */ + let mut snapshots = CHAIN_SEGMENT.clone(); + snapshots[block_index] + .beacon_block + .message + .body + .randao_reveal = junk_signature(); + update_parent_roots(&mut snapshots); + update_proposal_signatures(&mut snapshots, &harness); + assert_invalid_signature(&snapshots, "randao"); + + /* + * Proposer slashing + */ + let mut snapshots = CHAIN_SEGMENT.clone(); + let proposer_slashing = ProposerSlashing { + proposer_index: 0, + signed_header_1: SignedBeaconBlockHeader { + message: snapshots[block_index].beacon_block.message.block_header(), + signature: junk_signature(), + }, + signed_header_2: SignedBeaconBlockHeader { + message: snapshots[block_index].beacon_block.message.block_header(), + signature: junk_signature(), + }, + }; + snapshots[block_index] + .beacon_block + .message + .body + .proposer_slashings + .push(proposer_slashing) + .expect("should update proposer slashing"); + update_parent_roots(&mut snapshots); + update_proposal_signatures(&mut snapshots, &harness); + assert_invalid_signature(&snapshots, "proposer slashing"); + + /* + * Attester slashing + */ + let mut snapshots = CHAIN_SEGMENT.clone(); + let indexed_attestation = IndexedAttestation { + attesting_indices: vec![0].into(), + data: AttestationData { + slot: Slot::new(0), + index: 0, + beacon_block_root: Hash256::zero(), + source: Checkpoint { + epoch: Epoch::new(0), + root: Hash256::zero(), + }, + target: Checkpoint { + epoch: Epoch::new(0), + root: Hash256::zero(), + }, + }, + signature: junk_aggregate_signature(), + }; + let attester_slashing = AttesterSlashing { + attestation_1: indexed_attestation.clone(), + attestation_2: indexed_attestation, + }; + snapshots[block_index] + .beacon_block + .message + .body + .attester_slashings + .push(attester_slashing) + .expect("should update attester slashing"); + update_parent_roots(&mut snapshots); + update_proposal_signatures(&mut snapshots, &harness); + assert_invalid_signature(&snapshots, "attester slashing"); + + /* + * Attestation + */ + let mut snapshots = CHAIN_SEGMENT.clone(); + if let Some(attestation) = snapshots[block_index] + .beacon_block + .message + .body + .attestations + .get_mut(0) + { + attestation.signature = junk_aggregate_signature(); + update_parent_roots(&mut snapshots); + update_proposal_signatures(&mut snapshots, &harness); + assert_invalid_signature(&snapshots, "attestation"); + checked_attestation = true; + } + + /* + * Deposit + * + * Note: an invalid deposit signature is permitted! + */ + let mut snapshots = CHAIN_SEGMENT.clone(); + let deposit = Deposit { + proof: vec![Hash256::zero(); DEPOSIT_TREE_DEPTH + 1].into(), + data: DepositData { + pubkey: Keypair::random().pk.into(), + withdrawal_credentials: Hash256::zero(), + amount: 0, + signature: junk_signature().into(), + }, + }; + snapshots[block_index] + .beacon_block + .message + .body + .deposits + .push(deposit) + .expect("should update deposit"); + update_parent_roots(&mut snapshots); + update_proposal_signatures(&mut snapshots, &harness); + let blocks = snapshots + .iter() + .map(|snapshot| snapshot.beacon_block.clone()) + .collect(); + assert!( + harness.chain.process_chain_segment(blocks) != Err(BlockError::InvalidSignature), + "should not throw an invalid signature error for a bad deposit signature" + ); + + /* + * Voluntary exit + */ + let mut snapshots = CHAIN_SEGMENT.clone(); + let epoch = snapshots[block_index].beacon_state.current_epoch(); + snapshots[block_index] + .beacon_block + .message + .body + .voluntary_exits + .push(SignedVoluntaryExit { + message: VoluntaryExit { + epoch, + validator_index: 0, + }, + signature: junk_signature(), + }) + .expect("should update deposit"); + update_parent_roots(&mut snapshots); + update_proposal_signatures(&mut snapshots, &harness); + assert_invalid_signature(&snapshots, "voluntary exit"); + } + + assert!( + checked_attestation, + "the test should check an attestation signature" + ) +} + +fn unwrap_err(result: Result) -> E { + match result { + Ok(_) => panic!("called unwrap_err on Ok"), + Err(e) => e, + } +} + +#[test] +fn gossip_verification() { + let harness = get_harness(VALIDATOR_COUNT); + + let block_index = CHAIN_SEGMENT_LENGTH - 2; + + harness + .chain + .slot_clock + .set_slot(CHAIN_SEGMENT[block_index].beacon_block.slot().as_u64()); + + // Import the ancestors prior to the block we're testing. + for snapshot in &CHAIN_SEGMENT[0..block_index] { + let gossip_verified = harness + .chain + .verify_block_for_gossip(snapshot.beacon_block.clone()) + .expect("should obtain gossip verified block"); + + harness + .chain + .process_block(gossip_verified) + .expect("should import valid gossip verfied block"); + } + + /* + * Block with invalid signature + */ + + let mut block = CHAIN_SEGMENT[block_index].beacon_block.clone(); + block.signature = junk_signature(); + assert_eq!( + unwrap_err(harness.chain.verify_block_for_gossip(block)), + BlockError::ProposalSignatureInvalid, + "should not import a block with an invalid proposal signature" + ); + + /* + * Block from a future slot. + */ + + let mut block = CHAIN_SEGMENT[block_index].beacon_block.clone(); + let block_slot = block.message.slot + 1; + block.message.slot = block_slot; + assert_eq!( + unwrap_err(harness.chain.verify_block_for_gossip(block)), + BlockError::FutureSlot { + present_slot: block_slot - 1, + block_slot + }, + "should not import a block with a future slot" + ); + + /* + * Block from a finalized slot. + */ + + let mut block = CHAIN_SEGMENT[block_index].beacon_block.clone(); + let finalized_slot = harness + .chain + .head_info() + .expect("should get head info") + .finalized_checkpoint + .epoch + .start_slot(E::slots_per_epoch()); + block.message.slot = finalized_slot; + assert_eq!( + unwrap_err(harness.chain.verify_block_for_gossip(block)), + BlockError::WouldRevertFinalizedSlot { + block_slot: finalized_slot, + finalized_slot + }, + "should not import a block with a finalized slot" + ); +} diff --git a/beacon_node/beacon_chain/tests/tests.rs b/beacon_node/beacon_chain/tests/tests.rs index 6d4c5244f..999b25464 100644 --- a/beacon_node/beacon_chain/tests/tests.rs +++ b/beacon_node/beacon_chain/tests/tests.rs @@ -3,13 +3,10 @@ #[macro_use] extern crate lazy_static; -use beacon_chain::AttestationProcessingOutcome; -use beacon_chain::{ - test_utils::{ - AttestationStrategy, BeaconChainHarness, BlockStrategy, HarnessType, OP_POOL_DB_KEY, - }, - BlockProcessingOutcome, +use beacon_chain::test_utils::{ + AttestationStrategy, BeaconChainHarness, BlockStrategy, HarnessType, OP_POOL_DB_KEY, }; +use beacon_chain::AttestationProcessingOutcome; use operation_pool::PersistedOperationPool; use state_processing::{ per_slot_processing, per_slot_processing::Error as SlotProcessingError, EpochProcessingError, @@ -562,15 +559,13 @@ fn run_skip_slot_test(skip_slots: u64) { .head() .expect("should get head") .beacon_block - .clone() + .clone(), ), - Ok(BlockProcessingOutcome::Processed { - block_root: harness_a - .chain - .head() - .expect("should get head") - .beacon_block_root - }) + Ok(harness_a + .chain + .head() + .expect("should get head") + .beacon_block_root) ); harness_b diff --git a/beacon_node/client/Cargo.toml b/beacon_node/client/Cargo.toml index 8feed866e..04c4edfda 100644 --- a/beacon_node/client/Cargo.toml +++ b/beacon_node/client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "client" -version = "0.1.0" +version = "0.2.0" authors = ["Age Manning "] edition = "2018" @@ -12,6 +12,7 @@ toml = "^0.5" beacon_chain = { path = "../beacon_chain" } store = { path = "../store" } network = { path = "../network" } +timer = { path = "../timer" } eth2-libp2p = { path = "../eth2-libp2p" } rest_api = { path = "../rest_api" } parking_lot = "0.9.0" @@ -29,7 +30,6 @@ slog = { version = "2.5.2", features = ["max_level_trace"] } slog-async = "2.3.0" tokio = "0.1.22" dirs = "2.0.2" -exit-future = "0.1.4" futures = "0.1.29" reqwest = "0.9.22" url = "2.1.0" @@ -38,3 +38,5 @@ genesis = { path = "../genesis" } environment = { path = "../../lighthouse/environment" } lighthouse_bootstrap = { path = "../../eth2/utils/lighthouse_bootstrap" } eth2_ssz = { path = "../../eth2/utils/ssz" } +lazy_static = "1.4.0" +lighthouse_metrics = { path = "../../eth2/utils/lighthouse_metrics" } diff --git a/beacon_node/client/src/builder.rs b/beacon_node/client/src/builder.rs index 42080663b..7e0f76519 100644 --- a/beacon_node/client/src/builder.rs +++ b/beacon_node/client/src/builder.rs @@ -14,13 +14,13 @@ use beacon_chain::{ use environment::RuntimeContext; use eth1::{Config as Eth1Config, Service as Eth1Service}; use eth2_config::Eth2Config; -use exit_future::Signal; +use eth2_libp2p::NetworkGlobals; use futures::{future, Future, IntoFuture}; use genesis::{ generate_deterministic_keypairs, interop_genesis_state, state_from_ssz_file, Eth1GenesisService, }; use lighthouse_bootstrap::Bootstrapper; -use network::{NetworkConfig, NetworkMessage, Service as NetworkService}; +use network::{NetworkConfig, NetworkMessage, NetworkService}; use slog::info; use ssz::Decode; use std::net::SocketAddr; @@ -56,10 +56,10 @@ pub struct ClientBuilder { beacon_chain_builder: Option>, beacon_chain: Option>>, eth1_service: Option, - exit_signals: Vec, + exit_channels: Vec>, event_handler: Option, - libp2p_network: Option>>, - libp2p_network_send: Option>, + network_globals: Option>>, + network_send: Option>>, http_listen_addr: Option, websocket_listen_addr: Option, eth_spec_instance: T::EthSpec, @@ -90,10 +90,10 @@ where beacon_chain_builder: None, beacon_chain: None, eth1_service: None, - exit_signals: vec![], + exit_channels: vec![], event_handler: None, - libp2p_network: None, - libp2p_network_send: None, + network_globals: None, + network_send: None, http_listen_addr: None, websocket_listen_addr: None, eth_spec_instance, @@ -249,24 +249,55 @@ where }) } - /// Immediately starts the libp2p networking stack. - pub fn libp2p_network(mut self, config: &NetworkConfig) -> Result { + /// Immediately starts the networking stack. + pub fn network(mut self, config: &NetworkConfig) -> Result { let beacon_chain = self .beacon_chain .clone() - .ok_or_else(|| "libp2p_network requires a beacon chain")?; + .ok_or_else(|| "network requires a beacon chain")?; let context = self .runtime_context .as_ref() - .ok_or_else(|| "libp2p_network requires a runtime_context")? + .ok_or_else(|| "network requires a runtime_context")? .service_context("network".into()); - let (network, network_send) = - NetworkService::new(beacon_chain, config, &context.executor, context.log) - .map_err(|e| format!("Failed to start libp2p network: {:?}", e))?; + let (network_globals, network_send, network_exit) = + NetworkService::start(beacon_chain, config, &context.executor, context.log) + .map_err(|e| format!("Failed to start network: {:?}", e))?; - self.libp2p_network = Some(network); - self.libp2p_network_send = Some(network_send); + self.network_globals = Some(network_globals); + self.network_send = Some(network_send); + self.exit_channels.push(network_exit); + + Ok(self) + } + + /// Immediately starts the timer service. + fn timer(mut self) -> Result { + let context = self + .runtime_context + .as_ref() + .ok_or_else(|| "node timer requires a runtime_context")? + .service_context("node_timer".into()); + let beacon_chain = self + .beacon_chain + .clone() + .ok_or_else(|| "node timer requires a beacon chain")?; + let milliseconds_per_slot = self + .chain_spec + .as_ref() + .ok_or_else(|| "node timer requires a chain spec".to_string())? + .milliseconds_per_slot; + + let timer_exit = timer::spawn( + &context.executor, + beacon_chain, + milliseconds_per_slot, + context.log, + ) + .map_err(|e| format!("Unable to start node timer: {}", e))?; + + self.exit_channels.push(timer_exit); Ok(self) } @@ -286,21 +317,21 @@ where .as_ref() .ok_or_else(|| "http_server requires a runtime_context")? .service_context("http".into()); - let network = self - .libp2p_network + let network_globals = self + .network_globals .clone() .ok_or_else(|| "http_server requires a libp2p network")?; let network_send = self - .libp2p_network_send + .network_send .clone() .ok_or_else(|| "http_server requires a libp2p network sender")?; let network_info = rest_api::NetworkInfo { - network_service: network, + network_globals, network_chan: network_send, }; - let (exit_signal, listening_addr) = rest_api::start_server( + let (exit_channel, listening_addr) = rest_api::start_server( &client_config.rest_api, &context.executor, beacon_chain, @@ -316,7 +347,7 @@ where ) .map_err(|e| format!("Failed to start HTTP API: {:?}", e))?; - self.exit_signals.push(exit_signal); + self.exit_channels.push(exit_channel); self.http_listen_addr = Some(listening_addr); Ok(self) @@ -333,8 +364,8 @@ where .beacon_chain .clone() .ok_or_else(|| "slot_notifier requires a beacon chain")?; - let network = self - .libp2p_network + let network_globals = self + .network_globals .clone() .ok_or_else(|| "slot_notifier requires a libp2p network")?; let milliseconds_per_slot = self @@ -343,10 +374,15 @@ where .ok_or_else(|| "slot_notifier requires a chain spec".to_string())? .milliseconds_per_slot; - let exit_signal = spawn_notifier(context, beacon_chain, network, milliseconds_per_slot) - .map_err(|e| format!("Unable to start slot notifier: {}", e))?; + let exit_channel = spawn_notifier( + context, + beacon_chain, + network_globals, + milliseconds_per_slot, + ) + .map_err(|e| format!("Unable to start slot notifier: {}", e))?; - self.exit_signals.push(exit_signal); + self.exit_channels.push(exit_channel); Ok(self) } @@ -361,10 +397,10 @@ where { Client { beacon_chain: self.beacon_chain, - libp2p_network: self.libp2p_network, + network_globals: self.network_globals, http_listen_addr: self.http_listen_addr, websocket_listen_addr: self.websocket_listen_addr, - _exit_signals: self.exit_signals, + _exit_channels: self.exit_channels, } } } @@ -404,7 +440,8 @@ where self.beacon_chain_builder = None; self.event_handler = None; - Ok(self) + // a beacon chain requires a timer + self.timer() } } @@ -434,7 +471,7 @@ where .ok_or_else(|| "websocket_event_handler requires a runtime_context")? .service_context("ws".into()); - let (sender, exit_signal, listening_addr): ( + let (sender, exit_channel, listening_addr): ( WebSocketSender, Option<_>, Option<_>, @@ -446,8 +483,8 @@ where (WebSocketSender::dummy(), None, None) }; - if let Some(signal) = exit_signal { - self.exit_signals.push(signal); + if let Some(channel) = exit_channel { + self.exit_channels.push(channel); } self.event_handler = Some(sender); self.websocket_listen_addr = listening_addr; @@ -648,8 +685,8 @@ where self.eth1_service = None; let exit = { - let (tx, rx) = exit_future::signal(); - self.exit_signals.push(tx); + let (tx, rx) = tokio::sync::oneshot::channel(); + self.exit_channels.push(tx); rx }; @@ -711,7 +748,7 @@ where .ok_or_else(|| "system_time_slot_clock requires a beacon_chain_builder")?; let genesis_time = beacon_chain_builder - .finalized_checkpoint + .finalized_snapshot .as_ref() .ok_or_else(|| "system_time_slot_clock requires an initialized beacon state")? .beacon_state diff --git a/beacon_node/client/src/lib.rs b/beacon_node/client/src/lib.rs index 6f1214ce5..ab2e0556c 100644 --- a/beacon_node/client/src/lib.rs +++ b/beacon_node/client/src/lib.rs @@ -1,15 +1,14 @@ extern crate slog; pub mod config; +mod metrics; mod notifier; pub mod builder; pub mod error; use beacon_chain::BeaconChain; -use eth2_libp2p::{Enr, Multiaddr}; -use exit_future::Signal; -use network::Service as NetworkService; +use eth2_libp2p::{Enr, Multiaddr, NetworkGlobals}; use std::net::SocketAddr; use std::sync::Arc; @@ -23,11 +22,11 @@ pub use eth2_config::Eth2Config; /// Holds references to running services, cleanly shutting them down when dropped. pub struct Client { beacon_chain: Option>>, - libp2p_network: Option>>, + network_globals: Option>>, http_listen_addr: Option, websocket_listen_addr: Option, - /// Exit signals will "fire" when dropped, causing each service to exit gracefully. - _exit_signals: Vec, + /// Exit channels will complete/error when dropped, causing each service to exit gracefully. + _exit_channels: Vec>, } impl Client { @@ -48,16 +47,16 @@ impl Client { /// Returns the port of the client's libp2p stack, if it was started. pub fn libp2p_listen_port(&self) -> Option { - self.libp2p_network.as_ref().map(|n| n.listen_port()) + self.network_globals.as_ref().map(|n| n.listen_port_tcp()) } /// Returns the list of libp2p addresses the client is listening to. pub fn libp2p_listen_addresses(&self) -> Option> { - self.libp2p_network.as_ref().map(|n| n.listen_multiaddrs()) + self.network_globals.as_ref().map(|n| n.listen_multiaddrs()) } /// Returns the local libp2p ENR of this node, for network discovery. pub fn enr(&self) -> Option { - self.libp2p_network.as_ref()?.local_enr() + self.network_globals.as_ref()?.local_enr() } } diff --git a/beacon_node/client/src/metrics.rs b/beacon_node/client/src/metrics.rs new file mode 100644 index 000000000..5598fde22 --- /dev/null +++ b/beacon_node/client/src/metrics.rs @@ -0,0 +1,9 @@ +use lazy_static::lazy_static; +pub use lighthouse_metrics::*; + +lazy_static! { + pub static ref SYNC_SLOTS_PER_SECOND: Result = try_create_int_gauge( + "sync_slots_per_second", + "The number of blocks being imported per second" + ); +} diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs index eddebce1f..4f57800b1 100644 --- a/beacon_node/client/src/notifier.rs +++ b/beacon_node/client/src/notifier.rs @@ -1,8 +1,8 @@ +use crate::metrics; use beacon_chain::{BeaconChain, BeaconChainTypes}; use environment::RuntimeContext; -use exit_future::Signal; +use eth2_libp2p::NetworkGlobals; use futures::{Future, Stream}; -use network::Service as NetworkService; use parking_lot::Mutex; use slog::{debug, error, info, warn}; use slot_clock::SlotClock; @@ -29,9 +29,9 @@ const SPEEDO_OBSERVATIONS: usize = 4; pub fn spawn_notifier( context: RuntimeContext, beacon_chain: Arc>, - network: Arc>, + network: Arc>, milliseconds_per_slot: u64, -) -> Result { +) -> Result, String> { let log_1 = context.log.clone(); let log_2 = context.log.clone(); let log_3 = context.log.clone(); @@ -83,6 +83,8 @@ pub fn spawn_notifier( let mut speedo = speedo.lock(); speedo.observe(head_slot, Instant::now()); + metrics::set_gauge(&metrics::SYNC_SLOTS_PER_SECOND, speedo.slots_per_second().unwrap_or_else(|| 0_f64) as i64); + // The next two lines take advantage of saturating subtraction on `Slot`. let head_distance = current_slot - head_slot; @@ -164,10 +166,11 @@ pub fn spawn_notifier( Ok(()) } } }); - let (exit_signal, exit) = exit_future::signal(); + let (exit_signal, exit) = tokio::sync::oneshot::channel(); + context .executor - .spawn(exit.until(interval_future).map(|_| ())); + .spawn(interval_future.select(exit).map(|_| ()).map_err(|_| ())); Ok(exit_signal) } diff --git a/beacon_node/eth1/Cargo.toml b/beacon_node/eth1/Cargo.toml index 03e592940..fa945752b 100644 --- a/beacon_node/eth1/Cargo.toml +++ b/beacon_node/eth1/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "eth1" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" @@ -26,7 +26,6 @@ parking_lot = "0.7" slog = "^2.2.3" tokio = "0.1.22" state_processing = { path = "../../eth2/state_processing" } -exit-future = "0.1.4" libflate = "0.1" lighthouse_metrics = { path = "../../eth2/utils/lighthouse_metrics"} lazy_static = "1.4.0" diff --git a/beacon_node/eth1/src/service.rs b/beacon_node/eth1/src/service.rs index 292f777fe..9890ec6b0 100644 --- a/beacon_node/eth1/src/service.rs +++ b/beacon_node/eth1/src/service.rs @@ -6,7 +6,6 @@ use crate::{ inner::{DepositUpdater, Inner}, DepositLog, }; -use exit_future::Exit; use futures::{ future::{loop_fn, Loop}, stream, Future, Stream, @@ -314,7 +313,10 @@ impl Service { /// - Err(_) if there is an error. /// /// Emits logs for debugging and errors. - pub fn auto_update(&self, exit: Exit) -> impl Future { + pub fn auto_update( + &self, + exit: tokio::sync::oneshot::Receiver<()>, + ) -> impl Future { let service = self.clone(); let log = self.log.clone(); let update_interval = Duration::from_millis(self.config().auto_update_interval_millis); @@ -360,7 +362,7 @@ impl Service { }) }); - exit.until(loop_future).map(|_: Option<()>| ()) + loop_future.select(exit).map(|_| ()).map_err(|_| ()) } /// Contacts the remote eth1 node and attempts to import deposit logs up to the configured diff --git a/beacon_node/eth2-libp2p/Cargo.toml b/beacon_node/eth2-libp2p/Cargo.toml index edee55307..1232dcda6 100644 --- a/beacon_node/eth2-libp2p/Cargo.toml +++ b/beacon_node/eth2-libp2p/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "eth2-libp2p" -version = "0.1.0" +version = "0.2.0" authors = ["Age Manning "] edition = "2018" diff --git a/beacon_node/eth2-libp2p/src/behaviour.rs b/beacon_node/eth2-libp2p/src/behaviour.rs index 66cf6f0a7..7c2294d8a 100644 --- a/beacon_node/eth2-libp2p/src/behaviour.rs +++ b/beacon_node/eth2-libp2p/src/behaviour.rs @@ -1,6 +1,6 @@ use crate::discovery::Discovery; use crate::rpc::{RPCEvent, RPCMessage, RPC}; -use crate::{error, GossipTopic, NetworkConfig, NetworkGlobals, Topic, TopicHash}; +use crate::{error, GossipTopic, NetworkConfig, NetworkGlobals, PubsubMessage, TopicHash}; use enr::Enr; use futures::prelude::*; use libp2p::{ @@ -8,16 +8,14 @@ use libp2p::{ discv5::Discv5Event, gossipsub::{Gossipsub, GossipsubEvent, MessageId}, identify::{Identify, IdentifyEvent}, - ping::{Ping, PingConfig, PingEvent}, swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess}, tokio_io::{AsyncRead, AsyncWrite}, NetworkBehaviour, PeerId, }; use lru::LruCache; -use slog::{debug, o}; -use std::num::NonZeroU32; +use slog::{debug, o, warn}; use std::sync::Arc; -use std::time::Duration; +use types::EthSpec; const MAX_IDENTIFY_ADDRESSES: usize = 20; @@ -25,48 +23,43 @@ const MAX_IDENTIFY_ADDRESSES: usize = 20; /// This core behaviour is managed by `Behaviour` which adds peer management to all core /// behaviours. #[derive(NetworkBehaviour)] -#[behaviour(out_event = "BehaviourEvent", poll_method = "poll")] -pub struct Behaviour { +#[behaviour(out_event = "BehaviourEvent", poll_method = "poll")] +pub struct Behaviour { /// The routing pub-sub mechanism for eth2. gossipsub: Gossipsub, /// The Eth2 RPC specified in the wire-0 protocol. - eth2_rpc: RPC, + eth2_rpc: RPC, /// Keep regular connection to peers and disconnect if absent. - // TODO: Remove Libp2p ping in favour of discv5 ping. - ping: Ping, // TODO: Using id for initial interop. This will be removed by mainnet. /// Provides IP addresses and peer information. identify: Identify, /// Discovery behaviour. - discovery: Discovery, + discovery: Discovery, /// The events generated by this behaviour to be consumed in the swarm poll. #[behaviour(ignore)] - events: Vec, + events: Vec>, /// A cache of recently seen gossip messages. This is used to filter out any possible /// duplicates that may still be seen over gossipsub. #[behaviour(ignore)] seen_gossip_messages: LruCache, + /// A collections of variables accessible outside the network service. + #[behaviour(ignore)] + network_globals: Arc>, #[behaviour(ignore)] /// Logger for behaviour actions. log: slog::Logger, } -impl Behaviour { +impl Behaviour { pub fn new( local_key: &Keypair, net_conf: &NetworkConfig, - network_globals: Arc, + network_globals: Arc>, log: &slog::Logger, ) -> error::Result { let local_peer_id = local_key.public().into_peer_id(); let behaviour_log = log.new(o!()); - let ping_config = PingConfig::new() - .with_timeout(Duration::from_secs(30)) - .with_interval(Duration::from_secs(20)) - .with_max_failures(NonZeroU32::new(2).expect("2 != 0")) - .with_keep_alive(false); - let identify = Identify::new( "lighthouse/libp2p".into(), version::version(), @@ -76,16 +69,16 @@ impl Behaviour { Ok(Behaviour { eth2_rpc: RPC::new(log.clone()), gossipsub: Gossipsub::new(local_peer_id, net_conf.gs_config.clone()), - discovery: Discovery::new(local_key, net_conf, network_globals, log)?, - ping: Ping::new(ping_config), + discovery: Discovery::new(local_key, net_conf, network_globals.clone(), log)?, identify, events: Vec::new(), seen_gossip_messages: LruCache::new(100_000), + network_globals, log: behaviour_log, }) } - pub fn discovery(&self) -> &Discovery { + pub fn discovery(&self) -> &Discovery { &self.discovery } @@ -95,26 +88,31 @@ impl Behaviour { } // Implement the NetworkBehaviourEventProcess trait so that we can derive NetworkBehaviour for Behaviour -impl NetworkBehaviourEventProcess - for Behaviour +impl + NetworkBehaviourEventProcess for Behaviour { fn inject_event(&mut self, event: GossipsubEvent) { match event { GossipsubEvent::Message(propagation_source, id, gs_msg) => { - let msg = PubsubMessage::from_topics(&gs_msg.topics, gs_msg.data); - // Note: We are keeping track here of the peer that sent us the message, not the // peer that originally published the message. if self.seen_gossip_messages.put(id.clone(), ()).is_none() { - // if this message isn't a duplicate, notify the network - self.events.push(BehaviourEvent::GossipMessage { - id, - source: propagation_source, - topics: gs_msg.topics, - message: msg, - }); + match PubsubMessage::decode(&gs_msg.topics, &gs_msg.data) { + Err(e) => { + debug!(self.log, "Could not decode gossipsub message"; "error" => format!("{}", e)) + } + Ok(msg) => { + // if this message isn't a duplicate, notify the network + self.events.push(BehaviourEvent::GossipMessage { + id, + source: propagation_source, + topics: gs_msg.topics, + message: msg, + }); + } + } } else { - debug!(self.log, "A duplicate message was received"; "message" => format!("{:?}", msg)); + warn!(self.log, "A duplicate gossipsub message was received"; "message" => format!("{:?}", gs_msg)); } } GossipsubEvent::Subscribed { peer_id, topic } => { @@ -126,10 +124,10 @@ impl NetworkBehaviourEventProcess NetworkBehaviourEventProcess - for Behaviour +impl + NetworkBehaviourEventProcess> for Behaviour { - fn inject_event(&mut self, event: RPCMessage) { + fn inject_event(&mut self, event: RPCMessage) { match event { RPCMessage::PeerDialed(peer_id) => { self.events.push(BehaviourEvent::PeerDialed(peer_id)) @@ -144,19 +142,11 @@ impl NetworkBehaviourEventProcess NetworkBehaviourEventProcess - for Behaviour -{ - fn inject_event(&mut self, _event: PingEvent) { - // not interested in ping responses at the moment. - } -} - -impl Behaviour { +impl Behaviour { /// Consumes the events list when polled. fn poll( &mut self, - ) -> Async> { + ) -> Async>> { if !self.events.is_empty() { return Async::Ready(NetworkBehaviourAction::GenerateEvent(self.events.remove(0))); } @@ -165,8 +155,8 @@ impl Behaviour { } } -impl NetworkBehaviourEventProcess - for Behaviour +impl NetworkBehaviourEventProcess + for Behaviour { fn inject_event(&mut self, event: IdentifyEvent) { match event { @@ -196,8 +186,8 @@ impl NetworkBehaviourEventProcess NetworkBehaviourEventProcess - for Behaviour +impl NetworkBehaviourEventProcess + for Behaviour { fn inject_event(&mut self, _event: Discv5Event) { // discv5 has no events to inject @@ -205,24 +195,49 @@ impl NetworkBehaviourEventProcess Behaviour { +impl Behaviour { /* Pubsub behaviour functions */ /// Subscribes to a gossipsub topic. - pub fn subscribe(&mut self, topic: Topic) -> bool { - self.gossipsub.subscribe(topic) + pub fn subscribe(&mut self, topic: GossipTopic) -> bool { + if !self + .network_globals + .gossipsub_subscriptions + .read() + .contains(&topic) + { + self.network_globals + .gossipsub_subscriptions + .write() + .push(topic.clone()); + } + self.gossipsub.subscribe(topic.into()) } /// Unsubscribe from a gossipsub topic. - pub fn unsubscribe(&mut self, topic: Topic) -> bool { - self.gossipsub.unsubscribe(topic) + pub fn unsubscribe(&mut self, topic: GossipTopic) -> bool { + let pos = self + .network_globals + .gossipsub_subscriptions + .read() + .iter() + .position(|s| s == &topic); + if let Some(pos) = pos { + self.network_globals + .gossipsub_subscriptions + .write() + .swap_remove(pos); + } + self.gossipsub.unsubscribe(topic.into()) } - /// Publishes a message on the pubsub (gossipsub) behaviour. - pub fn publish(&mut self, topics: &[Topic], message: PubsubMessage) { - let message_data = message.into_data(); - for topic in topics { - self.gossipsub.publish(topic, message_data.clone()); + /// Publishes a list of messages on the pubsub (gossipsub) behaviour, choosing the encoding. + pub fn publish(&mut self, messages: Vec>) { + for message in messages { + for topic in message.topics() { + let message_data = message.encode(); + self.gossipsub.publish(&topic.into(), message_data); + } } } @@ -236,14 +251,15 @@ impl Behaviour { /* Eth2 RPC behaviour functions */ /// Sends an RPC Request/Response via the RPC protocol. - pub fn send_rpc(&mut self, peer_id: PeerId, rpc_event: RPCEvent) { + pub fn send_rpc(&mut self, peer_id: PeerId, rpc_event: RPCEvent) { self.eth2_rpc.send_rpc(peer_id, rpc_event); } /* Discovery / Peer management functions */ - /// Return the list of currently connected peers. + + /// The current number of connected libp2p peers. pub fn connected_peers(&self) -> usize { - self.discovery.connected_peers() + self.network_globals.connected_peers() } /// Notify discovery that the peer has been banned. @@ -268,9 +284,9 @@ impl Behaviour { } /// The types of events than can be obtained from polling the behaviour. -pub enum BehaviourEvent { +pub enum BehaviourEvent { /// A received RPC event and the peer that it was received from. - RPC(PeerId, RPCEvent), + RPC(PeerId, RPCEvent), /// We have completed an initial connection to a new peer. PeerDialed(PeerId), /// A peer has disconnected. @@ -284,60 +300,8 @@ pub enum BehaviourEvent { /// The topics that this message was sent on. topics: Vec, /// The message itself. - message: PubsubMessage, + message: PubsubMessage, }, /// Subscribed to peer for given topic PeerSubscribed(PeerId, TopicHash), } - -/// Messages that are passed to and from the pubsub (Gossipsub) behaviour. These are encoded and -/// decoded upstream. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum PubsubMessage { - /// Gossipsub message providing notification of a new block. - Block(Vec), - /// Gossipsub message providing notification of a new attestation. - Attestation(Vec), - /// Gossipsub message providing notification of a voluntary exit. - VoluntaryExit(Vec), - /// Gossipsub message providing notification of a new proposer slashing. - ProposerSlashing(Vec), - /// Gossipsub message providing notification of a new attester slashing. - AttesterSlashing(Vec), - /// Gossipsub message from an unknown topic. - Unknown(Vec), -} - -impl PubsubMessage { - /* Note: This is assuming we are not hashing topics. If we choose to hash topics, these will - * need to be modified. - * - * Also note that a message can be associated with many topics. As soon as one of the topics is - * known we match. If none of the topics are known we return an unknown state. - */ - fn from_topics(topics: &[TopicHash], data: Vec) -> Self { - for topic in topics { - match GossipTopic::from(topic.as_str()) { - GossipTopic::BeaconBlock => return PubsubMessage::Block(data), - GossipTopic::BeaconAttestation => return PubsubMessage::Attestation(data), - GossipTopic::VoluntaryExit => return PubsubMessage::VoluntaryExit(data), - GossipTopic::ProposerSlashing => return PubsubMessage::ProposerSlashing(data), - GossipTopic::AttesterSlashing => return PubsubMessage::AttesterSlashing(data), - GossipTopic::Shard => return PubsubMessage::Unknown(data), - GossipTopic::Unknown(_) => continue, - } - } - PubsubMessage::Unknown(data) - } - - fn into_data(self) -> Vec { - match self { - PubsubMessage::Block(data) - | PubsubMessage::Attestation(data) - | PubsubMessage::VoluntaryExit(data) - | PubsubMessage::ProposerSlashing(data) - | PubsubMessage::AttesterSlashing(data) - | PubsubMessage::Unknown(data) => data, - } - } -} diff --git a/beacon_node/eth2-libp2p/src/config.rs b/beacon_node/eth2-libp2p/src/config.rs index d0ec62df2..5941da3d7 100644 --- a/beacon_node/eth2-libp2p/src/config.rs +++ b/beacon_node/eth2-libp2p/src/config.rs @@ -1,4 +1,4 @@ -use crate::topics::GossipTopic; +use crate::types::{GossipEncoding, GossipKind, GossipTopic}; use enr::Enr; use libp2p::gossipsub::{GossipsubConfig, GossipsubConfigBuilder, GossipsubMessage, MessageId}; use libp2p::Multiaddr; @@ -67,11 +67,11 @@ impl Default for Config { // The default topics that we will initially subscribe to let topics = vec![ - GossipTopic::BeaconBlock, - GossipTopic::BeaconAttestation, - GossipTopic::VoluntaryExit, - GossipTopic::ProposerSlashing, - GossipTopic::AttesterSlashing, + GossipTopic::new(GossipKind::BeaconBlock, GossipEncoding::SSZ), + GossipTopic::new(GossipKind::BeaconAggregateAndProof, GossipEncoding::SSZ), + GossipTopic::new(GossipKind::VoluntaryExit, GossipEncoding::SSZ), + GossipTopic::new(GossipKind::ProposerSlashing, GossipEncoding::SSZ), + GossipTopic::new(GossipKind::AttesterSlashing, GossipEncoding::SSZ), ]; // The function used to generate a gossipsub message id diff --git a/beacon_node/eth2-libp2p/src/discovery.rs b/beacon_node/eth2-libp2p/src/discovery.rs index 235fd7194..733b14c84 100644 --- a/beacon_node/eth2-libp2p/src/discovery.rs +++ b/beacon_node/eth2-libp2p/src/discovery.rs @@ -1,5 +1,5 @@ use crate::metrics; -use crate::{error, NetworkConfig, NetworkGlobals}; +use crate::{error, NetworkConfig, NetworkGlobals, PeerInfo}; /// This manages the discovery and management of peers. /// /// Currently using discv5 for peer discovery. @@ -16,10 +16,11 @@ use std::fs::File; use std::io::prelude::*; use std::path::Path; use std::str::FromStr; -use std::sync::{atomic::Ordering, Arc}; +use std::sync::Arc; use std::time::{Duration, Instant}; use tokio::io::{AsyncRead, AsyncWrite}; use tokio::timer::Delay; +use types::EthSpec; /// Maximum seconds before searching for extra peers. const MAX_TIME_BETWEEN_PEER_SEARCHES: u64 = 120; @@ -30,7 +31,7 @@ const ENR_FILENAME: &str = "enr.dat"; /// Lighthouse discovery behaviour. This provides peer management and discovery using the Discv5 /// libp2p protocol. -pub struct Discovery { +pub struct Discovery { /// The currently banned peers. banned_peers: HashSet, @@ -56,17 +57,17 @@ pub struct Discovery { discovery: Discv5, /// A collection of network constants that can be read from other threads. - network_globals: Arc, + network_globals: Arc>, /// Logger for the discovery behaviour. log: slog::Logger, } -impl Discovery { +impl Discovery { pub fn new( local_key: &Keypair, config: &NetworkConfig, - network_globals: Arc, + network_globals: Arc>, log: &slog::Logger, ) -> error::Result { let log = log.clone(); @@ -81,8 +82,7 @@ impl Discovery { None => String::from(""), }; - info!(log, "ENR Initialised"; "enr" => local_enr.to_base64(), "seq" => local_enr.seq()); - debug!(log, "Discv5 Node ID Initialised"; "node_id" => format!("{}",local_enr.node_id())); + info!(log, "ENR Initialised"; "enr" => local_enr.to_base64(), "seq" => local_enr.seq(), "id"=> format!("{}",local_enr.node_id()), "ip" => format!("{:?}", local_enr.ip()), "udp"=> local_enr.udp().unwrap_or_else(|| 0), "tcp" => local_enr.tcp().unwrap_or_else(|| 0)); // the last parameter enables IP limiting. 2 Nodes on the same /24 subnet per bucket and 10 // nodes on the same /24 subnet per table. @@ -131,21 +131,6 @@ impl Discovery { self.discovery.add_enr(enr); } - /// The current number of connected libp2p peers. - pub fn connected_peers(&self) -> usize { - self.network_globals.connected_peers.load(Ordering::Relaxed) - } - - /// The current number of connected libp2p peers. - pub fn connected_peer_set(&self) -> Vec { - self.network_globals - .connected_peer_set - .read() - .iter() - .cloned() - .collect::>() - } - /// The peer has been banned. Add this peer to the banned list to prevent any future /// re-connections. // TODO: Remove the peer from the DHT if present @@ -172,7 +157,7 @@ impl Discovery { } // Redirect all behaviour events to underlying discovery behaviour. -impl NetworkBehaviour for Discovery +impl NetworkBehaviour for Discovery where TSubstream: AsyncRead + AsyncWrite, { @@ -189,18 +174,18 @@ where } fn inject_connected(&mut self, peer_id: PeerId, _endpoint: ConnectedPoint) { + // TODO: Search for a known ENR once discv5 is updated. self.network_globals .connected_peer_set .write() - .insert(peer_id); - self.network_globals.connected_peers.store( - self.network_globals.connected_peer_set.read().len(), - Ordering::Relaxed, - ); + .insert(peer_id, PeerInfo::new()); // TODO: Drop peers if over max_peer limit metrics::inc_counter(&metrics::PEER_CONNECT_EVENT_COUNT); - metrics::set_gauge(&metrics::PEERS_CONNECTED, self.connected_peers() as i64); + metrics::set_gauge( + &metrics::PEERS_CONNECTED, + self.network_globals.connected_peers() as i64, + ); } fn inject_disconnected(&mut self, peer_id: &PeerId, _endpoint: ConnectedPoint) { @@ -208,13 +193,12 @@ where .connected_peer_set .write() .remove(peer_id); - self.network_globals.connected_peers.store( - self.network_globals.connected_peer_set.read().len(), - Ordering::Relaxed, - ); metrics::inc_counter(&metrics::PEER_DISCONNECT_EVENT_COUNT); - metrics::set_gauge(&metrics::PEERS_CONNECTED, self.connected_peers() as i64); + metrics::set_gauge( + &metrics::PEERS_CONNECTED, + self.network_globals.connected_peers() as i64, + ); } fn inject_replaced( @@ -247,8 +231,7 @@ where loop { match self.peer_discovery_delay.poll() { Ok(Async::Ready(_)) => { - if self.network_globals.connected_peers.load(Ordering::Relaxed) < self.max_peers - { + if self.network_globals.connected_peers() < self.max_peers { self.find_peers(); } // Set to maximum, and update to earlier, once we get our results back. @@ -303,8 +286,7 @@ where for peer_id in closer_peers { // if we need more peers, attempt a connection - if self.network_globals.connected_peers.load(Ordering::Relaxed) - < self.max_peers + if self.network_globals.connected_peers() < self.max_peers && self .network_globals .connected_peer_set diff --git a/beacon_node/eth2-libp2p/src/globals.rs b/beacon_node/eth2-libp2p/src/globals.rs deleted file mode 100644 index 901550034..000000000 --- a/beacon_node/eth2-libp2p/src/globals.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! A collection of variables that are accessible outside of the network thread itself. -use crate::{Enr, Multiaddr, PeerId}; -use parking_lot::RwLock; -use std::collections::HashSet; -use std::sync::atomic::AtomicUsize; - -pub struct NetworkGlobals { - /// The current local ENR. - pub local_enr: RwLock>, - /// The local peer_id. - pub peer_id: RwLock, - /// Listening multiaddrs. - pub listen_multiaddrs: RwLock>, - /// Current number of connected libp2p peers. - pub connected_peers: AtomicUsize, - /// The collection of currently connected peers. - pub connected_peer_set: RwLock>, -} - -impl NetworkGlobals { - pub fn new(peer_id: PeerId) -> Self { - NetworkGlobals { - local_enr: RwLock::new(None), - peer_id: RwLock::new(peer_id), - listen_multiaddrs: RwLock::new(Vec::new()), - connected_peers: AtomicUsize::new(0), - connected_peer_set: RwLock::new(HashSet::new()), - } - } -} diff --git a/beacon_node/eth2-libp2p/src/lib.rs b/beacon_node/eth2-libp2p/src/lib.rs index d09921b2d..49e571567 100644 --- a/beacon_node/eth2-libp2p/src/lib.rs +++ b/beacon_node/eth2-libp2p/src/lib.rs @@ -8,25 +8,16 @@ extern crate lazy_static; pub mod behaviour; mod config; mod discovery; -pub mod error; -mod globals; mod metrics; pub mod rpc; mod service; -mod topics; +pub mod types; -pub use behaviour::PubsubMessage; +pub use crate::types::{error, GossipTopic, NetworkGlobals, PeerInfo, PubsubData, PubsubMessage}; pub use config::Config as NetworkConfig; -pub use globals::NetworkGlobals; pub use libp2p::enr::Enr; pub use libp2p::gossipsub::{MessageId, Topic, TopicHash}; -pub use libp2p::multiaddr; -pub use libp2p::Multiaddr; -pub use libp2p::{ - gossipsub::{GossipsubConfig, GossipsubConfigBuilder}, - PeerId, Swarm, -}; +pub use libp2p::{multiaddr, Multiaddr}; +pub use libp2p::{PeerId, Swarm}; pub use rpc::RPCEvent; -pub use service::Libp2pEvent; -pub use service::Service; -pub use topics::GossipTopic; +pub use service::{Libp2pEvent, Service}; diff --git a/beacon_node/eth2-libp2p/src/rpc/codec/base.rs b/beacon_node/eth2-libp2p/src/rpc/codec/base.rs index cc247911f..48b537c7b 100644 --- a/beacon_node/eth2-libp2p/src/rpc/codec/base.rs +++ b/beacon_node/eth2-libp2p/src/rpc/codec/base.rs @@ -3,7 +3,9 @@ use crate::rpc::{ErrorMessage, RPCErrorResponse, RPCRequest, RPCResponse}; use libp2p::bytes::BufMut; use libp2p::bytes::BytesMut; +use std::marker::PhantomData; use tokio::codec::{Decoder, Encoder}; +use types::EthSpec; pub trait OutboundCodec: Encoder + Decoder { type ErrorType; @@ -17,43 +19,53 @@ pub trait OutboundCodec: Encoder + Decoder { /* Global Inbound Codec */ // This deals with Decoding RPC Requests from other peers and encoding our responses -pub struct BaseInboundCodec +pub struct BaseInboundCodec where TCodec: Encoder + Decoder, + TSpec: EthSpec, { /// Inner codec for handling various encodings inner: TCodec, + phantom: PhantomData, } -impl BaseInboundCodec +impl BaseInboundCodec where TCodec: Encoder + Decoder, + TSpec: EthSpec, { pub fn new(codec: TCodec) -> Self { - BaseInboundCodec { inner: codec } + BaseInboundCodec { + inner: codec, + phantom: PhantomData, + } } } /* Global Outbound Codec */ // This deals with Decoding RPC Responses from other peers and encoding our requests -pub struct BaseOutboundCodec +pub struct BaseOutboundCodec where TOutboundCodec: OutboundCodec, + TSpec: EthSpec, { /// Inner codec for handling various encodings. inner: TOutboundCodec, /// Keeps track of the current response code for a chunk. current_response_code: Option, + phantom: PhantomData, } -impl BaseOutboundCodec +impl BaseOutboundCodec where + TSpec: EthSpec, TOutboundCodec: OutboundCodec, { pub fn new(codec: TOutboundCodec) -> Self { BaseOutboundCodec { inner: codec, current_response_code: None, + phantom: PhantomData, } } } @@ -63,11 +75,12 @@ where /* Base Inbound Codec */ // This Encodes RPC Responses sent to external peers -impl Encoder for BaseInboundCodec +impl Encoder for BaseInboundCodec where - TCodec: Decoder + Encoder, + TSpec: EthSpec, + TCodec: Decoder + Encoder>, { - type Item = RPCErrorResponse; + type Item = RPCErrorResponse; type Error = ::Error; fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> { @@ -82,11 +95,12 @@ where } // This Decodes RPC Requests from external peers -impl Decoder for BaseInboundCodec +impl Decoder for BaseInboundCodec where - TCodec: Encoder + Decoder, + TSpec: EthSpec, + TCodec: Encoder + Decoder>, { - type Item = RPCRequest; + type Item = RPCRequest; type Error = ::Error; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { @@ -97,11 +111,12 @@ where /* Base Outbound Codec */ // This Encodes RPC Requests sent to external peers -impl Encoder for BaseOutboundCodec +impl Encoder for BaseOutboundCodec where - TCodec: OutboundCodec + Encoder, + TSpec: EthSpec, + TCodec: OutboundCodec + Encoder>, { - type Item = RPCRequest; + type Item = RPCRequest; type Error = ::Error; fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> { @@ -110,11 +125,12 @@ where } // This decodes RPC Responses received from external peers -impl Decoder for BaseOutboundCodec +impl Decoder for BaseOutboundCodec where - TCodec: OutboundCodec + Decoder, + TSpec: EthSpec, + TCodec: OutboundCodec + Decoder>, { - type Item = RPCErrorResponse; + type Item = RPCErrorResponse; type Error = ::Error; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { @@ -130,7 +146,7 @@ where }); let inner_result = { - if RPCErrorResponse::is_response(response_code) { + if RPCErrorResponse::::is_response(response_code) { // decode an actual response and mutates the buffer if enough bytes have been read // returning the result. self.inner diff --git a/beacon_node/eth2-libp2p/src/rpc/codec/mod.rs b/beacon_node/eth2-libp2p/src/rpc/codec/mod.rs index b9993d4b3..c6644cf26 100644 --- a/beacon_node/eth2-libp2p/src/rpc/codec/mod.rs +++ b/beacon_node/eth2-libp2p/src/rpc/codec/mod.rs @@ -7,18 +7,19 @@ use crate::rpc::protocol::RPCError; use crate::rpc::{RPCErrorResponse, RPCRequest}; use libp2p::bytes::BytesMut; use tokio::codec::{Decoder, Encoder}; +use types::EthSpec; // Known types of codecs -pub enum InboundCodec { - SSZ(BaseInboundCodec), +pub enum InboundCodec { + SSZ(BaseInboundCodec, TSpec>), } -pub enum OutboundCodec { - SSZ(BaseOutboundCodec), +pub enum OutboundCodec { + SSZ(BaseOutboundCodec, TSpec>), } -impl Encoder for InboundCodec { - type Item = RPCErrorResponse; +impl Encoder for InboundCodec { + type Item = RPCErrorResponse; type Error = RPCError; fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> { @@ -28,8 +29,8 @@ impl Encoder for InboundCodec { } } -impl Decoder for InboundCodec { - type Item = RPCRequest; +impl Decoder for InboundCodec { + type Item = RPCRequest; type Error = RPCError; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { @@ -39,8 +40,8 @@ impl Decoder for InboundCodec { } } -impl Encoder for OutboundCodec { - type Item = RPCRequest; +impl Encoder for OutboundCodec { + type Item = RPCRequest; type Error = RPCError; fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> { @@ -50,8 +51,8 @@ impl Encoder for OutboundCodec { } } -impl Decoder for OutboundCodec { - type Item = RPCErrorResponse; +impl Decoder for OutboundCodec { + type Item = RPCErrorResponse; type Error = RPCError; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { diff --git a/beacon_node/eth2-libp2p/src/rpc/codec/ssz.rs b/beacon_node/eth2-libp2p/src/rpc/codec/ssz.rs index b377f5972..893af554c 100644 --- a/beacon_node/eth2-libp2p/src/rpc/codec/ssz.rs +++ b/beacon_node/eth2-libp2p/src/rpc/codec/ssz.rs @@ -8,17 +8,20 @@ use crate::rpc::{ use crate::rpc::{ErrorMessage, RPCErrorResponse, RPCRequest, RPCResponse}; use libp2p::bytes::{BufMut, Bytes, BytesMut}; use ssz::{Decode, Encode}; +use std::marker::PhantomData; use tokio::codec::{Decoder, Encoder}; +use types::{EthSpec, SignedBeaconBlock}; use unsigned_varint::codec::UviBytes; /* Inbound Codec */ -pub struct SSZInboundCodec { +pub struct SSZInboundCodec { inner: UviBytes, protocol: ProtocolId, + phantom: PhantomData, } -impl SSZInboundCodec { +impl SSZInboundCodec { pub fn new(protocol: ProtocolId, max_packet_size: usize) -> Self { let mut uvi_codec = UviBytes::default(); uvi_codec.set_max_len(max_packet_size); @@ -29,24 +32,23 @@ impl SSZInboundCodec { SSZInboundCodec { inner: uvi_codec, protocol, + phantom: PhantomData, } } } // Encoder for inbound streams: Encodes RPC Responses sent to peers. -impl Encoder for SSZInboundCodec { - type Item = RPCErrorResponse; +impl Encoder for SSZInboundCodec { + type Item = RPCErrorResponse; type Error = RPCError; fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> { let bytes = match item { - RPCErrorResponse::Success(resp) => { - match resp { - RPCResponse::Status(res) => res.as_ssz_bytes(), - RPCResponse::BlocksByRange(res) => res, // already raw bytes - RPCResponse::BlocksByRoot(res) => res, // already raw bytes - } - } + RPCErrorResponse::Success(resp) => match resp { + RPCResponse::Status(res) => res.as_ssz_bytes(), + RPCResponse::BlocksByRange(res) => res.as_ssz_bytes(), + RPCResponse::BlocksByRoot(res) => res.as_ssz_bytes(), + }, RPCErrorResponse::InvalidRequest(err) => err.as_ssz_bytes(), RPCErrorResponse::ServerError(err) => err.as_ssz_bytes(), RPCErrorResponse::Unknown(err) => err.as_ssz_bytes(), @@ -70,8 +72,8 @@ impl Encoder for SSZInboundCodec { } // Decoder for inbound streams: Decodes RPC requests from peers -impl Decoder for SSZInboundCodec { - type Item = RPCRequest; +impl Decoder for SSZInboundCodec { + type Item = RPCRequest; type Error = RPCError; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { @@ -111,12 +113,13 @@ impl Decoder for SSZInboundCodec { /* Outbound Codec: Codec for initiating RPC requests */ -pub struct SSZOutboundCodec { +pub struct SSZOutboundCodec { inner: UviBytes, protocol: ProtocolId, + phantom: PhantomData, } -impl SSZOutboundCodec { +impl SSZOutboundCodec { pub fn new(protocol: ProtocolId, max_packet_size: usize) -> Self { let mut uvi_codec = UviBytes::default(); uvi_codec.set_max_len(max_packet_size); @@ -127,13 +130,14 @@ impl SSZOutboundCodec { SSZOutboundCodec { inner: uvi_codec, protocol, + phantom: PhantomData, } } } // Encoder for outbound streams: Encodes RPC Requests to peers -impl Encoder for SSZOutboundCodec { - type Item = RPCRequest; +impl Encoder for SSZOutboundCodec { + type Item = RPCRequest; type Error = RPCError; fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> { @@ -142,6 +146,7 @@ impl Encoder for SSZOutboundCodec { RPCRequest::Goodbye(req) => req.as_ssz_bytes(), RPCRequest::BlocksByRange(req) => req.as_ssz_bytes(), RPCRequest::BlocksByRoot(req) => req.block_roots.as_ssz_bytes(), + RPCRequest::Phantom(_) => unreachable!("Never encode phantom data"), }; // length-prefix self.inner @@ -155,8 +160,8 @@ impl Encoder for SSZOutboundCodec { // The majority of the decoding has now been pushed upstream due to the changing specification. // We prefer to decode blocks and attestations with extra knowledge about the chain to perform // faster verification checks before decoding entire blocks/attestations. -impl Decoder for SSZOutboundCodec { - type Item = RPCResponse; +impl Decoder for SSZOutboundCodec { + type Item = RPCResponse; type Error = RPCError; fn decode(&mut self, src: &mut BytesMut) -> Result, Self::Error> { @@ -173,11 +178,15 @@ impl Decoder for SSZOutboundCodec { }, RPC_GOODBYE => Err(RPCError::InvalidProtocol("GOODBYE doesn't have a response")), RPC_BLOCKS_BY_RANGE => match self.protocol.version.as_str() { - "1" => Ok(Some(RPCResponse::BlocksByRange(Vec::new()))), + "1" => Err(RPCError::Custom( + "Status stream terminated unexpectedly, empty block".into(), + )), // cannot have an empty block message. _ => unreachable!("Cannot negotiate an unknown version"), }, RPC_BLOCKS_BY_ROOT => match self.protocol.version.as_str() { - "1" => Ok(Some(RPCResponse::BlocksByRoot(Vec::new()))), + "1" => Err(RPCError::Custom( + "Status stream terminated unexpectedly, empty block".into(), + )), // cannot have an empty block message. _ => unreachable!("Cannot negotiate an unknown version"), }, _ => unreachable!("Cannot negotiate an unknown protocol"), @@ -199,11 +208,15 @@ impl Decoder for SSZOutboundCodec { Err(RPCError::InvalidProtocol("GOODBYE doesn't have a response")) } RPC_BLOCKS_BY_RANGE => match self.protocol.version.as_str() { - "1" => Ok(Some(RPCResponse::BlocksByRange(raw_bytes.to_vec()))), + "1" => Ok(Some(RPCResponse::BlocksByRange(Box::new( + SignedBeaconBlock::from_ssz_bytes(&raw_bytes)?, + )))), _ => unreachable!("Cannot negotiate an unknown version"), }, RPC_BLOCKS_BY_ROOT => match self.protocol.version.as_str() { - "1" => Ok(Some(RPCResponse::BlocksByRoot(raw_bytes.to_vec()))), + "1" => Ok(Some(RPCResponse::BlocksByRoot(Box::new( + SignedBeaconBlock::from_ssz_bytes(&raw_bytes)?, + )))), _ => unreachable!("Cannot negotiate an unknown version"), }, _ => unreachable!("Cannot negotiate an unknown protocol"), @@ -216,7 +229,7 @@ impl Decoder for SSZOutboundCodec { } } -impl OutboundCodec for SSZOutboundCodec { +impl OutboundCodec for SSZOutboundCodec { type ErrorType = ErrorMessage; fn decode_error(&mut self, src: &mut BytesMut) -> Result, RPCError> { diff --git a/beacon_node/eth2-libp2p/src/rpc/handler.rs b/beacon_node/eth2-libp2p/src/rpc/handler.rs index 72c0379d4..83b82edc6 100644 --- a/beacon_node/eth2-libp2p/src/rpc/handler.rs +++ b/beacon_node/eth2-libp2p/src/rpc/handler.rs @@ -18,6 +18,7 @@ use std::collections::hash_map::Entry; use std::time::{Duration, Instant}; use tokio::io::{AsyncRead, AsyncWrite}; use tokio::timer::{delay_queue, DelayQueue}; +use types::EthSpec; //TODO: Implement close() on the substream types to improve the poll code. //TODO: Implement check_timeout() on the substream types @@ -36,42 +37,50 @@ type InboundRequestId = RequestId; type OutboundRequestId = RequestId; /// Implementation of `ProtocolsHandler` for the RPC protocol. -pub struct RPCHandler +pub struct RPCHandler where TSubstream: AsyncRead + AsyncWrite, + TSpec: EthSpec, { /// The upgrade for inbound substreams. - listen_protocol: SubstreamProtocol, + listen_protocol: SubstreamProtocol>, /// If something bad happened and we should shut down the handler with an error. pending_error: Vec<(RequestId, ProtocolsHandlerUpgrErr)>, /// Queue of events to produce in `poll()`. - events_out: SmallVec<[RPCEvent; 4]>, + events_out: SmallVec<[RPCEvent; 4]>, /// Queue of outbound substreams to open. - dial_queue: SmallVec<[RPCEvent; 4]>, + dial_queue: SmallVec<[RPCEvent; 4]>, /// Current number of concurrent outbound substreams being opened. dial_negotiated: u32, /// Current inbound substreams awaiting processing. - inbound_substreams: - FnvHashMap, Option)>, + inbound_substreams: FnvHashMap< + InboundRequestId, + ( + InboundSubstreamState, + Option, + ), + >, /// Inbound substream `DelayQueue` which keeps track of when an inbound substream will timeout. inbound_substreams_delay: DelayQueue, /// Map of outbound substreams that need to be driven to completion. The `RequestId` is /// maintained by the application sending the request. - outbound_substreams: - FnvHashMap, delay_queue::Key)>, + outbound_substreams: FnvHashMap< + OutboundRequestId, + (OutboundSubstreamState, delay_queue::Key), + >, /// Inbound substream `DelayQueue` which keeps track of when an inbound substream will timeout. outbound_substreams_delay: DelayQueue, /// Map of outbound items that are queued as the stream processes them. - queued_outbound_items: FnvHashMap>, + queued_outbound_items: FnvHashMap>>, /// Sequential ID for waiting substreams. For inbound substreams, this is also the inbound request ID. current_inbound_substream_id: RequestId, @@ -97,14 +106,15 @@ where } /// State of an outbound substream. Either waiting for a response, or in the process of sending. -pub enum InboundSubstreamState +pub enum InboundSubstreamState where TSubstream: AsyncRead + AsyncWrite, + TSpec: EthSpec, { /// A response has been sent, pending writing and flush. ResponsePendingSend { /// The substream used to send the response - substream: futures::sink::Send>, + substream: futures::sink::Send>, /// Whether a stream termination is requested. If true the stream will be closed after /// this send. Otherwise it will transition to an idle state until a stream termination is /// requested or a timeout is reached. @@ -112,40 +122,41 @@ where }, /// The response stream is idle and awaiting input from the application to send more chunked /// responses. - ResponseIdle(InboundFramed), + ResponseIdle(InboundFramed), /// The substream is attempting to shutdown. - Closing(InboundFramed), + Closing(InboundFramed), /// Temporary state during processing Poisoned, } -pub enum OutboundSubstreamState { +pub enum OutboundSubstreamState { /// A request has been sent, and we are awaiting a response. This future is driven in the /// handler because GOODBYE requests can be handled and responses dropped instantly. RequestPendingResponse { /// The framed negotiated substream. - substream: OutboundFramed, + substream: OutboundFramed, /// Keeps track of the actual request sent. - request: RPCRequest, + request: RPCRequest, }, /// Closing an outbound substream> - Closing(OutboundFramed), + Closing(OutboundFramed), /// Temporary state during processing Poisoned, } -impl InboundSubstreamState +impl InboundSubstreamState where TSubstream: AsyncRead + AsyncWrite, + TSpec: EthSpec, { /// Moves the substream state to closing and informs the connected peer. The /// `queued_outbound_items` must be given as a parameter to add stream termination messages to /// the outbound queue. - pub fn close(&mut self, outbound_queue: &mut Vec) { + pub fn close(&mut self, outbound_queue: &mut Vec>) { // When terminating a stream, report the stream termination to the requesting user via // an RPC error let error = RPCErrorResponse::ServerError(ErrorMessage { - error_message: b"Request timed out".to_vec(), + error_message: "Request timed out".as_bytes().to_vec(), }); // The stream termination type is irrelevant, this will terminate the @@ -163,16 +174,11 @@ where *self = InboundSubstreamState::ResponsePendingSend { substream, closing } } - InboundSubstreamState::ResponseIdle(mut substream) => { - // check if the stream is already closed - if let Ok(Async::Ready(None)) = substream.poll() { - *self = InboundSubstreamState::Closing(substream); - } else { - *self = InboundSubstreamState::ResponsePendingSend { - substream: substream.send(error), - closing: true, - }; - } + InboundSubstreamState::ResponseIdle(substream) => { + *self = InboundSubstreamState::ResponsePendingSend { + substream: substream.send(error), + closing: true, + }; } InboundSubstreamState::Closing(substream) => { // let the stream close @@ -185,12 +191,13 @@ where } } -impl RPCHandler +impl RPCHandler where TSubstream: AsyncRead + AsyncWrite, + TSpec: EthSpec, { pub fn new( - listen_protocol: SubstreamProtocol, + listen_protocol: SubstreamProtocol>, inactive_timeout: Duration, log: &slog::Logger, ) -> Self { @@ -224,7 +231,7 @@ where /// /// > **Note**: If you modify the protocol, modifications will only applies to future inbound /// > substreams, not the ones already being negotiated. - pub fn listen_protocol_ref(&self) -> &SubstreamProtocol { + pub fn listen_protocol_ref(&self) -> &SubstreamProtocol> { &self.listen_protocol } @@ -232,29 +239,30 @@ where /// /// > **Note**: If you modify the protocol, modifications will only applies to future inbound /// > substreams, not the ones already being negotiated. - pub fn listen_protocol_mut(&mut self) -> &mut SubstreamProtocol { + pub fn listen_protocol_mut(&mut self) -> &mut SubstreamProtocol> { &mut self.listen_protocol } /// Opens an outbound substream with a request. - pub fn send_request(&mut self, rpc_event: RPCEvent) { + pub fn send_request(&mut self, rpc_event: RPCEvent) { self.keep_alive = KeepAlive::Yes; self.dial_queue.push(rpc_event); } } -impl ProtocolsHandler for RPCHandler +impl ProtocolsHandler for RPCHandler where TSubstream: AsyncRead + AsyncWrite, + TSpec: EthSpec, { - type InEvent = RPCEvent; - type OutEvent = RPCEvent; + type InEvent = RPCEvent; + type OutEvent = RPCEvent; type Error = ProtocolsHandlerUpgrErr; type Substream = TSubstream; - type InboundProtocol = RPCProtocol; - type OutboundProtocol = RPCRequest; - type OutboundOpenInfo = RPCEvent; // Keep track of the id and the request + type InboundProtocol = RPCProtocol; + type OutboundProtocol = RPCRequest; + type OutboundOpenInfo = RPCEvent; // Keep track of the id and the request fn listen_protocol(&self) -> SubstreamProtocol { self.listen_protocol.clone() @@ -262,7 +270,7 @@ where fn inject_fully_negotiated_inbound( &mut self, - out: >::Output, + out: as InboundUpgrade>::Output, ) { // update the keep alive timeout if there are no more remaining outbound streams if let KeepAlive::Until(_) = self.keep_alive { @@ -294,7 +302,7 @@ where fn inject_fully_negotiated_outbound( &mut self, - out: >::Output, + out: as OutboundUpgrade>::Output, rpc_event: Self::OutboundOpenInfo, ) { self.dial_negotiated -= 1; @@ -748,11 +756,11 @@ where } // Check for new items to send to the peer and update the underlying stream -fn apply_queued_responses( - raw_substream: InboundFramed, - queued_outbound_items: &mut Option<&mut Vec>, +fn apply_queued_responses( + raw_substream: InboundFramed, + queued_outbound_items: &mut Option<&mut Vec>>, new_items_to_send: &mut bool, -) -> InboundSubstreamState { +) -> InboundSubstreamState { match queued_outbound_items { Some(ref mut queue) if !queue.is_empty() => { *new_items_to_send = true; diff --git a/beacon_node/eth2-libp2p/src/rpc/methods.rs b/beacon_node/eth2-libp2p/src/rpc/methods.rs index 0c16e99cc..a98be9624 100644 --- a/beacon_node/eth2-libp2p/src/rpc/methods.rs +++ b/beacon_node/eth2-libp2p/src/rpc/methods.rs @@ -1,7 +1,7 @@ //! Available RPC methods types and ids. use ssz_derive::{Decode, Encode}; -use types::{Epoch, Hash256, Slot}; +use types::{Epoch, EthSpec, Hash256, SignedBeaconBlock, Slot}; /* Request/Response data structures for RPC methods */ @@ -129,16 +129,16 @@ pub struct BlocksByRootRequest { // Collection of enums and structs used by the Codecs to encode/decode RPC messages #[derive(Debug, Clone, PartialEq)] -pub enum RPCResponse { +pub enum RPCResponse { /// A HELLO message. Status(StatusMessage), /// A response to a get BLOCKS_BY_RANGE request. A None response signifies the end of the /// batch. - BlocksByRange(Vec), + BlocksByRange(Box>), /// A response to a get BLOCKS_BY_ROOT request. - BlocksByRoot(Vec), + BlocksByRoot(Box>), } /// Indicates which response is being terminated by a stream termination response. @@ -152,9 +152,9 @@ pub enum ResponseTermination { } #[derive(Debug)] -pub enum RPCErrorResponse { +pub enum RPCErrorResponse { /// The response is a successful. - Success(RPCResponse), + Success(RPCResponse), /// The response was invalid. InvalidRequest(ErrorMessage), @@ -169,7 +169,7 @@ pub enum RPCErrorResponse { StreamTermination(ResponseTermination), } -impl RPCErrorResponse { +impl RPCErrorResponse { /// Used to encode the response in the codec. pub fn as_u8(&self) -> Option { match self { @@ -242,17 +242,21 @@ impl std::fmt::Display for StatusMessage { } } -impl std::fmt::Display for RPCResponse { +impl std::fmt::Display for RPCResponse { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { RPCResponse::Status(status) => write!(f, "{}", status), - RPCResponse::BlocksByRange(_) => write!(f, ""), - RPCResponse::BlocksByRoot(_) => write!(f, ""), + RPCResponse::BlocksByRange(block) => { + write!(f, "BlocksByRange: Block slot: {}", block.message.slot) + } + RPCResponse::BlocksByRoot(block) => { + write!(f, "BlocksByRoot: BLock slot: {}", block.message.slot) + } } } } -impl std::fmt::Display for RPCErrorResponse { +impl std::fmt::Display for RPCErrorResponse { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { RPCErrorResponse::Success(res) => write!(f, "{}", res), diff --git a/beacon_node/eth2-libp2p/src/rpc/mod.rs b/beacon_node/eth2-libp2p/src/rpc/mod.rs index bfd87b9dd..2beae12d0 100644 --- a/beacon_node/eth2-libp2p/src/rpc/mod.rs +++ b/beacon_node/eth2-libp2p/src/rpc/mod.rs @@ -20,6 +20,7 @@ use slog::o; use std::marker::PhantomData; use std::time::Duration; use tokio::io::{AsyncRead, AsyncWrite}; +use types::EthSpec; pub(crate) mod codec; mod handler; @@ -28,19 +29,19 @@ mod protocol; /// The return type used in the behaviour and the resultant event from the protocols handler. #[derive(Debug)] -pub enum RPCEvent { +pub enum RPCEvent { /// An inbound/outbound request for RPC protocol. The first parameter is a sequential /// id which tracks an awaiting substream for the response. - Request(RequestId, RPCRequest), + Request(RequestId, RPCRequest), /// A response that is being sent or has been received from the RPC protocol. The first parameter returns /// that which was sent with the corresponding request, the second is a single chunk of a /// response. - Response(RequestId, RPCErrorResponse), + Response(RequestId, RPCErrorResponse), /// An Error occurred. Error(RequestId, RPCError), } -impl RPCEvent { +impl RPCEvent { pub fn id(&self) -> usize { match *self { RPCEvent::Request(id, _) => id, @@ -50,7 +51,7 @@ impl RPCEvent { } } -impl std::fmt::Display for RPCEvent { +impl std::fmt::Display for RPCEvent { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { RPCEvent::Request(id, req) => write!(f, "RPC Request(id: {}, {})", id, req), @@ -62,16 +63,16 @@ impl std::fmt::Display for RPCEvent { /// Implements the libp2p `NetworkBehaviour` trait and therefore manages network-level /// logic. -pub struct RPC { +pub struct RPC { /// Queue of events to processed. - events: Vec>, + events: Vec, RPCMessage>>, /// Pins the generic substream. marker: PhantomData, /// Slog logger for RPC behaviour. log: slog::Logger, } -impl RPC { +impl RPC { pub fn new(log: slog::Logger) -> Self { let log = log.new(o!("service" => "libp2p_rpc")); RPC { @@ -84,7 +85,7 @@ impl RPC { /// Submits an RPC request. /// /// The peer must be connected for this to succeed. - pub fn send_rpc(&mut self, peer_id: PeerId, rpc_event: RPCEvent) { + pub fn send_rpc(&mut self, peer_id: PeerId, rpc_event: RPCEvent) { self.events.push(NetworkBehaviourAction::SendEvent { peer_id, event: rpc_event, @@ -92,16 +93,19 @@ impl RPC { } } -impl NetworkBehaviour for RPC +impl NetworkBehaviour for RPC where TSubstream: AsyncRead + AsyncWrite, + TSpec: EthSpec, { - type ProtocolsHandler = RPCHandler; - type OutEvent = RPCMessage; + type ProtocolsHandler = RPCHandler; + type OutEvent = RPCMessage; fn new_handler(&mut self) -> Self::ProtocolsHandler { RPCHandler::new( - SubstreamProtocol::new(RPCProtocol), + SubstreamProtocol::new(RPCProtocol { + phantom: PhantomData, + }), Duration::from_secs(30), &self.log, ) @@ -157,8 +161,8 @@ where } /// Messages sent to the user from the RPC protocol. -pub enum RPCMessage { - RPC(PeerId, RPCEvent), +pub enum RPCMessage { + RPC(PeerId, RPCEvent), PeerDialed(PeerId), PeerDisconnected(PeerId), } diff --git a/beacon_node/eth2-libp2p/src/rpc/protocol.rs b/beacon_node/eth2-libp2p/src/rpc/protocol.rs index 003770af9..e077fd740 100644 --- a/beacon_node/eth2-libp2p/src/rpc/protocol.rs +++ b/beacon_node/eth2-libp2p/src/rpc/protocol.rs @@ -15,6 +15,7 @@ use futures::{ }; use libp2p::core::{upgrade, InboundUpgrade, OutboundUpgrade, ProtocolName, UpgradeInfo}; use std::io; +use std::marker::PhantomData; use std::time::Duration; use tokio::codec::Framed; use tokio::io::{AsyncRead, AsyncWrite}; @@ -22,6 +23,7 @@ use tokio::prelude::*; use tokio::timer::timeout; use tokio::util::FutureExt; use tokio_io_timeout::TimeoutStream; +use types::EthSpec; /// The maximum bytes that can be sent across the RPC. const MAX_RPC_SIZE: usize = 4_194_304; // 4M @@ -44,9 +46,11 @@ pub const RPC_BLOCKS_BY_RANGE: &str = "beacon_blocks_by_range"; pub const RPC_BLOCKS_BY_ROOT: &str = "beacon_blocks_by_root"; #[derive(Debug, Clone)] -pub struct RPCProtocol; +pub struct RPCProtocol { + pub phantom: PhantomData, +} -impl UpgradeInfo for RPCProtocol { +impl UpgradeInfo for RPCProtocol { type Info = ProtocolId; type InfoIter = Vec; @@ -104,27 +108,30 @@ impl ProtocolName for ProtocolId { // The inbound protocol reads the request, decodes it and returns the stream to the protocol // handler to respond to once ready. -pub type InboundOutput = (RPCRequest, InboundFramed); -pub type InboundFramed = Framed>, InboundCodec>; -type FnAndThen = fn( - (Option, InboundFramed), -) -> FutureResult, RPCError>; -type FnMapErr = fn(timeout::Error<(RPCError, InboundFramed)>) -> RPCError; +pub type InboundOutput = (RPCRequest, InboundFramed); +pub type InboundFramed = + Framed>, InboundCodec>; +type FnAndThen = fn( + (Option>, InboundFramed), +) -> FutureResult, RPCError>; +type FnMapErr = + fn(timeout::Error<(RPCError, InboundFramed)>) -> RPCError; -impl InboundUpgrade for RPCProtocol +impl InboundUpgrade for RPCProtocol where TSocket: AsyncRead + AsyncWrite, + TSpec: EthSpec, { - type Output = InboundOutput; + type Output = InboundOutput; type Error = RPCError; type Future = future::AndThen< future::MapErr< - timeout::Timeout>>, - FnMapErr, + timeout::Timeout>>, + FnMapErr, >, - FutureResult, RPCError>, - FnAndThen, + FutureResult, RPCError>, + FnAndThen, >; fn upgrade_inbound( @@ -141,7 +148,7 @@ where Framed::new(timed_socket, codec) .into_future() .timeout(Duration::from_secs(REQUEST_TIMEOUT)) - .map_err(RPCError::from as FnMapErr) + .map_err(RPCError::from as FnMapErr) .and_then({ |(req, stream)| match req { Some(req) => futures::future::ok((req, stream)), @@ -149,7 +156,7 @@ where "Stream terminated early".into(), )), } - } as FnAndThen) + } as FnAndThen) } } } @@ -161,14 +168,15 @@ where // `OutboundUpgrade` #[derive(Debug, Clone, PartialEq)] -pub enum RPCRequest { +pub enum RPCRequest { Status(StatusMessage), Goodbye(GoodbyeReason), BlocksByRange(BlocksByRangeRequest), BlocksByRoot(BlocksByRootRequest), + Phantom(PhantomData), } -impl UpgradeInfo for RPCRequest { +impl UpgradeInfo for RPCRequest { type Info = ProtocolId; type InfoIter = Vec; @@ -179,7 +187,7 @@ impl UpgradeInfo for RPCRequest { } /// Implements the encoding per supported protocol for RPCRequest. -impl RPCRequest { +impl RPCRequest { pub fn supported_protocols(&self) -> Vec { match self { // add more protocols when versions/encodings are supported @@ -187,6 +195,7 @@ impl RPCRequest { RPCRequest::Goodbye(_) => vec![ProtocolId::new(RPC_GOODBYE, "1", "ssz")], RPCRequest::BlocksByRange(_) => vec![ProtocolId::new(RPC_BLOCKS_BY_RANGE, "1", "ssz")], RPCRequest::BlocksByRoot(_) => vec![ProtocolId::new(RPC_BLOCKS_BY_ROOT, "1", "ssz")], + RPCRequest::Phantom(_) => Vec::new(), } } @@ -200,6 +209,7 @@ impl RPCRequest { RPCRequest::Goodbye(_) => false, RPCRequest::BlocksByRange(_) => true, RPCRequest::BlocksByRoot(_) => true, + RPCRequest::Phantom(_) => unreachable!("Phantom should never be initialised"), } } @@ -211,6 +221,7 @@ impl RPCRequest { RPCRequest::Goodbye(_) => false, RPCRequest::BlocksByRange(_) => true, RPCRequest::BlocksByRoot(_) => true, + RPCRequest::Phantom(_) => unreachable!("Phantom should never be initialised"), } } @@ -224,6 +235,7 @@ impl RPCRequest { RPCRequest::BlocksByRoot(_) => ResponseTermination::BlocksByRoot, RPCRequest::Status(_) => unreachable!(), RPCRequest::Goodbye(_) => unreachable!(), + RPCRequest::Phantom(_) => unreachable!("Phantom should never be initialised"), } } } @@ -232,15 +244,17 @@ impl RPCRequest { /* Outbound upgrades */ -pub type OutboundFramed = Framed, OutboundCodec>; +pub type OutboundFramed = + Framed, OutboundCodec>; -impl OutboundUpgrade for RPCRequest +impl OutboundUpgrade for RPCRequest where + TSpec: EthSpec, TSocket: AsyncRead + AsyncWrite, { - type Output = OutboundFramed; + type Output = OutboundFramed; type Error = RPCError; - type Future = sink::Send>; + type Future = sink::Send>; fn upgrade_outbound( self, socket: upgrade::Negotiated, @@ -340,13 +354,14 @@ impl std::error::Error for RPCError { } } -impl std::fmt::Display for RPCRequest { +impl std::fmt::Display for RPCRequest { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { RPCRequest::Status(status) => write!(f, "Status Message: {}", status), RPCRequest::Goodbye(reason) => write!(f, "Goodbye: {}", reason), RPCRequest::BlocksByRange(req) => write!(f, "Blocks by range: {}", req), RPCRequest::BlocksByRoot(req) => write!(f, "Blocks by root: {:?}", req), + RPCRequest::Phantom(_) => unreachable!("Phantom should never be initialised"), } } } diff --git a/beacon_node/eth2-libp2p/src/service.rs b/beacon_node/eth2-libp2p/src/service.rs index f9d5f7210..6a2fc48c6 100644 --- a/beacon_node/eth2-libp2p/src/service.rs +++ b/beacon_node/eth2-libp2p/src/service.rs @@ -1,9 +1,9 @@ -use crate::behaviour::{Behaviour, BehaviourEvent, PubsubMessage}; -use crate::error; +use crate::behaviour::{Behaviour, BehaviourEvent}; use crate::multiaddr::Protocol; use crate::rpc::RPCEvent; +use crate::types::error; use crate::NetworkConfig; -use crate::{NetworkGlobals, Topic, TopicHash}; +use crate::{NetworkGlobals, PubsubMessage, TopicHash}; use futures::prelude::*; use futures::Stream; use libp2p::core::{ @@ -24,9 +24,10 @@ use std::io::{Error, ErrorKind}; use std::sync::Arc; use std::time::Duration; use tokio::timer::DelayQueue; +use types::EthSpec; type Libp2pStream = Boxed<(PeerId, StreamMuxerBox), Error>; -type Libp2pBehaviour = Behaviour>; +type Libp2pBehaviour = Behaviour, TSpec>; const NETWORK_KEY_FILENAME: &str = "key"; /// The time in milliseconds to wait before banning a peer. This allows for any Goodbye messages to be @@ -34,10 +35,10 @@ const NETWORK_KEY_FILENAME: &str = "key"; const BAN_PEER_WAIT_TIMEOUT: u64 = 200; /// The configuration and state of the libp2p components for the beacon node. -pub struct Service { +pub struct Service { /// The libp2p Swarm handler. //TODO: Make this private - pub swarm: Swarm, + pub swarm: Swarm>, /// This node's PeerId. pub local_peer_id: PeerId, @@ -52,11 +53,11 @@ pub struct Service { pub log: slog::Logger, } -impl Service { +impl Service { pub fn new( config: &NetworkConfig, log: slog::Logger, - ) -> error::Result<(Arc, Self)> { + ) -> error::Result<(Arc>, Self)> { trace!(log, "Libp2p Service starting"); let local_keypair = if let Some(hex_bytes) = &config.secret_key_hex { @@ -70,7 +71,11 @@ impl Service { info!(log, "Libp2p Service"; "peer_id" => format!("{:?}", local_peer_id)); // set up a collection of variables accessible outside of the network crate - let network_globals = Arc::new(NetworkGlobals::new(local_peer_id.clone())); + let network_globals = Arc::new(NetworkGlobals::new( + local_peer_id.clone(), + config.libp2p_port, + config.discovery_port, + )); let mut swarm = { // Set up the transport - tcp/ws with noise/secio and mplex/yamux @@ -133,12 +138,15 @@ impl Service { } let mut subscribed_topics: Vec = vec![]; - for topic in config.topics.clone() { - let raw_topic: Topic = topic.into(); - let topic_string = raw_topic.no_hash(); - if swarm.subscribe(raw_topic.clone()) { + for topic in &config.topics { + let topic_string: String = topic.clone().into(); + if swarm.subscribe(topic.clone()) { trace!(log, "Subscribed to topic"; "topic" => format!("{}", topic_string)); - subscribed_topics.push(topic_string.as_str().into()); + subscribed_topics.push(topic_string); + network_globals + .gossipsub_subscriptions + .write() + .push(topic.clone()); } else { warn!(log, "Could not subscribe to topic"; "topic" => format!("{}",topic_string)); } @@ -167,9 +175,9 @@ impl Service { } } -impl Stream for Service { - type Item = Libp2pEvent; - type Error = crate::error::Error; +impl Stream for Service { + type Item = Libp2pEvent; + type Error = error::Error; fn poll(&mut self) -> Poll, Self::Error> { loop { @@ -313,9 +321,9 @@ fn build_transport(local_private_key: Keypair) -> Boxed<(PeerId, StreamMuxerBox) #[derive(Debug)] /// Events that can be obtained from polling the Libp2p Service. -pub enum Libp2pEvent { +pub enum Libp2pEvent { /// An RPC response request has been received on the swarm. - RPC(PeerId, RPCEvent), + RPC(PeerId, RPCEvent), /// Initiated the connection to a new peer. PeerDialed(PeerId), /// A peer has disconnected. @@ -325,7 +333,7 @@ pub enum Libp2pEvent { id: MessageId, source: PeerId, topics: Vec, - message: PubsubMessage, + message: PubsubMessage, }, /// Subscribed to peer for a topic hash. PeerSubscribed(PeerId, TopicHash), diff --git a/beacon_node/eth2-libp2p/src/topics.rs b/beacon_node/eth2-libp2p/src/topics.rs deleted file mode 100644 index 6a7ed5881..000000000 --- a/beacon_node/eth2-libp2p/src/topics.rs +++ /dev/null @@ -1,71 +0,0 @@ -use libp2p::gossipsub::Topic; -use serde_derive::{Deserialize, Serialize}; - -/// The gossipsub topic names. -// These constants form a topic name of the form /TOPIC_PREFIX/TOPIC/ENCODING_POSTFIX -// For example /eth2/beacon_block/ssz -pub const TOPIC_PREFIX: &str = "eth2"; -pub const TOPIC_ENCODING_POSTFIX: &str = "ssz"; -pub const BEACON_BLOCK_TOPIC: &str = "beacon_block"; -pub const BEACON_ATTESTATION_TOPIC: &str = "beacon_attestation"; -pub const VOLUNTARY_EXIT_TOPIC: &str = "voluntary_exit"; -pub const PROPOSER_SLASHING_TOPIC: &str = "proposer_slashing"; -pub const ATTESTER_SLASHING_TOPIC: &str = "attester_slashing"; -pub const SHARD_TOPIC_PREFIX: &str = "shard"; - -/// Enum that brings these topics into the rust type system. -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum GossipTopic { - BeaconBlock, - BeaconAttestation, - VoluntaryExit, - ProposerSlashing, - AttesterSlashing, - Shard, - Unknown(String), -} - -impl From<&str> for GossipTopic { - fn from(topic: &str) -> GossipTopic { - let topic_parts: Vec<&str> = topic.split('/').collect(); - if topic_parts.len() == 4 - && topic_parts[1] == TOPIC_PREFIX - && topic_parts[3] == TOPIC_ENCODING_POSTFIX - { - match topic_parts[2] { - BEACON_BLOCK_TOPIC => GossipTopic::BeaconBlock, - BEACON_ATTESTATION_TOPIC => GossipTopic::BeaconAttestation, - VOLUNTARY_EXIT_TOPIC => GossipTopic::VoluntaryExit, - PROPOSER_SLASHING_TOPIC => GossipTopic::ProposerSlashing, - ATTESTER_SLASHING_TOPIC => GossipTopic::AttesterSlashing, - unknown_topic => GossipTopic::Unknown(unknown_topic.into()), - } - } else { - GossipTopic::Unknown(topic.into()) - } - } -} - -impl Into for GossipTopic { - fn into(self) -> Topic { - Topic::new(self.into()) - } -} - -impl Into for GossipTopic { - fn into(self) -> String { - match self { - GossipTopic::BeaconBlock => topic_builder(BEACON_BLOCK_TOPIC), - GossipTopic::BeaconAttestation => topic_builder(BEACON_ATTESTATION_TOPIC), - GossipTopic::VoluntaryExit => topic_builder(VOLUNTARY_EXIT_TOPIC), - GossipTopic::ProposerSlashing => topic_builder(PROPOSER_SLASHING_TOPIC), - GossipTopic::AttesterSlashing => topic_builder(ATTESTER_SLASHING_TOPIC), - GossipTopic::Shard => topic_builder(SHARD_TOPIC_PREFIX), - GossipTopic::Unknown(topic) => topic, - } - } -} - -fn topic_builder(topic: &'static str) -> String { - format!("/{}/{}/{}", TOPIC_PREFIX, topic, TOPIC_ENCODING_POSTFIX,) -} diff --git a/beacon_node/eth2-libp2p/src/error.rs b/beacon_node/eth2-libp2p/src/types/error.rs similarity index 100% rename from beacon_node/eth2-libp2p/src/error.rs rename to beacon_node/eth2-libp2p/src/types/error.rs diff --git a/beacon_node/eth2-libp2p/src/types/globals.rs b/beacon_node/eth2-libp2p/src/types/globals.rs new file mode 100644 index 000000000..6fa6349fe --- /dev/null +++ b/beacon_node/eth2-libp2p/src/types/globals.rs @@ -0,0 +1,68 @@ +//! A collection of variables that are accessible outside of the network thread itself. +use crate::{Enr, GossipTopic, Multiaddr, PeerId, PeerInfo}; +use parking_lot::RwLock; +use std::collections::HashMap; +use std::sync::atomic::{AtomicU16, Ordering}; +use types::EthSpec; + +pub struct NetworkGlobals { + /// The current local ENR. + pub local_enr: RwLock>, + /// The local peer_id. + pub peer_id: RwLock, + /// Listening multiaddrs. + pub listen_multiaddrs: RwLock>, + /// The tcp port that the libp2p service is listening on + pub listen_port_tcp: AtomicU16, + /// The udp port that the discovery service is listening on + pub listen_port_udp: AtomicU16, + /// The collection of currently connected peers. + pub connected_peer_set: RwLock>>, + /// The current gossipsub topic subscriptions. + pub gossipsub_subscriptions: RwLock>, +} + +impl NetworkGlobals { + pub fn new(peer_id: PeerId, tcp_port: u16, udp_port: u16) -> Self { + NetworkGlobals { + local_enr: RwLock::new(None), + peer_id: RwLock::new(peer_id), + listen_multiaddrs: RwLock::new(Vec::new()), + listen_port_tcp: AtomicU16::new(tcp_port), + listen_port_udp: AtomicU16::new(udp_port), + connected_peer_set: RwLock::new(HashMap::new()), + gossipsub_subscriptions: RwLock::new(Vec::new()), + } + } + + /// Returns the local ENR from the underlying Discv5 behaviour that external peers may connect + /// to. + pub fn local_enr(&self) -> Option { + self.local_enr.read().clone() + } + + /// Returns the local libp2p PeerID. + pub fn local_peer_id(&self) -> PeerId { + self.peer_id.read().clone() + } + + /// Returns the list of `Multiaddr` that the underlying libp2p instance is listening on. + pub fn listen_multiaddrs(&self) -> Vec { + self.listen_multiaddrs.read().clone() + } + + /// Returns the libp2p TCP port that this node has been configured to listen on. + pub fn listen_port_tcp(&self) -> u16 { + self.listen_port_tcp.load(Ordering::Relaxed) + } + + /// Returns the UDP discovery port that this node has been configured to listen on. + pub fn listen_port_udp(&self) -> u16 { + self.listen_port_udp.load(Ordering::Relaxed) + } + + /// Returns the number of libp2p connected peers. + pub fn connected_peers(&self) -> usize { + self.connected_peer_set.read().len() + } +} diff --git a/beacon_node/eth2-libp2p/src/types/mod.rs b/beacon_node/eth2-libp2p/src/types/mod.rs new file mode 100644 index 000000000..5146ecdd4 --- /dev/null +++ b/beacon_node/eth2-libp2p/src/types/mod.rs @@ -0,0 +1,10 @@ +pub mod error; +mod globals; +mod peer_info; +mod pubsub; +mod topics; + +pub use globals::NetworkGlobals; +pub use peer_info::{EnrBitfield, PeerInfo}; +pub use pubsub::{PubsubData, PubsubMessage}; +pub use topics::{GossipEncoding, GossipKind, GossipTopic}; diff --git a/beacon_node/eth2-libp2p/src/types/peer_info.rs b/beacon_node/eth2-libp2p/src/types/peer_info.rs new file mode 100644 index 000000000..1db953c13 --- /dev/null +++ b/beacon_node/eth2-libp2p/src/types/peer_info.rs @@ -0,0 +1,45 @@ +//NOTE: This should be removed in favour of the PeerManager PeerInfo, once built. + +use types::{BitVector, EthSpec, SubnetId}; + +#[allow(type_alias_bounds)] +pub type EnrBitfield = BitVector; + +/// Information about a given connected peer. +#[derive(Debug, Clone)] +pub struct PeerInfo { + /// The current syncing state of the peer. The state may be determined after it's initial + /// connection. + pub syncing_state: Option, + /// The ENR subnet bitfield of the peer. This may be determined after it's initial + /// connection. + pub enr_bitfield: Option>, +} + +#[derive(Debug, Clone)] +pub enum PeerSyncingState { + /// At the current state as our node. + Synced, + /// The peer is further ahead than our node and useful for block downloads. + Ahead, + /// Is behind our current head and not useful for block downloads. + Behind, +} + +impl PeerInfo { + /// Creates a new PeerInfo, specifying it's + pub fn new() -> Self { + PeerInfo { + syncing_state: None, + enr_bitfield: None, + } + } + + /// Returns if the peer is subscribed to a given `SubnetId` + pub fn on_subnet(&self, subnet_id: SubnetId) -> bool { + if let Some(bitfield) = &self.enr_bitfield { + return bitfield.get(*subnet_id as usize).unwrap_or_else(|_| false); + } + false + } +} diff --git a/beacon_node/eth2-libp2p/src/types/pubsub.rs b/beacon_node/eth2-libp2p/src/types/pubsub.rs new file mode 100644 index 000000000..efab328f2 --- /dev/null +++ b/beacon_node/eth2-libp2p/src/types/pubsub.rs @@ -0,0 +1,170 @@ +//! Handles the encoding and decoding of pubsub messages. + +use crate::types::{GossipEncoding, GossipKind, GossipTopic}; +use crate::TopicHash; +use ssz::{Decode, Encode}; +use std::boxed::Box; +use types::SubnetId; +use types::{ + Attestation, AttesterSlashing, EthSpec, ProposerSlashing, SignedAggregateAndProof, + SignedBeaconBlock, VoluntaryExit, +}; + +/// Messages that are passed to and from the pubsub (Gossipsub) behaviour. +#[derive(Debug, Clone, PartialEq)] +pub struct PubsubMessage { + /// The encoding to be used to encode/decode the message + pub encoding: GossipEncoding, + /// The actual message being sent. + pub data: PubsubData, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum PubsubData { + /// Gossipsub message providing notification of a new block. + BeaconBlock(Box>), + /// Gossipsub message providing notification of a Aggregate attestation and associated proof. + AggregateAndProofAttestation(Box>), + /// Gossipsub message providing notification of a raw un-aggregated attestation with its shard id. + Attestation(Box<(SubnetId, Attestation)>), + /// Gossipsub message providing notification of a voluntary exit. + VoluntaryExit(Box), + /// Gossipsub message providing notification of a new proposer slashing. + ProposerSlashing(Box), + /// Gossipsub message providing notification of a new attester slashing. + AttesterSlashing(Box>), +} + +impl PubsubMessage { + pub fn new(encoding: GossipEncoding, data: PubsubData) -> Self { + PubsubMessage { encoding, data } + } + + /// Returns the topics that each pubsub message will be sent across, given a supported + /// gossipsub encoding. + pub fn topics(&self) -> Vec { + let encoding = self.encoding.clone(); + match &self.data { + PubsubData::BeaconBlock(_) => vec![GossipTopic::new(GossipKind::BeaconBlock, encoding)], + PubsubData::AggregateAndProofAttestation(_) => vec![GossipTopic::new( + GossipKind::BeaconAggregateAndProof, + encoding, + )], + PubsubData::Attestation(attestation_data) => vec![GossipTopic::new( + GossipKind::CommitteeIndex(attestation_data.0), + encoding, + )], + PubsubData::VoluntaryExit(_) => { + vec![GossipTopic::new(GossipKind::VoluntaryExit, encoding)] + } + PubsubData::ProposerSlashing(_) => { + vec![GossipTopic::new(GossipKind::ProposerSlashing, encoding)] + } + PubsubData::AttesterSlashing(_) => { + vec![GossipTopic::new(GossipKind::AttesterSlashing, encoding)] + } + } + } + + /* Note: This is assuming we are not hashing topics. If we choose to hash topics, these will + * need to be modified. + * + * Also note that a message can be associated with many topics. As soon as one of the topics is + * known we match. If none of the topics are known we return an unknown state. + */ + pub fn decode(topics: &[TopicHash], data: &[u8]) -> Result { + let mut unknown_topics = Vec::new(); + for topic in topics { + match GossipTopic::decode(topic.as_str()) { + Err(_) => { + unknown_topics.push(topic); + continue; + } + Ok(gossip_topic) => { + match gossip_topic.encoding() { + // group each part by encoding type + GossipEncoding::SSZ => { + // the ssz decoders + let encoding = GossipEncoding::SSZ; + match gossip_topic.kind() { + GossipKind::BeaconAggregateAndProof => { + let agg_and_proof = + SignedAggregateAndProof::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?; + return Ok(PubsubMessage::new( + encoding, + PubsubData::AggregateAndProofAttestation(Box::new( + agg_and_proof, + )), + )); + } + GossipKind::CommitteeIndex(subnet_id) => { + let attestation = Attestation::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?; + return Ok(PubsubMessage::new( + encoding, + PubsubData::Attestation(Box::new(( + *subnet_id, + attestation, + ))), + )); + } + GossipKind::BeaconBlock => { + let beacon_block = SignedBeaconBlock::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?; + return Ok(PubsubMessage::new( + encoding, + PubsubData::BeaconBlock(Box::new(beacon_block)), + )); + } + GossipKind::VoluntaryExit => { + let voluntary_exit = VoluntaryExit::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?; + return Ok(PubsubMessage::new( + encoding, + PubsubData::VoluntaryExit(Box::new(voluntary_exit)), + )); + } + GossipKind::ProposerSlashing => { + let proposer_slashing = ProposerSlashing::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?; + return Ok(PubsubMessage::new( + encoding, + PubsubData::ProposerSlashing(Box::new(proposer_slashing)), + )); + } + GossipKind::AttesterSlashing => { + let attester_slashing = AttesterSlashing::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?; + return Ok(PubsubMessage::new( + encoding, + PubsubData::AttesterSlashing(Box::new(attester_slashing)), + )); + } + } + } + } + } + } + } + Err(format!("Unknown gossipsub topics: {:?}", unknown_topics)) + } + + /// Encodes a pubsub message based on the topic encodings. The first known encoding is used. If + /// no encoding is known, and error is returned. + pub fn encode(&self) -> Vec { + match self.encoding { + GossipEncoding::SSZ => { + // SSZ Encodings + return match &self.data { + PubsubData::BeaconBlock(data) => data.as_ssz_bytes(), + PubsubData::AggregateAndProofAttestation(data) => data.as_ssz_bytes(), + PubsubData::VoluntaryExit(data) => data.as_ssz_bytes(), + PubsubData::ProposerSlashing(data) => data.as_ssz_bytes(), + PubsubData::AttesterSlashing(data) => data.as_ssz_bytes(), + PubsubData::Attestation(data) => data.1.as_ssz_bytes(), + }; + } + } + } +} diff --git a/beacon_node/eth2-libp2p/src/types/topics.rs b/beacon_node/eth2-libp2p/src/types/topics.rs new file mode 100644 index 000000000..98844a811 --- /dev/null +++ b/beacon_node/eth2-libp2p/src/types/topics.rs @@ -0,0 +1,140 @@ +use libp2p::gossipsub::Topic; +use serde_derive::{Deserialize, Serialize}; +use types::SubnetId; + +/// The gossipsub topic names. +// These constants form a topic name of the form /TOPIC_PREFIX/TOPIC/ENCODING_POSTFIX +// For example /eth2/beacon_block/ssz +pub const TOPIC_PREFIX: &str = "eth2"; +pub const SSZ_ENCODING_POSTFIX: &str = "ssz"; +pub const BEACON_BLOCK_TOPIC: &str = "beacon_block"; +pub const BEACON_AGGREGATE_AND_PROOF_TOPIC: &str = "beacon_aggregate_and_proof"; +// for speed and easier string manipulation, committee topic index is split into a prefix and a +// postfix. The topic is committee_index{}_beacon_attestation where {} is an integer. +pub const COMMITEE_INDEX_TOPIC_PREFIX: &str = "committee_index"; +pub const COMMITEE_INDEX_TOPIC_POSTFIX: &str = "_beacon_attestation"; +pub const VOLUNTARY_EXIT_TOPIC: &str = "voluntary_exit"; +pub const PROPOSER_SLASHING_TOPIC: &str = "proposer_slashing"; +pub const ATTESTER_SLASHING_TOPIC: &str = "attester_slashing"; + +/// A gossipsub topic which encapsulates the type of messages that should be sent and received over +/// the pubsub protocol and the way the messages should be encoded. +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct GossipTopic { + /// The encoding of the topic. + encoding: GossipEncoding, + /// The kind of topic. + kind: GossipKind, +} + +/// Enum that brings these topics into the rust type system. +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub enum GossipKind { + /// Topic for publishing beacon blocks. + BeaconBlock, + /// Topic for publishing aggregate attestations and proofs. + BeaconAggregateAndProof, + /// Topic for publishing raw attestations on a particular subnet. + CommitteeIndex(SubnetId), + /// Topic for publishing voluntary exits. + VoluntaryExit, + /// Topic for publishing block proposer slashings. + ProposerSlashing, + /// Topic for publishing attester slashings. + AttesterSlashing, +} + +/// The known encoding types for gossipsub messages. +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub enum GossipEncoding { + /// Messages are encoded with SSZ. + SSZ, +} + +impl GossipTopic { + pub fn new(kind: GossipKind, encoding: GossipEncoding) -> Self { + GossipTopic { encoding, kind } + } + + /// Returns the encoding type for the gossipsub topic. + pub fn encoding(&self) -> &GossipEncoding { + &self.encoding + } + + /// Returns the kind of message expected on the gossipsub topic. + pub fn kind(&self) -> &GossipKind { + &self.kind + } + + pub fn decode(topic: &str) -> Result { + let topic_parts: Vec<&str> = topic.split('/').collect(); + if topic_parts.len() == 4 && topic_parts[1] == TOPIC_PREFIX { + let encoding = match topic_parts[3] { + SSZ_ENCODING_POSTFIX => GossipEncoding::SSZ, + _ => return Err(format!("Unknown encoding: {}", topic)), + }; + let kind = match topic_parts[2] { + BEACON_BLOCK_TOPIC => GossipKind::BeaconBlock, + BEACON_AGGREGATE_AND_PROOF_TOPIC => GossipKind::BeaconAggregateAndProof, + VOLUNTARY_EXIT_TOPIC => GossipKind::VoluntaryExit, + PROPOSER_SLASHING_TOPIC => GossipKind::ProposerSlashing, + ATTESTER_SLASHING_TOPIC => GossipKind::AttesterSlashing, + topic => match committee_topic_index(topic) { + Some(subnet_id) => GossipKind::CommitteeIndex(subnet_id), + None => return Err(format!("Unknown topic: {}", topic)), + }, + }; + + return Ok(GossipTopic { encoding, kind }); + } + + Err(format!("Unknown topic: {}", topic)) + } +} + +impl Into for GossipTopic { + fn into(self) -> Topic { + Topic::new(self.into()) + } +} + +impl Into for GossipTopic { + fn into(self) -> String { + let encoding = match self.encoding { + GossipEncoding::SSZ => SSZ_ENCODING_POSTFIX, + }; + + let kind = match self.kind { + GossipKind::BeaconBlock => BEACON_BLOCK_TOPIC.into(), + GossipKind::BeaconAggregateAndProof => BEACON_AGGREGATE_AND_PROOF_TOPIC.into(), + GossipKind::VoluntaryExit => VOLUNTARY_EXIT_TOPIC.into(), + GossipKind::ProposerSlashing => PROPOSER_SLASHING_TOPIC.into(), + GossipKind::AttesterSlashing => ATTESTER_SLASHING_TOPIC.into(), + GossipKind::CommitteeIndex(index) => format!( + "{}{}{}", + COMMITEE_INDEX_TOPIC_PREFIX, *index, COMMITEE_INDEX_TOPIC_POSTFIX + ), + }; + format!("/{}/{}/{}", TOPIC_PREFIX, kind, encoding) + } +} + +// helper functions + +// Determines if a string is a committee topic. +fn committee_topic_index(topic: &str) -> Option { + if topic.starts_with(COMMITEE_INDEX_TOPIC_PREFIX) + && topic.ends_with(COMMITEE_INDEX_TOPIC_POSTFIX) + { + return Some(SubnetId::new( + u64::from_str_radix( + topic + .trim_start_matches(COMMITEE_INDEX_TOPIC_PREFIX) + .trim_end_matches(COMMITEE_INDEX_TOPIC_POSTFIX), + 10, + ) + .ok()?, + )); + } + None +} diff --git a/beacon_node/eth2-libp2p/tests/common/mod.rs b/beacon_node/eth2-libp2p/tests/common/mod.rs index 035b6caef..ea075ff55 100644 --- a/beacon_node/eth2-libp2p/tests/common/mod.rs +++ b/beacon_node/eth2-libp2p/tests/common/mod.rs @@ -5,6 +5,9 @@ use eth2_libp2p::NetworkConfig; use eth2_libp2p::Service as LibP2PService; use slog::{debug, error, o, Drain}; use std::time::Duration; +use types::MinimalEthSpec; + +type E = MinimalEthSpec; use tempdir::TempDir; pub fn build_log(level: slog::Level, enabled: bool) -> slog::Logger { @@ -43,7 +46,7 @@ pub fn build_libp2p_instance( boot_nodes: Vec, secret_key: Option, log: slog::Logger, -) -> LibP2PService { +) -> LibP2PService { let config = build_config(port, boot_nodes, secret_key); // launch libp2p service LibP2PService::new(&config, log.clone()) @@ -52,15 +55,19 @@ pub fn build_libp2p_instance( } #[allow(dead_code)] -pub fn get_enr(node: &LibP2PService) -> Enr { +pub fn get_enr(node: &LibP2PService) -> Enr { node.swarm.discovery().local_enr().clone() } // Returns `n` libp2p peers in fully connected topology. #[allow(dead_code)] -pub fn build_full_mesh(log: slog::Logger, n: usize, start_port: Option) -> Vec { +pub fn build_full_mesh( + log: slog::Logger, + n: usize, + start_port: Option, +) -> Vec> { let base_port = start_port.unwrap_or(9000); - let mut nodes: Vec = (base_port..base_port + n as u16) + let mut nodes: Vec> = (base_port..base_port + n as u16) .map(|p| build_libp2p_instance(p, vec![], None, log.clone())) .collect(); let multiaddrs: Vec = nodes @@ -84,7 +91,10 @@ pub fn build_full_mesh(log: slog::Logger, n: usize, start_port: Option) -> // Constructs a pair of nodes with seperate loggers. The sender dials the receiver. // This returns a (sender, receiver) pair. #[allow(dead_code)] -pub fn build_node_pair(log: &slog::Logger, start_port: u16) -> (LibP2PService, LibP2PService) { +pub fn build_node_pair( + log: &slog::Logger, + start_port: u16, +) -> (LibP2PService, LibP2PService) { let sender_log = log.new(o!("who" => "sender")); let receiver_log = log.new(o!("who" => "receiver")); @@ -101,9 +111,9 @@ pub fn build_node_pair(log: &slog::Logger, start_port: u16) -> (LibP2PService, L // Returns `n` peers in a linear topology #[allow(dead_code)] -pub fn build_linear(log: slog::Logger, n: usize, start_port: Option) -> Vec { +pub fn build_linear(log: slog::Logger, n: usize, start_port: Option) -> Vec> { let base_port = start_port.unwrap_or(9000); - let mut nodes: Vec = (base_port..base_port + n as u16) + let mut nodes: Vec> = (base_port..base_port + n as u16) .map(|p| build_libp2p_instance(p, vec![], None, log.clone())) .collect(); let multiaddrs: Vec = nodes diff --git a/beacon_node/eth2-libp2p/tests/gossipsub_tests.rs b/beacon_node/eth2-libp2p/tests/gossipsub_tests.rs index 37d38f986..09f8d351d 100644 --- a/beacon_node/eth2-libp2p/tests/gossipsub_tests.rs +++ b/beacon_node/eth2-libp2p/tests/gossipsub_tests.rs @@ -1,8 +1,12 @@ #![cfg(test)] +use crate::types::GossipEncoding; +use ::types::{BeaconBlock, EthSpec, MinimalEthSpec, Signature, SignedBeaconBlock}; use eth2_libp2p::*; use futures::prelude::*; use slog::{debug, Level}; +type E = MinimalEthSpec; + mod common; /* Gossipsub tests */ @@ -23,7 +27,14 @@ fn test_gossipsub_forward() { let num_nodes = 20; let mut nodes = common::build_linear(log.clone(), num_nodes, Some(19000)); let mut received_count = 0; - let pubsub_message = PubsubMessage::Block(vec![0; 4]); + let spec = E::default_spec(); + let empty_block = BeaconBlock::empty(&spec); + let signed_block = SignedBeaconBlock { + message: empty_block, + signature: Signature::empty_signature(), + }; + let data = PubsubData::BeaconBlock(Box::new(signed_block)); + let pubsub_message = PubsubMessage::new(GossipEncoding::SSZ, data); let publishing_topic: String = "/eth2/beacon_block/ssz".into(); let mut subscribed_count = 0; tokio::run(futures::future::poll_fn(move || -> Result<_, ()> { @@ -61,10 +72,7 @@ fn test_gossipsub_forward() { subscribed_count += 1; // Every node except the corner nodes are connected to 2 nodes. if subscribed_count == (num_nodes * 2) - 2 { - node.swarm.publish( - &[Topic::new(topic.into_string())], - pubsub_message.clone(), - ); + node.swarm.publish(vec![pubsub_message.clone()]); } } } @@ -90,7 +98,14 @@ fn test_gossipsub_full_mesh_publish() { let num_nodes = 12; let mut nodes = common::build_full_mesh(log, num_nodes, Some(11320)); let mut publishing_node = nodes.pop().unwrap(); - let pubsub_message = PubsubMessage::Block(vec![0; 4]); + let spec = E::default_spec(); + let empty_block = BeaconBlock::empty(&spec); + let signed_block = SignedBeaconBlock { + message: empty_block, + signature: Signature::empty_signature(), + }; + let data = PubsubData::BeaconBlock(Box::new(signed_block)); + let pubsub_message = PubsubMessage::new(GossipEncoding::SSZ, data); let publishing_topic: String = "/eth2/beacon_block/ssz".into(); let mut subscribed_count = 0; let mut received_count = 0; @@ -123,9 +138,7 @@ fn test_gossipsub_full_mesh_publish() { if topic == TopicHash::from_raw("/eth2/beacon_block/ssz") { subscribed_count += 1; if subscribed_count == num_nodes - 1 { - publishing_node - .swarm - .publish(&[Topic::new(topic.into_string())], pubsub_message.clone()); + publishing_node.swarm.publish(vec![pubsub_message.clone()]); } } } diff --git a/beacon_node/eth2-libp2p/tests/noise.rs b/beacon_node/eth2-libp2p/tests/noise.rs index 5b322d366..4e02648ec 100644 --- a/beacon_node/eth2-libp2p/tests/noise.rs +++ b/beacon_node/eth2-libp2p/tests/noise.rs @@ -1,6 +1,7 @@ #![cfg(test)] use crate::behaviour::{Behaviour, BehaviourEvent}; use crate::multiaddr::Protocol; +use ::types::MinimalEthSpec; use eth2_libp2p::*; use futures::prelude::*; use libp2p::core::identity::Keypair; @@ -16,10 +17,12 @@ use std::sync::Arc; use std::time::Duration; use tokio::prelude::*; +type TSpec = MinimalEthSpec; + mod common; type Libp2pStream = Boxed<(PeerId, StreamMuxerBox), Error>; -type Libp2pBehaviour = Behaviour>; +type Libp2pBehaviour = Behaviour, TSpec>; /// Build and return a eth2_libp2p Swarm with only secio support. fn build_secio_swarm( @@ -29,7 +32,11 @@ fn build_secio_swarm( let local_keypair = Keypair::generate_secp256k1(); let local_peer_id = PeerId::from(local_keypair.public()); - let network_globals = Arc::new(NetworkGlobals::new(local_peer_id.clone())); + let network_globals = Arc::new(NetworkGlobals::new( + local_peer_id.clone(), + config.libp2p_port, + config.discovery_port, + )); let mut swarm = { // Set up the transport - tcp/ws with secio and mplex/yamux diff --git a/beacon_node/eth2-libp2p/tests/rpc_tests.rs b/beacon_node/eth2-libp2p/tests/rpc_tests.rs index 279cc7569..1882e0844 100644 --- a/beacon_node/eth2-libp2p/tests/rpc_tests.rs +++ b/beacon_node/eth2-libp2p/tests/rpc_tests.rs @@ -7,10 +7,14 @@ use std::sync::atomic::{AtomicBool, Ordering::Relaxed}; use std::sync::{Arc, Mutex}; use std::time::Duration; use tokio::prelude::*; -use types::{Epoch, Hash256, Slot}; +use types::{ + BeaconBlock, Epoch, EthSpec, Hash256, MinimalEthSpec, Signature, SignedBeaconBlock, Slot, +}; mod common; +type E = MinimalEthSpec; + #[test] // Tests the STATUS RPC message fn test_status_rpc() { @@ -73,7 +77,7 @@ fn test_status_rpc() { warn!(sender_log, "Sender Completed"); return Ok(Async::Ready(true)); } - _ => panic!("Received invalid RPC message"), + e => panic!("Received invalid RPC message {}", e), }, Async::Ready(Some(_)) => (), Async::Ready(None) | Async::NotReady => return Ok(Async::NotReady), @@ -98,7 +102,7 @@ fn test_status_rpc() { RPCEvent::Response(id, RPCErrorResponse::Success(rpc_response.clone())), ); } - _ => panic!("Received invalid RPC message"), + e => panic!("Received invalid RPC message {}", e), }, Async::Ready(Some(_)) => (), Async::Ready(None) | Async::NotReady => return Ok(Async::NotReady), @@ -145,7 +149,13 @@ fn test_blocks_by_range_chunked_rpc() { }); // BlocksByRange Response - let rpc_response = RPCResponse::BlocksByRange(vec![13, 13, 13]); + let spec = E::default_spec(); + let empty_block = BeaconBlock::empty(&spec); + let empty_signed = SignedBeaconBlock { + message: empty_block, + signature: Signature::empty_signature(), + }; + let rpc_response = RPCResponse::BlocksByRange(Box::new(empty_signed)); let sender_request = rpc_request.clone(); let sender_log = log.clone(); @@ -272,7 +282,13 @@ fn test_blocks_by_range_single_empty_rpc() { }); // BlocksByRange Response - let rpc_response = RPCResponse::BlocksByRange(vec![]); + let spec = E::default_spec(); + let empty_block = BeaconBlock::empty(&spec); + let empty_signed = SignedBeaconBlock { + message: empty_block, + signature: Signature::empty_signature(), + }; + let rpc_response = RPCResponse::BlocksByRange(Box::new(empty_signed)); let sender_request = rpc_request.clone(); let sender_log = log.clone(); @@ -373,132 +389,6 @@ fn test_blocks_by_range_single_empty_rpc() { assert!(test_result.load(Relaxed)); } -#[test] -// Tests a streamed, chunked BlocksByRoot RPC Message -fn test_blocks_by_root_chunked_rpc() { - // set up the logging. The level and enabled logging or not - let log_level = Level::Trace; - let enable_logging = false; - - let messages_to_send = 3; - - let log = common::build_log(log_level, enable_logging); - - // get sender/receiver - let (mut sender, mut receiver) = common::build_node_pair(&log, 10515); - - // BlocksByRoot Request - let rpc_request = RPCRequest::BlocksByRoot(BlocksByRootRequest { - block_roots: vec![Hash256::from_low_u64_be(0), Hash256::from_low_u64_be(0)], - }); - - // BlocksByRoot Response - let rpc_response = RPCResponse::BlocksByRoot(vec![13, 13, 13]); - - let sender_request = rpc_request.clone(); - let sender_log = log.clone(); - let sender_response = rpc_response.clone(); - - // keep count of the number of messages received - let messages_received = Arc::new(Mutex::new(0)); - // build the sender future - let sender_future = future::poll_fn(move || -> Poll { - loop { - match sender.poll().unwrap() { - Async::Ready(Some(Libp2pEvent::PeerDialed(peer_id))) => { - // Send a BlocksByRoot request - warn!(sender_log, "Sender sending RPC request"); - sender - .swarm - .send_rpc(peer_id, RPCEvent::Request(1, sender_request.clone())); - } - Async::Ready(Some(Libp2pEvent::RPC(_, event))) => match event { - // Should receive the RPC response - RPCEvent::Response(id, response) => { - warn!(sender_log, "Sender received a response"); - assert_eq!(id, 1); - match response { - RPCErrorResponse::Success(res) => { - assert_eq!(res, sender_response.clone()); - *messages_received.lock().unwrap() += 1; - warn!(sender_log, "Chunk received"); - } - RPCErrorResponse::StreamTermination( - ResponseTermination::BlocksByRoot, - ) => { - // should be exactly 10 messages before terminating - assert_eq!(*messages_received.lock().unwrap(), messages_to_send); - // end the test - return Ok(Async::Ready(true)); - } - m => panic!("Invalid RPC received: {}", m), - } - } - m => panic!("Received invalid RPC message: {}", m), - }, - Async::Ready(Some(_)) => {} - Async::Ready(None) | Async::NotReady => return Ok(Async::NotReady), - }; - } - }); - - // build the receiver future - let receiver_future = future::poll_fn(move || -> Poll { - loop { - match receiver.poll().unwrap() { - Async::Ready(Some(Libp2pEvent::RPC(peer_id, event))) => match event { - // Should receive the sent RPC request - RPCEvent::Request(id, request) => { - assert_eq!(id, 1); - assert_eq!(rpc_request.clone(), request); - - // send the response - warn!(log, "Receiver got request"); - - for _ in 1..=messages_to_send { - receiver.swarm.send_rpc( - peer_id.clone(), - RPCEvent::Response( - id, - RPCErrorResponse::Success(rpc_response.clone()), - ), - ); - } - // send the stream termination - receiver.swarm.send_rpc( - peer_id, - RPCEvent::Response( - id, - RPCErrorResponse::StreamTermination( - ResponseTermination::BlocksByRoot, - ), - ), - ); - } - _ => panic!("Received invalid RPC message"), - }, - Async::Ready(Some(_)) => (), - Async::Ready(None) | Async::NotReady => return Ok(Async::NotReady), - } - } - }); - - // execute the futures and check the result - let test_result = Arc::new(AtomicBool::new(false)); - let error_result = test_result.clone(); - let thread_result = test_result.clone(); - tokio::run( - sender_future - .select(receiver_future) - .timeout(Duration::from_millis(1000)) - .map_err(move |_| error_result.store(false, Relaxed)) - .map(move |result| { - thread_result.store(result.0, Relaxed); - }), - ); - assert!(test_result.load(Relaxed)); -} - #[test] // Tests a Goodbye RPC message fn test_goodbye_rpc() { diff --git a/beacon_node/genesis/Cargo.toml b/beacon_node/genesis/Cargo.toml index 7ab56a689..a5723ee6e 100644 --- a/beacon_node/genesis/Cargo.toml +++ b/beacon_node/genesis/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "genesis" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/beacon_node/network/Cargo.toml b/beacon_node/network/Cargo.toml index b299c4a27..88b1b2560 100644 --- a/beacon_node/network/Cargo.toml +++ b/beacon_node/network/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "network" -version = "0.1.0" +version = "0.2.0" authors = ["Age Manning "] edition = "2018" @@ -13,7 +13,10 @@ tempdir = "0.3" beacon_chain = { path = "../beacon_chain" } store = { path = "../store" } eth2-libp2p = { path = "../eth2-libp2p" } +hashmap_delay = { path = "../../eth2/utils/hashmap_delay" } +rest_types = { path = "../../eth2/utils/rest_types" } types = { path = "../../eth2/types" } +slot_clock = { path = "../../eth2/utils/slot_clock" } slog = { version = "2.5.2", features = ["max_level_trace"] } hex = "0.3" eth2_ssz = "0.1.2" diff --git a/beacon_node/network/src/attestation_service/mod.rs b/beacon_node/network/src/attestation_service/mod.rs new file mode 100644 index 000000000..3985afd96 --- /dev/null +++ b/beacon_node/network/src/attestation_service/mod.rs @@ -0,0 +1,575 @@ +//! This service keeps track of which shard subnet the beacon node should be subscribed to at any +//! given time. It schedules subscriptions to shard subnets, requests peer discoveries and +//! determines whether attestations should be aggregated and/or passed to the beacon node. + +use beacon_chain::{BeaconChain, BeaconChainTypes}; +use eth2_libp2p::{types::GossipKind, NetworkGlobals}; +use futures::prelude::*; +use hashmap_delay::HashSetDelay; +use rand::seq::SliceRandom; +use rest_types::ValidatorSubscription; +use slog::{crit, debug, error, o, warn}; +use slot_clock::SlotClock; +use std::boxed::Box; +use std::collections::VecDeque; +use std::sync::Arc; +use std::time::{Duration, Instant}; +use types::{Attestation, SubnetId}; +use types::{EthSpec, Slot}; + +/// The minimum number of slots ahead that we attempt to discover peers for a subscription. If the +/// slot is less than this number, skip the peer discovery process. +const MIN_PEER_DISCOVERY_SLOT_LOOK_AHEAD: u64 = 1; +/// The number of slots ahead that we attempt to discover peers for a subscription. If the slot to +/// attest to is greater than this, we queue a discovery request for this many slots prior to +/// subscribing. +const TARGET_PEER_DISCOVERY_SLOT_LOOK_AHEAD: u64 = 6; +/// The time (in seconds) before a last seen validator is considered absent and we unsubscribe from the random +/// gossip topics that we subscribed to due to the validator connection. +const LAST_SEEN_VALIDATOR_TIMEOUT: u64 = 1800; // 30 mins +/// The number of seconds in advance that we subscribe to a subnet before the required slot. +const ADVANCE_SUBSCRIBE_SECS: u64 = 3; + +#[derive(Debug, PartialEq)] +pub enum AttServiceMessage { + /// Subscribe to the specified subnet id. + Subscribe(SubnetId), + /// Unsubscribe to the specified subnet id. + Unsubscribe(SubnetId), + /// Add the `SubnetId` to the ENR bitfield. + EnrAdd(SubnetId), + /// Remove the `SubnetId` from the ENR bitfield. + EnrRemove(SubnetId), + /// Discover peers for a particular subnet. + DiscoverPeers(SubnetId), +} + +pub struct AttestationService { + /// Queued events to return to the driving service. + events: VecDeque, + + /// A collection of public network variables. + network_globals: Arc>, + + /// A reference to the beacon chain to process received attestations. + beacon_chain: Arc>, + + /// The collection of currently subscribed random subnets mapped to their expiry deadline. + random_subnets: HashSetDelay, + + /// A collection of timeouts for when to start searching for peers for a particular shard. + discover_peers: HashSetDelay<(SubnetId, Slot)>, + + /// A collection of timeouts for when to subscribe to a shard subnet. + subscriptions: HashSetDelay<(SubnetId, Slot)>, + + /// A collection of timeouts for when to unsubscribe from a shard subnet. + unsubscriptions: HashSetDelay<(SubnetId, Slot)>, + + /// A collection of seen validators. These dictate how many random subnets we should be + /// subscribed to. As these time out, we unsubscribe for the required random subnets and update + /// our ENR. + /// This is a set of validator indices. + known_validators: HashSetDelay, + + /// The logger for the attestation service. + log: slog::Logger, +} + +impl AttestationService { + /* Public functions */ + + pub fn new( + beacon_chain: Arc>, + network_globals: Arc>, + log: &slog::Logger, + ) -> Self { + let log = log.new(o!("service" => "attestation_service")); + + // calculate the random subnet duration from the spec constants + let spec = &beacon_chain.spec; + let random_subnet_duration_millis = spec + .epochs_per_random_subnet_subscription + .saturating_mul(T::EthSpec::slots_per_epoch()) + .saturating_mul(spec.milliseconds_per_slot); + + AttestationService { + events: VecDeque::with_capacity(10), + network_globals, + beacon_chain, + random_subnets: HashSetDelay::new(Duration::from_millis(random_subnet_duration_millis)), + discover_peers: HashSetDelay::default(), + subscriptions: HashSetDelay::default(), + unsubscriptions: HashSetDelay::default(), + known_validators: HashSetDelay::new(Duration::from_secs(LAST_SEEN_VALIDATOR_TIMEOUT)), + log, + } + } + + /// Processes a list of validator subscriptions. + /// + /// This will: + /// - Register new validators as being known. + /// - Subscribe to the required number of random subnets. + /// - Update the local ENR for new random subnets due to seeing new validators. + /// - Search for peers for required subnets. + /// - Request subscriptions for subnets on specific slots when required. + /// - Build the timeouts for each of these events. + /// + /// This returns a result simply for the ergonomics of using ?. The result can be + /// safely dropped. + pub fn validator_subscriptions( + &mut self, + subscriptions: Vec, + ) -> Result<(), ()> { + for subscription in subscriptions { + //NOTE: We assume all subscriptions have been verified before reaching this service + + // Registers the validator with the attestation service. + // This will subscribe to long-lived random subnets if required. + self.add_known_validator(subscription.validator_index); + + let subnet_id = SubnetId::new( + subscription.attestation_committee_index + % self.beacon_chain.spec.attestation_subnet_count, + ); + // determine if we should run a discovery lookup request and request it if required + let _ = self.discover_peers_request(subnet_id, subscription.slot); + + // set the subscription timer to subscribe to the next subnet if required + let _ = self.subscribe_to_subnet(subnet_id, subscription.slot); + } + Ok(()) + } + + pub fn handle_attestation( + &mut self, + subnet: SubnetId, + attestation: Box>, + ) { + } + + /* Internal private functions */ + + /// Checks if there are currently queued discovery requests and the time required to make the + /// request. + /// + /// If there is sufficient time and no other request exists, queues a peer discovery request + /// for the required subnet. + fn discover_peers_request( + &mut self, + subnet_id: SubnetId, + subscription_slot: Slot, + ) -> Result<(), ()> { + let current_slot = self.beacon_chain.slot_clock.now().ok_or_else(|| { + warn!(self.log, "Could not get the current slot"); + })?; + let slot_duration = Duration::from_millis(self.beacon_chain.spec.milliseconds_per_slot); + + // if there is enough time to perform a discovery lookup + if subscription_slot >= current_slot.saturating_add(MIN_PEER_DISCOVERY_SLOT_LOOK_AHEAD) { + // check if a discovery request already exists + if self + .discover_peers + .get(&(subnet_id, subscription_slot)) + .is_some() + { + // already a request queued, end + return Ok(()); + } + + // check current event log to see if there is a discovery event queued + if self + .events + .iter() + .find(|event| event == &&AttServiceMessage::DiscoverPeers(subnet_id)) + .is_some() + { + // already queued a discovery event + return Ok(()); + } + + // if the slot is more than epoch away, add an event to start looking for peers + if subscription_slot + < current_slot.saturating_add(TARGET_PEER_DISCOVERY_SLOT_LOOK_AHEAD) + { + // then instantly add a discovery request + self.events + .push_back(AttServiceMessage::DiscoverPeers(subnet_id)); + } else { + // Queue the discovery event to be executed for + // TARGET_PEER_DISCOVERY_SLOT_LOOK_AHEAD + + let duration_to_discover = { + let duration_to_next_slot = self + .beacon_chain + .slot_clock + .duration_to_next_slot() + .ok_or_else(|| { + warn!(self.log, "Unable to determine duration to next slot"); + })?; + // The -1 is done here to exclude the current slot duration, as we will use + // `duration_to_next_slot`. + let slots_until_discover = subscription_slot + .saturating_sub(current_slot) + .saturating_sub(1u64) + .saturating_sub(TARGET_PEER_DISCOVERY_SLOT_LOOK_AHEAD); + + duration_to_next_slot + slot_duration * (slots_until_discover.as_u64() as u32) + }; + + self.discover_peers + .insert_at((subnet_id, subscription_slot), duration_to_discover); + } + } + Ok(()) + } + + /// Checks the current random subnets and subscriptions to determine if a new subscription for this + /// subnet is required for the given slot. + /// + /// If required, adds a subscription event and an associated unsubscription event. + fn subscribe_to_subnet( + &mut self, + subnet_id: SubnetId, + subscription_slot: Slot, + ) -> Result<(), ()> { + // initialise timing variables + let current_slot = self.beacon_chain.slot_clock.now().ok_or_else(|| { + warn!(self.log, "Could not get the current slot"); + })?; + let slot_duration = Duration::from_millis(self.beacon_chain.spec.milliseconds_per_slot); + let advance_subscription_duration = Duration::from_secs(ADVANCE_SUBSCRIBE_SECS); + + // calculate the time to subscribe to the subnet + let duration_to_subscribe = { + let duration_to_next_slot = self + .beacon_chain + .slot_clock + .duration_to_next_slot() + .ok_or_else(|| { + warn!(self.log, "Unable to determine duration to next slot"); + })?; + // The -1 is done here to exclude the current slot duration, as we will use + // `duration_to_next_slot`. + let slots_until_subscribe = subscription_slot + .saturating_sub(current_slot) + .saturating_sub(1u64); + + duration_to_next_slot + slot_duration * (slots_until_subscribe.as_u64() as u32) + - advance_subscription_duration + }; + // the duration until we no longer need this subscription. We assume a single slot is + // sufficient. + let expected_end_subscription_duration = + duration_to_subscribe + slot_duration + advance_subscription_duration; + + // Checks on current subscriptions + // Note: We may be connected to a long-lived random subnet. In this case we still add the + // subscription timeout and check this case when the timeout fires. This is because a + // long-lived random subnet can be unsubscribed at any time when a validator becomes + // in-active. This case is checked on the subscription event (see `handle_subscriptions`). + + // Return if we already have a subscription for this subnet_id and slot + if self.subscriptions.contains(&(subnet_id, subscription_slot)) { + return Ok(()); + } + + // We are not currently subscribed and have no waiting subscription, create one + self.subscriptions + .insert_at((subnet_id, subscription_slot), duration_to_subscribe); + + // if there is an unsubscription event for the slot prior, we remove it to prevent + // unsubscriptions immediately after the subscription. We also want to minimize + // subscription churn and maintain a consecutive subnet subscriptions. + self.unsubscriptions + .remove(&(subnet_id, subscription_slot.saturating_sub(1u64))); + // add an unsubscription event to remove ourselves from the subnet once completed + self.unsubscriptions.insert_at( + (subnet_id, subscription_slot), + expected_end_subscription_duration, + ); + Ok(()) + } + + /// Updates the `known_validators` mapping and subscribes to a set of random subnets if required. + /// + /// This also updates the ENR to indicate our long-lived subscription to the subnet + fn add_known_validator(&mut self, validator_index: u64) { + if self.known_validators.get(&validator_index).is_none() { + // New validator has subscribed + // Subscribe to random topics and update the ENR if needed. + + let spec = &self.beacon_chain.spec; + + if self.random_subnets.len() < spec.attestation_subnet_count as usize { + // Still room for subscriptions + self.subscribe_to_random_subnets( + self.beacon_chain.spec.random_subnets_per_validator as usize, + ); + } + } + // add the new validator or update the current timeout for a known validator + self.known_validators.insert(validator_index); + } + + /// Subscribe to long-lived random subnets and update the local ENR bitfield. + fn subscribe_to_random_subnets(&mut self, no_subnets_to_subscribe: usize) { + let subnet_count = self.beacon_chain.spec.attestation_subnet_count; + + // Build a list of random subnets that we are not currently subscribed to. + let available_subnets = (0..subnet_count) + .map(SubnetId::new) + .filter(|subnet_id| self.random_subnets.get(subnet_id).is_none()) + .collect::>(); + + let to_subscribe_subnets = { + if available_subnets.len() < no_subnets_to_subscribe { + debug!(self.log, "Reached maximum random subnet subscriptions"); + available_subnets + } else { + // select a random sample of available subnets + available_subnets + .choose_multiple(&mut rand::thread_rng(), no_subnets_to_subscribe) + .cloned() + .collect::>() + } + }; + + for subnet_id in to_subscribe_subnets { + // remove this subnet from any immediate subscription/un-subscription events + self.subscriptions + .retain(|(map_subnet_id, _)| map_subnet_id != &subnet_id); + self.unsubscriptions + .retain(|(map_subnet_id, _)| map_subnet_id != &subnet_id); + + // insert a new random subnet + self.random_subnets.insert(subnet_id); + + // if we are not already subscribed, then subscribe + let topic_kind = &GossipKind::CommitteeIndex(subnet_id); + + if let None = self + .network_globals + .gossipsub_subscriptions + .read() + .iter() + .find(|topic| topic.kind() == topic_kind) + { + // not already subscribed to the topic + self.events + .push_back(AttServiceMessage::Subscribe(subnet_id)); + } + // add the subnet to the ENR bitfield + self.events.push_back(AttServiceMessage::EnrAdd(subnet_id)); + } + } + + /* A collection of functions that handle the various timeouts */ + + /// Request a discovery query to find peers for a particular subnet. + fn handle_discover_peers(&mut self, subnet_id: SubnetId, target_slot: Slot) { + debug!(self.log, "Searching for peers for subnet"; "subnet" => *subnet_id, "target_slot" => target_slot); + self.events + .push_back(AttServiceMessage::DiscoverPeers(subnet_id)); + } + + /// A queued subscription is ready. + /// + /// We add subscriptions events even if we are already subscribed to a random subnet (as these + /// can be unsubscribed at any time by inactive validators). If we are + /// still subscribed at the time the event fires, we don't re-subscribe. + fn handle_subscriptions(&mut self, subnet_id: SubnetId, target_slot: Slot) { + // Check if the subnet currently exists as a long-lasting random subnet + if let Some(expiry) = self.random_subnets.get(&subnet_id) { + // we are subscribed via a random subnet, if this is to expire during the time we need + // to be subscribed, just extend the expiry + let slot_duration = Duration::from_millis(self.beacon_chain.spec.milliseconds_per_slot); + let advance_subscription_duration = Duration::from_secs(ADVANCE_SUBSCRIBE_SECS); + // we require the subnet subscription for at least a slot on top of the initial + // subscription time + let expected_end_subscription_duration = slot_duration + advance_subscription_duration; + + if expiry < &(Instant::now() + expected_end_subscription_duration) { + self.random_subnets + .update_timeout(&subnet_id, expected_end_subscription_duration); + } + } else { + // we are also not un-subscribing from a subnet if the next slot requires us to be + // subscribed. Therefore there could be the case that we are already still subscribed + // to the required subnet. In which case we do not issue another subscription request. + let topic_kind = &GossipKind::CommitteeIndex(subnet_id); + if self + .network_globals + .gossipsub_subscriptions + .read() + .iter() + .find(|topic| topic.kind() == topic_kind) + .is_none() + { + // we are not already subscribed + debug!(self.log, "Subscribing to subnet"; "subnet" => *subnet_id, "target_slot" => target_slot.as_u64()); + self.events + .push_back(AttServiceMessage::Subscribe(subnet_id)); + } + } + } + + /// A queued unsubscription is ready. + /// + /// Unsubscription events are added, even if we are subscribed to long-lived random subnets. If + /// a random subnet is present, we do not unsubscribe from it. + fn handle_unsubscriptions(&mut self, subnet_id: SubnetId, target_slot: Slot) { + // Check if the subnet currently exists as a long-lasting random subnet + if self.random_subnets.contains(&subnet_id) { + return; + } + + debug!(self.log, "Unsubscribing from subnet"; "subnet" => *subnet_id, "processed_slot" => target_slot.as_u64()); + + // various logic checks + if self.subscriptions.contains(&(subnet_id, target_slot)) { + crit!(self.log, "Unsubscribing from a subnet in subscriptions"); + } + self.events + .push_back(AttServiceMessage::Unsubscribe(subnet_id)); + } + + /// A random subnet has expired. + /// + /// This function selects a new subnet to join, or extends the expiry if there are no more + /// available subnets to choose from. + fn handle_random_subnet_expiry(&mut self, subnet_id: SubnetId) { + let subnet_count = self.beacon_chain.spec.attestation_subnet_count; + if self.random_subnets.len() == (subnet_count - 1) as usize { + // We are at capacity, simply increase the timeout of the current subnet + self.random_subnets.insert(subnet_id); + return; + } + + // we are not at capacity, unsubscribe from the current subnet, remove the ENR bitfield bit and choose a new random one + // from the available subnets + // Note: This should not occur during a required subnet as subscriptions update the timeout + // to last as long as they are needed. + + debug!(self.log, "Unsubscribing from random subnet"; "subnet_id" => *subnet_id); + self.events + .push_back(AttServiceMessage::Unsubscribe(subnet_id)); + self.events + .push_back(AttServiceMessage::EnrRemove(subnet_id)); + self.subscribe_to_random_subnets(1); + } + + /// A known validator has not sent a subscription in a while. They are considered offline and the + /// beacon node no longer needs to be subscribed to the allocated random subnets. + /// + /// We don't keep track of a specific validator to random subnet, rather the ratio of active + /// validators to random subnets. So when a validator goes offline, we can simply remove the + /// allocated amount of random subnets. + fn handle_known_validator_expiry(&mut self) -> Result<(), ()> { + let spec = &self.beacon_chain.spec; + let subnet_count = spec.attestation_subnet_count; + let random_subnets_per_validator = spec.random_subnets_per_validator; + if self.known_validators.len() as u64 * random_subnets_per_validator >= subnet_count { + // have too many validators, ignore + return Ok(()); + } + + let subscribed_subnets = self.random_subnets.keys_vec(); + let to_remove_subnets = subscribed_subnets.choose_multiple( + &mut rand::thread_rng(), + random_subnets_per_validator as usize, + ); + let current_slot = self.beacon_chain.slot_clock.now().ok_or_else(|| { + warn!(self.log, "Could not get the current slot"); + })?; + + for subnet_id in to_remove_subnets { + // If a subscription is queued for two slots in the future, it's associated unsubscription + // will unsubscribe from the expired subnet. + // If there is no subscription for this subnet,slot it is safe to add one, without + // unsubscribing early from a required subnet + if self + .subscriptions + .get(&(**subnet_id, current_slot + 2)) + .is_none() + { + // set an unsubscribe event + let duration_to_next_slot = self + .beacon_chain + .slot_clock + .duration_to_next_slot() + .ok_or_else(|| { + warn!(self.log, "Unable to determine duration to next slot"); + })?; + let slot_duration = + Duration::from_millis(self.beacon_chain.spec.milliseconds_per_slot); + // Set the unsubscription timeout + let unsubscription_duration = duration_to_next_slot + slot_duration * 2; + self.unsubscriptions + .insert_at((**subnet_id, current_slot + 2), unsubscription_duration); + } + + // as the long lasting subnet subscription is being removed, remove the subnet_id from + // the ENR bitfield + self.events + .push_back(AttServiceMessage::EnrRemove(**subnet_id)); + } + Ok(()) + } +} + +impl Stream for AttestationService { + type Item = AttServiceMessage; + type Error = (); + + fn poll(&mut self) -> Poll, Self::Error> { + // process any peer discovery events + while let Async::Ready(Some((subnet_id, target_slot))) = + self.discover_peers.poll().map_err(|e| { + error!(self.log, "Failed to check for peer discovery requests"; "error"=> format!("{}", e)); + })? + { + self.handle_discover_peers(subnet_id, target_slot); + } + + // process any subscription events + while let Async::Ready(Some((subnet_id, target_slot))) = self.subscriptions.poll().map_err(|e| { + error!(self.log, "Failed to check for subnet subscription times"; "error"=> format!("{}", e)); + })? + { + self.handle_subscriptions(subnet_id, target_slot); + } + + // process any un-subscription events + while let Async::Ready(Some((subnet_id, target_slot))) = self.unsubscriptions.poll().map_err(|e| { + error!(self.log, "Failed to check for subnet unsubscription times"; "error"=> format!("{}", e)); + })? + { + self.handle_unsubscriptions(subnet_id, target_slot); + } + + // process any random subnet expiries + while let Async::Ready(Some(subnet)) = self.random_subnets.poll().map_err(|e| { + error!(self.log, "Failed to check for random subnet cycles"; "error"=> format!("{}", e)); + })? + { + self.handle_random_subnet_expiry(subnet); + } + + // process any known validator expiries + while let Async::Ready(Some(_validator_index)) = self.known_validators.poll().map_err(|e| { + error!(self.log, "Failed to check for random subnet cycles"; "error"=> format!("{}", e)); + })? + { + let _ = self.handle_known_validator_expiry(); + } + + // process any generated events + if let Some(event) = self.events.pop_front() { + return Ok(Async::Ready(Some(event))); + } + + Ok(Async::NotReady) + } +} diff --git a/beacon_node/network/src/error.rs b/beacon_node/network/src/error.rs index fc061ff44..e30ce4f43 100644 --- a/beacon_node/network/src/error.rs +++ b/beacon_node/network/src/error.rs @@ -1,6 +1,4 @@ // generates error types -use eth2_libp2p; - use error_chain::error_chain; error_chain! { diff --git a/beacon_node/network/src/lib.rs b/beacon_node/network/src/lib.rs index fddca767b..040ade2b2 100644 --- a/beacon_node/network/src/lib.rs +++ b/beacon_node/network/src/lib.rs @@ -1,12 +1,11 @@ /// This crate provides the network server for Lighthouse. pub mod error; -pub mod message_handler; -pub mod message_processor; -pub mod persisted_dht; pub mod service; -pub mod sync; + +mod attestation_service; +mod persisted_dht; +mod router; +mod sync; pub use eth2_libp2p::NetworkConfig; -pub use message_processor::MessageProcessor; -pub use service::NetworkMessage; -pub use service::Service; +pub use service::{NetworkMessage, NetworkService}; diff --git a/beacon_node/network/src/message_handler.rs b/beacon_node/network/src/message_handler.rs deleted file mode 100644 index 97212a55e..000000000 --- a/beacon_node/network/src/message_handler.rs +++ /dev/null @@ -1,367 +0,0 @@ -#![allow(clippy::unit_arg)] -use crate::error; -use crate::service::NetworkMessage; -use crate::MessageProcessor; -use beacon_chain::{BeaconChain, BeaconChainTypes}; -use eth2_libp2p::{ - behaviour::PubsubMessage, - rpc::{RPCError, RPCErrorResponse, RPCRequest, RPCResponse, RequestId, ResponseTermination}, - MessageId, PeerId, RPCEvent, -}; -use futures::future::Future; -use futures::stream::Stream; -use slog::{debug, o, trace, warn}; -use ssz::{Decode, DecodeError}; -use std::sync::Arc; -use tokio::sync::mpsc; -use types::{Attestation, AttesterSlashing, ProposerSlashing, SignedBeaconBlock, VoluntaryExit}; - -/// Handles messages received from the network and client and organises syncing. This -/// functionality of this struct is to validate an decode messages from the network before -/// passing them to the internal message processor. The message processor spawns a syncing thread -/// which manages which blocks need to be requested and processed. -pub struct MessageHandler { - /// A channel to the network service to allow for gossip propagation. - network_send: mpsc::UnboundedSender, - /// Processes validated and decoded messages from the network. Has direct access to the - /// sync manager. - message_processor: MessageProcessor, - /// The `MessageHandler` logger. - log: slog::Logger, -} - -/// Types of messages the handler can receive. -#[derive(Debug)] -pub enum HandlerMessage { - /// We have initiated a connection to a new peer. - PeerDialed(PeerId), - /// Peer has disconnected, - PeerDisconnected(PeerId), - /// An RPC response/request has been received. - RPC(PeerId, RPCEvent), - /// A gossip message has been received. The fields are: message id, the peer that sent us this - /// message and the message itself. - PubsubMessage(MessageId, PeerId, PubsubMessage), -} - -impl MessageHandler { - /// Initializes and runs the MessageHandler. - pub fn spawn( - beacon_chain: Arc>, - network_send: mpsc::UnboundedSender, - executor: &tokio::runtime::TaskExecutor, - log: slog::Logger, - ) -> error::Result> { - let message_handler_log = log.new(o!("service"=> "msg_handler")); - trace!(message_handler_log, "Service starting"); - - let (handler_send, handler_recv) = mpsc::unbounded_channel(); - - // Initialise a message instance, which itself spawns the syncing thread. - let message_processor = - MessageProcessor::new(executor, beacon_chain, network_send.clone(), &log); - - // generate the Message handler - let mut handler = MessageHandler { - network_send, - message_processor, - log: message_handler_log, - }; - - // spawn handler task and move the message handler instance into the spawned thread - executor.spawn( - handler_recv - .for_each(move |msg| Ok(handler.handle_message(msg))) - .map_err(move |_| { - debug!(log, "Network message handler terminated."); - }), - ); - - Ok(handler_send) - } - - /// Handle all messages incoming from the network service. - fn handle_message(&mut self, message: HandlerMessage) { - match message { - // we have initiated a connection to a peer - HandlerMessage::PeerDialed(peer_id) => { - self.message_processor.on_connect(peer_id); - } - // A peer has disconnected - HandlerMessage::PeerDisconnected(peer_id) => { - self.message_processor.on_disconnect(peer_id); - } - // An RPC message request/response has been received - HandlerMessage::RPC(peer_id, rpc_event) => { - self.handle_rpc_message(peer_id, rpc_event); - } - // An RPC message request/response has been received - HandlerMessage::PubsubMessage(id, peer_id, gossip) => { - self.handle_gossip(id, peer_id, gossip); - } - } - } - - /* RPC - Related functionality */ - - /// Handle RPC messages - fn handle_rpc_message(&mut self, peer_id: PeerId, rpc_message: RPCEvent) { - match rpc_message { - RPCEvent::Request(id, req) => self.handle_rpc_request(peer_id, id, req), - RPCEvent::Response(id, resp) => self.handle_rpc_response(peer_id, id, resp), - RPCEvent::Error(id, error) => self.handle_rpc_error(peer_id, id, error), - } - } - - /// A new RPC request has been received from the network. - fn handle_rpc_request(&mut self, peer_id: PeerId, request_id: RequestId, request: RPCRequest) { - match request { - RPCRequest::Status(status_message) => { - self.message_processor - .on_status_request(peer_id, request_id, status_message) - } - RPCRequest::Goodbye(goodbye_reason) => { - debug!( - self.log, "PeerGoodbye"; - "peer" => format!("{:?}", peer_id), - "reason" => format!("{:?}", goodbye_reason), - ); - self.message_processor.on_disconnect(peer_id); - } - RPCRequest::BlocksByRange(request) => self - .message_processor - .on_blocks_by_range_request(peer_id, request_id, request), - RPCRequest::BlocksByRoot(request) => self - .message_processor - .on_blocks_by_root_request(peer_id, request_id, request), - } - } - - /// An RPC response has been received from the network. - // we match on id and ignore responses past the timeout. - fn handle_rpc_response( - &mut self, - peer_id: PeerId, - request_id: RequestId, - error_response: RPCErrorResponse, - ) { - // an error could have occurred. - match error_response { - RPCErrorResponse::InvalidRequest(error) => { - warn!(self.log, "Peer indicated invalid request";"peer_id" => format!("{:?}", peer_id), "error" => error.as_string()); - self.handle_rpc_error(peer_id, request_id, RPCError::RPCErrorResponse); - } - RPCErrorResponse::ServerError(error) => { - warn!(self.log, "Peer internal server error";"peer_id" => format!("{:?}", peer_id), "error" => error.as_string()); - self.handle_rpc_error(peer_id, request_id, RPCError::RPCErrorResponse); - } - RPCErrorResponse::Unknown(error) => { - warn!(self.log, "Unknown peer error";"peer" => format!("{:?}", peer_id), "error" => error.as_string()); - self.handle_rpc_error(peer_id, request_id, RPCError::RPCErrorResponse); - } - RPCErrorResponse::Success(response) => { - match response { - RPCResponse::Status(status_message) => { - self.message_processor - .on_status_response(peer_id, status_message); - } - RPCResponse::BlocksByRange(response) => { - match self.decode_beacon_block(response) { - Ok(beacon_block) => { - self.message_processor.on_blocks_by_range_response( - peer_id, - request_id, - Some(beacon_block), - ); - } - Err(e) => { - // TODO: Down-vote Peer - warn!(self.log, "Peer sent invalid BEACON_BLOCKS response";"peer" => format!("{:?}", peer_id), "error" => format!("{:?}", e)); - } - } - } - RPCResponse::BlocksByRoot(response) => { - match self.decode_beacon_block(response) { - Ok(beacon_block) => { - self.message_processor.on_blocks_by_root_response( - peer_id, - request_id, - Some(beacon_block), - ); - } - Err(e) => { - // TODO: Down-vote Peer - warn!(self.log, "Peer sent invalid BEACON_BLOCKS response";"peer" => format!("{:?}", peer_id), "error" => format!("{:?}", e)); - } - } - } - } - } - RPCErrorResponse::StreamTermination(response_type) => { - // have received a stream termination, notify the processing functions - match response_type { - ResponseTermination::BlocksByRange => { - self.message_processor - .on_blocks_by_range_response(peer_id, request_id, None); - } - ResponseTermination::BlocksByRoot => { - self.message_processor - .on_blocks_by_root_response(peer_id, request_id, None); - } - } - } - } - } - - /// Handle various RPC errors - fn handle_rpc_error(&mut self, peer_id: PeerId, request_id: RequestId, error: RPCError) { - warn!(self.log, "RPC Error"; "Peer" => format!("{:?}", peer_id), "request_id" => format!("{}", request_id), "Error" => format!("{:?}", error)); - self.message_processor.on_rpc_error(peer_id, request_id); - } - - /// Handle RPC messages - fn handle_gossip(&mut self, id: MessageId, peer_id: PeerId, gossip_message: PubsubMessage) { - match gossip_message { - PubsubMessage::Block(message) => match self.decode_gossip_block(message) { - Ok(block) => { - let should_forward_on = self - .message_processor - .on_block_gossip(peer_id.clone(), block); - // TODO: Apply more sophisticated validation and decoding logic - if should_forward_on { - self.propagate_message(id, peer_id); - } - } - Err(e) => { - debug!(self.log, "Invalid gossiped beacon block"; "peer_id" => format!("{}", peer_id), "Error" => format!("{:?}", e)); - } - }, - PubsubMessage::Attestation(message) => match self.decode_gossip_attestation(message) { - Ok(attestation) => { - // TODO: Apply more sophisticated validation and decoding logic - self.propagate_message(id, peer_id.clone()); - self.message_processor - .on_attestation_gossip(peer_id, attestation); - } - Err(e) => { - debug!(self.log, "Invalid gossiped attestation"; "peer_id" => format!("{}", peer_id), "Error" => format!("{:?}", e)); - } - }, - PubsubMessage::VoluntaryExit(message) => match self.decode_gossip_exit(message) { - Ok(_exit) => { - // TODO: Apply more sophisticated validation and decoding logic - self.propagate_message(id, peer_id.clone()); - // TODO: Handle exits - debug!(self.log, "Received a voluntary exit"; "peer_id" => format!("{}", peer_id) ); - } - Err(e) => { - debug!(self.log, "Invalid gossiped exit"; "peer_id" => format!("{}", peer_id), "Error" => format!("{:?}", e)); - } - }, - PubsubMessage::ProposerSlashing(message) => { - match self.decode_gossip_proposer_slashing(message) { - Ok(_slashing) => { - // TODO: Apply more sophisticated validation and decoding logic - self.propagate_message(id, peer_id.clone()); - // TODO: Handle proposer slashings - debug!(self.log, "Received a proposer slashing"; "peer_id" => format!("{}", peer_id) ); - } - Err(e) => { - debug!(self.log, "Invalid gossiped proposer slashing"; "peer_id" => format!("{}", peer_id), "Error" => format!("{:?}", e)); - } - } - } - PubsubMessage::AttesterSlashing(message) => { - match self.decode_gossip_attestation_slashing(message) { - Ok(_slashing) => { - // TODO: Apply more sophisticated validation and decoding logic - self.propagate_message(id, peer_id.clone()); - // TODO: Handle attester slashings - debug!(self.log, "Received an attester slashing"; "peer_id" => format!("{}", peer_id) ); - } - Err(e) => { - debug!(self.log, "Invalid gossiped attester slashing"; "peer_id" => format!("{}", peer_id), "Error" => format!("{:?}", e)); - } - } - } - PubsubMessage::Unknown(message) => { - // Received a message from an unknown topic. Ignore for now - debug!(self.log, "Unknown Gossip Message"; "peer_id" => format!("{}", peer_id), "Message" => format!("{:?}", message)); - } - } - } - - /// Informs the network service that the message should be forwarded to other peers. - fn propagate_message(&mut self, message_id: MessageId, propagation_source: PeerId) { - self.network_send - .try_send(NetworkMessage::Propagate { - propagation_source, - message_id, - }) - .unwrap_or_else(|_| { - warn!( - self.log, - "Could not send propagation request to the network service" - ) - }); - } - - /* Decoding of gossipsub objects from the network. - * - * The decoding is done in the message handler as it has access to to a `BeaconChain` and can - * therefore apply more efficient logic in decoding and verification. - * - * TODO: Apply efficient decoding/verification of these objects - */ - - /* Gossipsub Domain Decoding */ - // Note: These are not generics as type-specific verification will need to be applied. - fn decode_gossip_block( - &self, - beacon_block: Vec, - ) -> Result, DecodeError> { - //TODO: Apply verification before decoding. - SignedBeaconBlock::from_ssz_bytes(&beacon_block) - } - - fn decode_gossip_attestation( - &self, - beacon_block: Vec, - ) -> Result, DecodeError> { - //TODO: Apply verification before decoding. - Attestation::from_ssz_bytes(&beacon_block) - } - - fn decode_gossip_exit(&self, voluntary_exit: Vec) -> Result { - //TODO: Apply verification before decoding. - VoluntaryExit::from_ssz_bytes(&voluntary_exit) - } - - fn decode_gossip_proposer_slashing( - &self, - proposer_slashing: Vec, - ) -> Result { - //TODO: Apply verification before decoding. - ProposerSlashing::from_ssz_bytes(&proposer_slashing) - } - - fn decode_gossip_attestation_slashing( - &self, - attester_slashing: Vec, - ) -> Result, DecodeError> { - //TODO: Apply verification before decoding. - AttesterSlashing::from_ssz_bytes(&attester_slashing) - } - - /* Req/Resp Domain Decoding */ - - /// Verifies and decodes an ssz-encoded `SignedBeaconBlock`. If `None` is passed, this represents a - /// stream termination. - fn decode_beacon_block( - &self, - beacon_block: Vec, - ) -> Result, DecodeError> { - //TODO: Implement faster block verification before decoding entirely - SignedBeaconBlock::from_ssz_bytes(&beacon_block) - } -} diff --git a/beacon_node/network/src/persisted_dht.rs b/beacon_node/network/src/persisted_dht.rs index bf9d70430..c43e5d84f 100644 --- a/beacon_node/network/src/persisted_dht.rs +++ b/beacon_node/network/src/persisted_dht.rs @@ -1,13 +1,15 @@ +use beacon_chain::BeaconChainTypes; use eth2_libp2p::Enr; use rlp; use std::sync::Arc; -use store::{DBColumn, Error as StoreError, SimpleStoreItem, Store}; -use types::{EthSpec, Hash256}; +use store::Store; +use store::{DBColumn, Error as StoreError, SimpleStoreItem}; +use types::Hash256; /// 32-byte key for accessing the `DhtEnrs`. pub const DHT_DB_KEY: &str = "PERSISTEDDHTPERSISTEDDHTPERSISTE"; -pub fn load_dht, E: EthSpec>(store: Arc) -> Vec { +pub fn load_dht(store: Arc) -> Vec { // Load DHT from store let key = Hash256::from_slice(&DHT_DB_KEY.as_bytes()); match store.get(&key) { @@ -20,8 +22,8 @@ pub fn load_dht, E: EthSpec>(store: Arc) -> Vec { } /// Attempt to persist the ENR's in the DHT to `self.store`. -pub fn persist_dht, E: EthSpec>( - store: Arc, +pub fn persist_dht( + store: Arc, enrs: Vec, ) -> Result<(), store::Error> { let key = Hash256::from_slice(&DHT_DB_KEY.as_bytes()); diff --git a/beacon_node/network/src/router/mod.rs b/beacon_node/network/src/router/mod.rs new file mode 100644 index 000000000..fa35d95e3 --- /dev/null +++ b/beacon_node/network/src/router/mod.rs @@ -0,0 +1,275 @@ +//! This module handles incoming network messages. +//! +//! It routes the messages to appropriate services, such as the Sync +//! and processes those that are +#![allow(clippy::unit_arg)] + +pub mod processor; + +use crate::error; +use crate::service::NetworkMessage; +use beacon_chain::{BeaconChain, BeaconChainTypes}; +use eth2_libp2p::{ + rpc::{RPCError, RPCErrorResponse, RPCRequest, RPCResponse, RequestId, ResponseTermination}, + MessageId, PeerId, PubsubData, PubsubMessage, RPCEvent, +}; +use futures::future::Future; +use futures::stream::Stream; +use processor::Processor; +use slog::{debug, o, trace, warn}; +use std::sync::Arc; +use tokio::sync::mpsc; +use types::EthSpec; + +/// Handles messages received from the network and client and organises syncing. This +/// functionality of this struct is to validate an decode messages from the network before +/// passing them to the internal message processor. The message processor spawns a syncing thread +/// which manages which blocks need to be requested and processed. +pub struct Router { + /// A channel to the network service to allow for gossip propagation. + network_send: mpsc::UnboundedSender>, + /// Processes validated and decoded messages from the network. Has direct access to the + /// sync manager. + processor: Processor, + /// The `Router` logger. + log: slog::Logger, +} + +/// Types of messages the handler can receive. +#[derive(Debug)] +pub enum RouterMessage { + /// We have initiated a connection to a new peer. + PeerDialed(PeerId), + /// Peer has disconnected, + PeerDisconnected(PeerId), + /// An RPC response/request has been received. + RPC(PeerId, RPCEvent), + /// A gossip message has been received. The fields are: message id, the peer that sent us this + /// message and the message itself. + PubsubMessage(MessageId, PeerId, PubsubMessage), +} + +impl Router { + /// Initializes and runs the Router. + pub fn spawn( + beacon_chain: Arc>, + network_send: mpsc::UnboundedSender>, + executor: &tokio::runtime::TaskExecutor, + log: slog::Logger, + ) -> error::Result>> { + let message_handler_log = log.new(o!("service"=> "msg_handler")); + trace!(message_handler_log, "Service starting"); + + let (handler_send, handler_recv) = mpsc::unbounded_channel(); + + // Initialise a message instance, which itself spawns the syncing thread. + let processor = Processor::new(executor, beacon_chain, network_send.clone(), &log); + + // generate the Message handler + let mut handler = Router { + network_send, + processor, + log: message_handler_log, + }; + + // spawn handler task and move the message handler instance into the spawned thread + executor.spawn( + handler_recv + .for_each(move |msg| Ok(handler.handle_message(msg))) + .map_err(move |_| { + debug!(log, "Network message handler terminated."); + }), + ); + + Ok(handler_send) + } + + /// Handle all messages incoming from the network service. + fn handle_message(&mut self, message: RouterMessage) { + match message { + // we have initiated a connection to a peer + RouterMessage::PeerDialed(peer_id) => { + self.processor.on_connect(peer_id); + } + // A peer has disconnected + RouterMessage::PeerDisconnected(peer_id) => { + self.processor.on_disconnect(peer_id); + } + // An RPC message request/response has been received + RouterMessage::RPC(peer_id, rpc_event) => { + self.handle_rpc_message(peer_id, rpc_event); + } + // An RPC message request/response has been received + RouterMessage::PubsubMessage(id, peer_id, gossip) => { + self.handle_gossip(id, peer_id, gossip); + } + } + } + + /* RPC - Related functionality */ + + /// Handle RPC messages + fn handle_rpc_message(&mut self, peer_id: PeerId, rpc_message: RPCEvent) { + match rpc_message { + RPCEvent::Request(id, req) => self.handle_rpc_request(peer_id, id, req), + RPCEvent::Response(id, resp) => self.handle_rpc_response(peer_id, id, resp), + RPCEvent::Error(id, error) => self.handle_rpc_error(peer_id, id, error), + } + } + + /// A new RPC request has been received from the network. + fn handle_rpc_request( + &mut self, + peer_id: PeerId, + request_id: RequestId, + request: RPCRequest, + ) { + match request { + RPCRequest::Status(status_message) => { + self.processor + .on_status_request(peer_id, request_id, status_message) + } + RPCRequest::Goodbye(goodbye_reason) => { + debug!( + self.log, "PeerGoodbye"; + "peer" => format!("{:?}", peer_id), + "reason" => format!("{:?}", goodbye_reason), + ); + self.processor.on_disconnect(peer_id); + } + RPCRequest::BlocksByRange(request) => self + .processor + .on_blocks_by_range_request(peer_id, request_id, request), + RPCRequest::BlocksByRoot(request) => self + .processor + .on_blocks_by_root_request(peer_id, request_id, request), + RPCRequest::Phantom(_) => unreachable!("Phantom never initialised"), + } + } + + /// An RPC response has been received from the network. + // we match on id and ignore responses past the timeout. + fn handle_rpc_response( + &mut self, + peer_id: PeerId, + request_id: RequestId, + error_response: RPCErrorResponse, + ) { + // an error could have occurred. + match error_response { + RPCErrorResponse::InvalidRequest(error) => { + warn!(self.log, "Peer indicated invalid request";"peer_id" => format!("{:?}", peer_id), "error" => error.as_string()); + self.handle_rpc_error(peer_id, request_id, RPCError::RPCErrorResponse); + } + RPCErrorResponse::ServerError(error) => { + warn!(self.log, "Peer internal server error";"peer_id" => format!("{:?}", peer_id), "error" => error.as_string()); + self.handle_rpc_error(peer_id, request_id, RPCError::RPCErrorResponse); + } + RPCErrorResponse::Unknown(error) => { + warn!(self.log, "Unknown peer error";"peer" => format!("{:?}", peer_id), "error" => error.as_string()); + self.handle_rpc_error(peer_id, request_id, RPCError::RPCErrorResponse); + } + RPCErrorResponse::Success(response) => match response { + RPCResponse::Status(status_message) => { + self.processor.on_status_response(peer_id, status_message); + } + RPCResponse::BlocksByRange(beacon_block) => { + self.processor.on_blocks_by_range_response( + peer_id, + request_id, + Some(beacon_block), + ); + } + RPCResponse::BlocksByRoot(beacon_block) => { + self.processor.on_blocks_by_root_response( + peer_id, + request_id, + Some(beacon_block), + ); + } + }, + RPCErrorResponse::StreamTermination(response_type) => { + // have received a stream termination, notify the processing functions + match response_type { + ResponseTermination::BlocksByRange => { + self.processor + .on_blocks_by_range_response(peer_id, request_id, None); + } + ResponseTermination::BlocksByRoot => { + self.processor + .on_blocks_by_root_response(peer_id, request_id, None); + } + } + } + } + } + + /// Handle various RPC errors + fn handle_rpc_error(&mut self, peer_id: PeerId, request_id: RequestId, error: RPCError) { + warn!(self.log, "RPC Error"; "Peer" => format!("{:?}", peer_id), "request_id" => format!("{}", request_id), "Error" => format!("{:?}", error)); + self.processor.on_rpc_error(peer_id, request_id); + } + + /// Handle RPC messages + fn handle_gossip( + &mut self, + id: MessageId, + peer_id: PeerId, + gossip_message: PubsubMessage, + ) { + match gossip_message.data { + PubsubData::BeaconBlock(block) => { + if self.processor.should_forward_block(&block) { + self.propagate_message(id, peer_id.clone()); + } + self.processor.on_block_gossip(peer_id, block); + } + PubsubData::AggregateAndProofAttestation(_agg_attestation) => { + // TODO: Handle propagation conditions + self.propagate_message(id, peer_id); + // TODO Handle aggregate attestion + // self.processor + // .on_attestation_gossip(peer_id.clone(), &agg_attestation); + } + PubsubData::Attestation(boxed_shard_attestation) => { + // TODO: Handle propagation conditions + self.propagate_message(id, peer_id.clone()); + self.processor + .on_attestation_gossip(peer_id, boxed_shard_attestation.1); + } + PubsubData::VoluntaryExit(_exit) => { + // TODO: Apply more sophisticated validation + self.propagate_message(id, peer_id.clone()); + // TODO: Handle exits + debug!(self.log, "Received a voluntary exit"; "peer_id" => format!("{}", peer_id) ); + } + PubsubData::ProposerSlashing(_proposer_slashing) => { + // TODO: Apply more sophisticated validation + self.propagate_message(id, peer_id.clone()); + // TODO: Handle proposer slashings + debug!(self.log, "Received a proposer slashing"; "peer_id" => format!("{}", peer_id) ); + } + PubsubData::AttesterSlashing(_attester_slashing) => { + // TODO: Apply more sophisticated validation + self.propagate_message(id, peer_id.clone()); + // TODO: Handle attester slashings + debug!(self.log, "Received an attester slashing"; "peer_id" => format!("{}", peer_id) ); + } + } + } + + /// Informs the network service that the message should be forwarded to other peers. + fn propagate_message(&mut self, message_id: MessageId, propagation_source: PeerId) { + self.network_send + .try_send(NetworkMessage::Propagate { + propagation_source, + message_id, + }) + .unwrap_or_else(|_| { + warn!( + self.log, + "Could not send propagation request to the network service" + ) + }); + } +} diff --git a/beacon_node/network/src/message_processor.rs b/beacon_node/network/src/router/processor.rs similarity index 92% rename from beacon_node/network/src/message_processor.rs rename to beacon_node/network/src/router/processor.rs index 99b1a9fce..682c67c46 100644 --- a/beacon_node/network/src/message_processor.rs +++ b/beacon_node/network/src/router/processor.rs @@ -19,9 +19,6 @@ use types::{Attestation, Epoch, EthSpec, Hash256, SignedBeaconBlock, Slot}; /// Otherwise we queue it. pub(crate) const FUTURE_SLOT_TOLERANCE: u64 = 1; -const SHOULD_FORWARD_GOSSIP_BLOCK: bool = true; -const SHOULD_NOT_FORWARD_GOSSIP_BLOCK: bool = false; - /// Keeps track of syncing information for known connected peers. #[derive(Clone, Copy, Debug)] pub struct PeerSyncInfo { @@ -52,7 +49,7 @@ impl PeerSyncInfo { /// Processes validated messages from the network. It relays necessary data to the syncing thread /// and processes blocks from the pubsub network. -pub struct MessageProcessor { +pub struct Processor { /// A reference to the underlying beacon chain. chain: Arc>, /// A channel to the syncing thread. @@ -60,17 +57,17 @@ pub struct MessageProcessor { /// A oneshot channel for destroying the sync thread. _sync_exit: oneshot::Sender<()>, /// A network context to return and handle RPC requests. - network: HandlerNetworkContext, + network: HandlerNetworkContext, /// The `RPCHandler` logger. log: slog::Logger, } -impl MessageProcessor { - /// Instantiate a `MessageProcessor` instance +impl Processor { + /// Instantiate a `Processor` instance pub fn new( executor: &tokio::runtime::TaskExecutor, beacon_chain: Arc>, - network_send: mpsc::UnboundedSender, + network_send: mpsc::UnboundedSender>, log: &slog::Logger, ) -> Self { let sync_logger = log.new(o!("service"=> "sync")); @@ -83,7 +80,7 @@ impl MessageProcessor { sync_logger, ); - MessageProcessor { + Processor { chain: beacon_chain, sync_send, _sync_exit, @@ -303,7 +300,7 @@ impl MessageProcessor { self.network.send_rpc_response( peer_id.clone(), request_id, - RPCResponse::BlocksByRoot(block.as_ssz_bytes()), + RPCResponse::BlocksByRoot(Box::new(block)), ); send_block_count += 1; } else { @@ -389,7 +386,7 @@ impl MessageProcessor { self.network.send_rpc_response( peer_id.clone(), request_id, - RPCResponse::BlocksByRange(block.as_ssz_bytes()), + RPCResponse::BlocksByRange(Box::new(block)), ); } } else { @@ -436,9 +433,8 @@ impl MessageProcessor { &mut self, peer_id: PeerId, request_id: RequestId, - beacon_block: Option>, + beacon_block: Option>>, ) { - let beacon_block = beacon_block.map(Box::new); trace!( self.log, "Received BlocksByRange Response"; @@ -457,9 +453,8 @@ impl MessageProcessor { &mut self, peer_id: PeerId, request_id: RequestId, - beacon_block: Option>, + beacon_block: Option>>, ) { - let beacon_block = beacon_block.map(Box::new); trace!( self.log, "Received BlocksByRoot Response"; @@ -473,6 +468,22 @@ impl MessageProcessor { }); } + /// Template function to be called on a block to determine if the block should be propagated + /// across the network. + pub fn should_forward_block(&mut self, _block: &Box>) -> bool { + // TODO: Propagate error once complete + // self.chain.should_forward_block(block).is_ok() + true + } + + /// Template function to be called on an attestation to determine if the attestation should be propagated + /// across the network. + pub fn _should_forward_attestation(&mut self, _attestation: &Attestation) -> bool { + // TODO: Propagate error once complete + //self.chain.should_forward_attestation(attestation).is_ok() + true + } + /// Process a gossip message declaring a new block. /// /// Attempts to apply to block to the beacon chain. May queue the block for later processing. @@ -481,9 +492,9 @@ impl MessageProcessor { pub fn on_block_gossip( &mut self, peer_id: PeerId, - block: SignedBeaconBlock, + block: Box>, ) -> bool { - match self.chain.process_block(block.clone()) { + match BlockProcessingOutcome::shim(self.chain.process_block(*block.clone())) { Ok(outcome) => match outcome { BlockProcessingOutcome::Processed { .. } => { trace!(self.log, "Gossipsub block processed"; @@ -508,24 +519,13 @@ impl MessageProcessor { "location" => "block gossip" ), } - - SHOULD_FORWARD_GOSSIP_BLOCK } BlockProcessingOutcome::ParentUnknown { .. } => { // Inform the sync manager to find parents for this block trace!(self.log, "Block with unknown parent received"; "peer_id" => format!("{:?}",peer_id)); - self.send_to_sync(SyncMessage::UnknownBlock(peer_id, Box::new(block))); - SHOULD_FORWARD_GOSSIP_BLOCK + self.send_to_sync(SyncMessage::UnknownBlock(peer_id, block)); } - BlockProcessingOutcome::FutureSlot { - present_slot, - block_slot, - } if present_slot + FUTURE_SLOT_TOLERANCE >= block_slot => { - //TODO: Decide the logic here - SHOULD_FORWARD_GOSSIP_BLOCK - } - BlockProcessingOutcome::BlockIsAlreadyKnown => SHOULD_FORWARD_GOSSIP_BLOCK, other => { warn!( self.log, @@ -539,7 +539,6 @@ impl MessageProcessor { "Invalid gossip beacon block ssz"; "ssz" => format!("0x{}", hex::encode(block.as_ssz_bytes())), ); - SHOULD_NOT_FORWARD_GOSSIP_BLOCK //TODO: Decide if we want to forward these } }, Err(_) => { @@ -549,15 +548,18 @@ impl MessageProcessor { "Erroneous gossip beacon block ssz"; "ssz" => format!("0x{}", hex::encode(block.as_ssz_bytes())), ); - SHOULD_NOT_FORWARD_GOSSIP_BLOCK } } + // TODO: Update with correct block gossip checking + true } /// Process a gossip message declaring a new attestation. /// /// Not currently implemented. - pub fn on_attestation_gossip(&mut self, peer_id: PeerId, msg: Attestation) { + pub fn on_attestation_gossip(&mut self, _peer_id: PeerId, _msg: Attestation) { + // TODO: Handle subnet gossip + /* match self.chain.process_attestation(msg.clone()) { Ok(outcome) => match outcome { AttestationProcessingOutcome::Processed => { @@ -603,7 +605,8 @@ impl MessageProcessor { "ssz" => format!("0x{}", hex::encode(msg.as_ssz_bytes())), ); } - } + }; + */ } } @@ -625,15 +628,15 @@ pub(crate) fn status_message( /// Wraps a Network Channel to employ various RPC related network functionality for the message /// handler. The handler doesn't manage it's own request Id's and can therefore only send /// responses or requests with 0 request Ids. -pub struct HandlerNetworkContext { +pub struct HandlerNetworkContext { /// The network channel to relay messages to the Network service. - network_send: mpsc::UnboundedSender, + network_send: mpsc::UnboundedSender>, /// Logger for the `NetworkContext`. log: slog::Logger, } -impl HandlerNetworkContext { - pub fn new(network_send: mpsc::UnboundedSender, log: slog::Logger) -> Self { +impl HandlerNetworkContext { + pub fn new(network_send: mpsc::UnboundedSender>, log: slog::Logger) -> Self { Self { network_send, log } } @@ -655,7 +658,7 @@ impl HandlerNetworkContext { }); } - pub fn send_rpc_request(&mut self, peer_id: PeerId, rpc_request: RPCRequest) { + pub fn send_rpc_request(&mut self, peer_id: PeerId, rpc_request: RPCRequest) { // the message handler cannot send requests with ids. Id's are managed by the sync // manager. let request_id = 0; @@ -667,7 +670,7 @@ impl HandlerNetworkContext { &mut self, peer_id: PeerId, request_id: RequestId, - rpc_response: RPCResponse, + rpc_response: RPCResponse, ) { self.send_rpc_event( peer_id, @@ -680,12 +683,12 @@ impl HandlerNetworkContext { &mut self, peer_id: PeerId, request_id: RequestId, - rpc_error_response: RPCErrorResponse, + rpc_error_response: RPCErrorResponse, ) { self.send_rpc_event(peer_id, RPCEvent::Response(request_id, rpc_error_response)); } - fn send_rpc_event(&mut self, peer_id: PeerId, rpc_event: RPCEvent) { + fn send_rpc_event(&mut self, peer_id: PeerId, rpc_event: RPCEvent) { self.network_send .try_send(NetworkMessage::RPC(peer_id, rpc_event)) .unwrap_or_else(|_| { diff --git a/beacon_node/network/src/service.rs b/beacon_node/network/src/service.rs index 0439e39c8..73dfd1c0a 100644 --- a/beacon_node/network/src/service.rs +++ b/beacon_node/network/src/service.rs @@ -1,23 +1,24 @@ use crate::error; -use crate::message_handler::{HandlerMessage, MessageHandler}; use crate::persisted_dht::{load_dht, persist_dht}; -use crate::NetworkConfig; -use beacon_chain::{BeaconChain, BeaconChainTypes}; -use core::marker::PhantomData; -use eth2_libp2p::Service as LibP2PService; -use eth2_libp2p::{ - rpc::RPCRequest, Enr, Libp2pEvent, MessageId, Multiaddr, NetworkGlobals, PeerId, Swarm, Topic, +use crate::router::{Router, RouterMessage}; +use crate::{ + attestation_service::{AttServiceMessage, AttestationService}, + NetworkConfig, }; +use beacon_chain::{BeaconChain, BeaconChainTypes}; +use eth2_libp2p::Service as LibP2PService; +use eth2_libp2p::{rpc::RPCRequest, Enr, Libp2pEvent, MessageId, NetworkGlobals, PeerId, Swarm}; use eth2_libp2p::{PubsubMessage, RPCEvent}; use futures::prelude::*; use futures::Stream; +use rest_types::ValidatorSubscription; use slog::{debug, error, info, trace}; -use std::collections::HashSet; -use std::sync::{atomic::Ordering, Arc}; +use std::sync::Arc; use std::time::{Duration, Instant}; use tokio::runtime::TaskExecutor; use tokio::sync::{mpsc, oneshot}; use tokio::timer::Delay; +use types::EthSpec; mod tests; @@ -25,27 +26,46 @@ mod tests; const BAN_PEER_TIMEOUT: u64 = 30; /// Service that handles communication between internal services and the `eth2_libp2p` network service. -pub struct Service { - libp2p_port: u16, - network_globals: Arc, - _libp2p_exit: oneshot::Sender<()>, - _network_send: mpsc::UnboundedSender, - _phantom: PhantomData, +pub struct NetworkService { + /// The underlying libp2p service that drives all the network interactions. + libp2p: LibP2PService, + /// An attestation and subnet manager service. + attestation_service: AttestationService, + /// The receiver channel for lighthouse to communicate with the network service. + network_recv: mpsc::UnboundedReceiver>, + /// The sending channel for the network service to send messages to be routed throughout + /// lighthouse. + router_send: mpsc::UnboundedSender>, + /// A reference to lighthouse's database to persist the DHT. + store: Arc, + /// A collection of global variables, accessible outside of the network service. + network_globals: Arc>, + /// An initial delay to update variables after the libp2p service has started. + initial_delay: Delay, + /// The logger for the network service. + log: slog::Logger, + /// A probability of propagation. + propagation_percentage: Option, } -impl Service { - pub fn new( +impl NetworkService { + pub fn start( beacon_chain: Arc>, config: &NetworkConfig, executor: &TaskExecutor, network_log: slog::Logger, - ) -> error::Result<(Arc, mpsc::UnboundedSender)> { + ) -> error::Result<( + Arc>, + mpsc::UnboundedSender>, + oneshot::Sender<()>, + )> { // build the network channel - let (network_send, network_recv) = mpsc::unbounded_channel::(); - // launch message handler thread + let (network_send, network_recv) = mpsc::unbounded_channel::>(); + // Get a reference to the beacon chain store let store = beacon_chain.store.clone(); - let message_handler_send = MessageHandler::spawn( - beacon_chain, + // launch the router task + let router_send = Router::spawn( + beacon_chain.clone(), network_send.clone(), executor, network_log.clone(), @@ -53,82 +73,42 @@ impl Service { let propagation_percentage = config.propagation_percentage; // launch libp2p service - let (network_globals, mut libp2p_service) = - LibP2PService::new(config, network_log.clone())?; + let (network_globals, mut libp2p) = LibP2PService::new(config, network_log.clone())?; - for enr in load_dht::(store.clone()) { - libp2p_service.swarm.add_enr(enr); + for enr in load_dht::(store.clone()) { + libp2p.swarm.add_enr(enr); } // A delay used to initialise code after the network has started // This is currently used to obtain the listening addresses from the libp2p service. let initial_delay = Delay::new(Instant::now() + Duration::from_secs(1)); - let libp2p_exit = spawn_service::( - libp2p_service, - network_recv, - message_handler_send, - executor, - store, - network_globals.clone(), - initial_delay, - network_log.clone(), - propagation_percentage, - )?; + // create the attestation service + let attestation_service = + AttestationService::new(beacon_chain, network_globals.clone(), &network_log); - let network_service = Service { - libp2p_port: config.libp2p_port, - network_globals, - _libp2p_exit: libp2p_exit, - _network_send: network_send.clone(), - _phantom: PhantomData, + // create the network service and spawn the task + let network_service = NetworkService { + libp2p, + attestation_service, + network_recv, + router_send, + store, + network_globals: network_globals.clone(), + initial_delay, + log: network_log, + propagation_percentage, }; - Ok((Arc::new(network_service), network_send)) - } + let network_exit = spawn_service(network_service, &executor)?; - /// Returns the local ENR from the underlying Discv5 behaviour that external peers may connect - /// to. - pub fn local_enr(&self) -> Option { - self.network_globals.local_enr.read().clone() - } - - /// Returns the local libp2p PeerID. - pub fn local_peer_id(&self) -> PeerId { - self.network_globals.peer_id.read().clone() - } - - /// Returns the list of `Multiaddr` that the underlying libp2p instance is listening on. - pub fn listen_multiaddrs(&self) -> Vec { - self.network_globals.listen_multiaddrs.read().clone() - } - - /// Returns the libp2p port that this node has been configured to listen using. - pub fn listen_port(&self) -> u16 { - self.libp2p_port - } - - /// Returns the number of libp2p connected peers. - pub fn connected_peers(&self) -> usize { - self.network_globals.connected_peers.load(Ordering::Relaxed) - } - - /// Returns the set of `PeerId` that are connected via libp2p. - pub fn connected_peer_set(&self) -> HashSet { - self.network_globals.connected_peer_set.read().clone() + Ok((network_globals, network_send, network_exit)) } } fn spawn_service( - mut libp2p_service: LibP2PService, - mut network_recv: mpsc::UnboundedReceiver, - mut message_handler_send: mpsc::UnboundedSender, + mut service: NetworkService, executor: &TaskExecutor, - store: Arc, - network_globals: Arc, - mut initial_delay: Delay, - log: slog::Logger, - propagation_percentage: Option, ) -> error::Result> { let (network_exit, mut exit_rx) = tokio::sync::oneshot::channel(); @@ -136,25 +116,26 @@ fn spawn_service( executor.spawn( futures::future::poll_fn(move || -> Result<_, ()> { + let log = &service.log; - if !initial_delay.is_elapsed() { - if let Ok(Async::Ready(_)) = initial_delay.poll() { - let multi_addrs = Swarm::listeners(&libp2p_service.swarm).cloned().collect(); - *network_globals.listen_multiaddrs.write() = multi_addrs; + if !service.initial_delay.is_elapsed() { + if let Ok(Async::Ready(_)) = service.initial_delay.poll() { + let multi_addrs = Swarm::listeners(&service.libp2p.swarm).cloned().collect(); + *service.network_globals.listen_multiaddrs.write() = multi_addrs; } } // perform termination tasks when the network is being shutdown if let Ok(Async::Ready(_)) | Err(_) = exit_rx.poll() { // network thread is terminating - let enrs: Vec = libp2p_service.swarm.enr_entries().cloned().collect(); + let enrs: Vec = service.libp2p.swarm.enr_entries().cloned().collect(); debug!( log, "Persisting DHT to store"; "Number of peers" => format!("{}", enrs.len()), ); - match persist_dht::(store.clone(), enrs) { + match persist_dht::(service.store.clone(), enrs) { Err(e) => error!( log, "Failed to persist DHT on drop"; @@ -173,11 +154,11 @@ fn spawn_service( // processes the network channel before processing the libp2p swarm loop { // poll the network channel - match network_recv.poll() { + match service.network_recv.poll() { Ok(Async::Ready(Some(message))) => match message { NetworkMessage::RPC(peer_id, rpc_event) => { trace!(log, "Sending RPC"; "rpc" => format!("{}", rpc_event)); - libp2p_service.swarm.send_rpc(peer_id, rpc_event); + service.libp2p.swarm.send_rpc(peer_id, rpc_event); } NetworkMessage::Propagate { propagation_source, @@ -186,7 +167,7 @@ fn spawn_service( // TODO: Remove this for mainnet // randomly prevents propagation let mut should_send = true; - if let Some(percentage) = propagation_percentage { + if let Some(percentage) = service.propagation_percentage { // not exact percentage but close enough let rand = rand::random::() % 100; if rand > percentage { @@ -201,16 +182,16 @@ fn spawn_service( "propagation_peer" => format!("{:?}", propagation_source), "message_id" => message_id.to_string(), ); - libp2p_service + service.libp2p .swarm .propagate_message(&propagation_source, message_id); } } - NetworkMessage::Publish { topics, message } => { + NetworkMessage::Publish { messages } => { // TODO: Remove this for mainnet // randomly prevents propagation let mut should_send = true; - if let Some(percentage) = propagation_percentage { + if let Some(percentage) = service.propagation_percentage { // not exact percentage but close enough let rand = rand::random::() % 100; if rand > percentage { @@ -219,18 +200,31 @@ fn spawn_service( } } if !should_send { - info!(log, "Random filter did not publish message"); + info!(log, "Random filter did not publish messages"); } else { - debug!(log, "Sending pubsub message"; "topics" => format!("{:?}",topics)); - libp2p_service.swarm.publish(&topics, message); + let mut unique_topics = Vec::new(); + for message in &messages { + for topic in message.topics() { + if !unique_topics.contains(&topic) { + unique_topics.push(topic); + } + } + } + debug!(log, "Sending pubsub messages"; "count" => messages.len(), "topics" => format!("{:?}", unique_topics)); + service.libp2p.swarm.publish(messages); } } NetworkMessage::Disconnect { peer_id } => { - libp2p_service.disconnect_and_ban_peer( + service.libp2p.disconnect_and_ban_peer( peer_id, std::time::Duration::from_secs(BAN_PEER_TIMEOUT), ); } + NetworkMessage::Subscribe { subscriptions } => + { + // the result is dropped as it used solely for ergonomics + let _ = service.attestation_service.validator_subscriptions(subscriptions); + } }, Ok(Async::NotReady) => break, Ok(Async::Ready(None)) => { @@ -244,10 +238,24 @@ fn spawn_service( } } + // process any attestation service events + // NOTE: This must come after the network message processing as that may trigger events in + // the attestation service. + while let Ok(Async::Ready(Some(attestation_service_message))) = service.attestation_service.poll() { + match attestation_service_message { + // TODO: Implement + AttServiceMessage::Subscribe(_subnet) => { }, + AttServiceMessage::Unsubscribe(_subnet) => { }, + AttServiceMessage::EnrAdd(_subnet) => { }, + AttServiceMessage::EnrRemove(_subnet) => { }, + AttServiceMessage::DiscoverPeers(_subnet) => { }, + } + } + let mut peers_to_ban = Vec::new(); // poll the swarm loop { - match libp2p_service.poll() { + match service.libp2p.poll() { Ok(Async::Ready(Some(event))) => match event { Libp2pEvent::RPC(peer_id, rpc_event) => { // trace!(log, "Received RPC"; "rpc" => format!("{}", rpc_event)); @@ -256,21 +264,21 @@ fn spawn_service( if let RPCEvent::Request(_, RPCRequest::Goodbye(_)) = rpc_event { peers_to_ban.push(peer_id.clone()); }; - message_handler_send - .try_send(HandlerMessage::RPC(peer_id, rpc_event)) - .map_err(|_| { debug!(log, "Failed to send RPC to handler");} )?; + service.router_send + .try_send(RouterMessage::RPC(peer_id, rpc_event)) + .map_err(|_| { debug!(log, "Failed to send RPC to router");} )?; } Libp2pEvent::PeerDialed(peer_id) => { debug!(log, "Peer Dialed"; "peer_id" => format!("{:?}", peer_id)); - message_handler_send - .try_send(HandlerMessage::PeerDialed(peer_id)) - .map_err(|_| { debug!(log, "Failed to send peer dialed to handler");})?; + service.router_send + .try_send(RouterMessage::PeerDialed(peer_id)) + .map_err(|_| { debug!(log, "Failed to send peer dialed to router");})?; } Libp2pEvent::PeerDisconnected(peer_id) => { debug!(log, "Peer Disconnected"; "peer_id" => format!("{:?}", peer_id)); - message_handler_send - .try_send(HandlerMessage::PeerDisconnected(peer_id)) - .map_err(|_| { debug!(log, "Failed to send peer disconnect to handler");})?; + service.router_send + .try_send(RouterMessage::PeerDisconnected(peer_id)) + .map_err(|_| { debug!(log, "Failed to send peer disconnect to router");})?; } Libp2pEvent::PubsubMessage { id, @@ -278,9 +286,9 @@ fn spawn_service( message, .. } => { - message_handler_send - .try_send(HandlerMessage::PubsubMessage(id, source, message)) - .map_err(|_| { debug!(log, "Failed to send pubsub message to handler");})?; + service.router_send + .try_send(RouterMessage::PubsubMessage(id, source, message)) + .map_err(|_| { debug!(log, "Failed to send pubsub message to router");})?; } Libp2pEvent::PeerSubscribed(_, _) => {} }, @@ -292,7 +300,7 @@ fn spawn_service( // ban and disconnect any peers that sent Goodbye requests while let Some(peer_id) = peers_to_ban.pop() { - libp2p_service.disconnect_and_ban_peer( + service.libp2p.disconnect_and_ban_peer( peer_id.clone(), std::time::Duration::from_secs(BAN_PEER_TIMEOUT), ); @@ -308,14 +316,15 @@ fn spawn_service( /// Types of messages that the network service can receive. #[derive(Debug)] -pub enum NetworkMessage { - /// Send an RPC message to the libp2p service. - RPC(PeerId, RPCEvent), - /// Publish a message to gossipsub. - Publish { - topics: Vec, - message: PubsubMessage, +pub enum NetworkMessage { + /// Subscribes a list of validators to specific slots for attestation duties. + Subscribe { + subscriptions: Vec, }, + /// Send an RPC message to the libp2p service. + RPC(PeerId, RPCEvent), + /// Publish a list of messages to the gossipsub protocol. + Publish { messages: Vec> }, /// Propagate a received gossipsub message. Propagate { propagation_source: PeerId, diff --git a/beacon_node/network/src/sync/manager.rs b/beacon_node/network/src/sync/manager.rs index ae542b324..0b6f5a4f2 100644 --- a/beacon_node/network/src/sync/manager.rs +++ b/beacon_node/network/src/sync/manager.rs @@ -35,7 +35,7 @@ use super::network_context::SyncNetworkContext; use super::range_sync::{Batch, BatchProcessResult, RangeSync}; -use crate::message_processor::PeerSyncInfo; +use crate::router::processor::PeerSyncInfo; use crate::service::NetworkMessage; use beacon_chain::{BeaconChain, BeaconChainTypes, BlockProcessingOutcome}; use eth2_libp2p::rpc::methods::*; @@ -153,7 +153,7 @@ pub struct SyncManager { input_channel: mpsc::UnboundedReceiver>, /// A network context to contact the network service. - network: SyncNetworkContext, + network: SyncNetworkContext, /// The object handling long-range batch load-balanced syncing. range_sync: RangeSync, @@ -180,7 +180,7 @@ pub struct SyncManager { pub fn spawn( executor: &tokio::runtime::TaskExecutor, beacon_chain: Weak>, - network_send: mpsc::UnboundedSender, + network_send: mpsc::UnboundedSender>, log: slog::Logger, ) -> ( mpsc::UnboundedSender>, @@ -391,7 +391,7 @@ impl SyncManager { // we have the correct block, try and process it if let Some(chain) = self.chain.upgrade() { - match chain.process_block(block.clone()) { + match BlockProcessingOutcome::shim(chain.process_block(block.clone())) { Ok(outcome) => { match outcome { BlockProcessingOutcome::Processed { block_root } => { @@ -597,7 +597,7 @@ impl SyncManager { .downloaded_blocks .pop() .expect("There is always at least one block in the queue"); - match chain.process_block(newest_block.clone()) { + match BlockProcessingOutcome::shim(chain.process_block(newest_block.clone())) { Ok(BlockProcessingOutcome::ParentUnknown { .. }) => { // need to keep looking for parents // add the block back to the queue and continue the search @@ -642,7 +642,7 @@ impl SyncManager { while let Some(block) = parent_request.downloaded_blocks.pop() { // check if the chain exists if let Some(chain) = self.chain.upgrade() { - match chain.process_block(block) { + match BlockProcessingOutcome::shim(chain.process_block(block)) { Ok(BlockProcessingOutcome::Processed { .. }) | Ok(BlockProcessingOutcome::BlockIsAlreadyKnown { .. }) => {} // continue to the next block diff --git a/beacon_node/network/src/sync/mod.rs b/beacon_node/network/src/sync/mod.rs index e9bc70e55..b51cd78f9 100644 --- a/beacon_node/network/src/sync/mod.rs +++ b/beacon_node/network/src/sync/mod.rs @@ -5,9 +5,4 @@ pub mod manager; mod network_context; mod range_sync; -/// Currently implemented sync methods. -pub enum SyncMethod { - SimpleSync, -} - pub use manager::SyncMessage; diff --git a/beacon_node/network/src/sync/network_context.rs b/beacon_node/network/src/sync/network_context.rs index f2cd7a970..2d16391a0 100644 --- a/beacon_node/network/src/sync/network_context.rs +++ b/beacon_node/network/src/sync/network_context.rs @@ -1,7 +1,7 @@ //! Provides network functionality for the Syncing thread. This fundamentally wraps a network //! channel and stores a global RPC ID to perform requests. -use crate::message_processor::status_message; +use crate::router::processor::status_message; use crate::service::NetworkMessage; use beacon_chain::{BeaconChain, BeaconChainTypes}; use eth2_libp2p::rpc::methods::*; @@ -10,20 +10,21 @@ use eth2_libp2p::PeerId; use slog::{debug, trace, warn}; use std::sync::Weak; use tokio::sync::mpsc; +use types::EthSpec; /// Wraps a Network channel to employ various RPC related network functionality for the Sync manager. This includes management of a global RPC request Id. -pub struct SyncNetworkContext { +pub struct SyncNetworkContext { /// The network channel to relay messages to the Network service. - network_send: mpsc::UnboundedSender, + network_send: mpsc::UnboundedSender>, request_id: RequestId, /// Logger for the `SyncNetworkContext`. log: slog::Logger, } -impl SyncNetworkContext { - pub fn new(network_send: mpsc::UnboundedSender, log: slog::Logger) -> Self { +impl SyncNetworkContext { + pub fn new(network_send: mpsc::UnboundedSender>, log: slog::Logger) -> Self { Self { network_send, request_id: 0, @@ -31,9 +32,9 @@ impl SyncNetworkContext { } } - pub fn status_peer( + pub fn status_peer( &mut self, - chain: Weak>, + chain: Weak>, peer_id: PeerId, ) { if let Some(chain) = chain.upgrade() { @@ -117,7 +118,7 @@ impl SyncNetworkContext { pub fn send_rpc_request( &mut self, peer_id: PeerId, - rpc_request: RPCRequest, + rpc_request: RPCRequest, ) -> Result { let request_id = self.request_id; self.request_id += 1; @@ -125,7 +126,11 @@ impl SyncNetworkContext { Ok(request_id) } - fn send_rpc_event(&mut self, peer_id: PeerId, rpc_event: RPCEvent) -> Result<(), &'static str> { + fn send_rpc_event( + &mut self, + peer_id: PeerId, + rpc_event: RPCEvent, + ) -> Result<(), &'static str> { self.network_send .try_send(NetworkMessage::RPC(peer_id, rpc_event)) .map_err(|_| { diff --git a/beacon_node/network/src/sync/range_sync/batch_processing.rs b/beacon_node/network/src/sync/range_sync/batch_processing.rs index 484bab9ba..e518d0c4d 100644 --- a/beacon_node/network/src/sync/range_sync/batch_processing.rs +++ b/beacon_node/network/src/sync/range_sync/batch_processing.rs @@ -1,7 +1,7 @@ use super::batch::Batch; -use crate::message_processor::FUTURE_SLOT_TOLERANCE; +use crate::router::processor::FUTURE_SLOT_TOLERANCE; use crate::sync::manager::SyncMessage; -use beacon_chain::{BeaconChain, BeaconChainTypes, BlockProcessingOutcome}; +use beacon_chain::{BeaconChain, BeaconChainTypes, BlockError}; use slog::{debug, error, trace, warn}; use std::sync::{Arc, Weak}; use tokio::sync::mpsc; @@ -54,116 +54,78 @@ fn process_batch( batch: &Batch, log: &slog::Logger, ) -> Result<(), String> { - let mut successful_block_import = false; - for block in &batch.downloaded_blocks { - if let Some(chain) = chain.upgrade() { - let processing_result = chain.process_block(block.clone()); - - if let Ok(outcome) = processing_result { - match outcome { - BlockProcessingOutcome::Processed { block_root } => { - // The block was valid and we processed it successfully. - trace!( - log, "Imported block from network"; - "slot" => block.slot(), - "block_root" => format!("{}", block_root), - ); - successful_block_import = true; - } - BlockProcessingOutcome::ParentUnknown { parent, .. } => { - // blocks should be sequential and all parents should exist - warn!( - log, "Parent block is unknown"; - "parent_root" => format!("{}", parent), - "baby_block_slot" => block.slot(), - ); - if successful_block_import { - run_fork_choice(chain, log); - } - return Err(format!( - "Block at slot {} has an unknown parent.", - block.slot() - )); - } - BlockProcessingOutcome::BlockIsAlreadyKnown => { - // this block is already known to us, move to the next - debug!( - log, "Imported a block that is already known"; - "block_slot" => block.slot(), - ); - } - BlockProcessingOutcome::FutureSlot { - present_slot, - block_slot, - } => { - if present_slot + FUTURE_SLOT_TOLERANCE >= block_slot { - // The block is too far in the future, drop it. - warn!( - log, "Block is ahead of our slot clock"; - "msg" => "block for future slot rejected, check your time", - "present_slot" => present_slot, - "block_slot" => block_slot, - "FUTURE_SLOT_TOLERANCE" => FUTURE_SLOT_TOLERANCE, - ); - if successful_block_import { - run_fork_choice(chain, log); - } - return Err(format!( - "Block at slot {} is too far in the future", - block.slot() - )); - } else { - // The block is in the future, but not too far. - debug!( - log, "Block is slightly ahead of our slot clock, ignoring."; - "present_slot" => present_slot, - "block_slot" => block_slot, - "FUTURE_SLOT_TOLERANCE" => FUTURE_SLOT_TOLERANCE, - ); - } - } - BlockProcessingOutcome::WouldRevertFinalizedSlot { .. } => { - debug!( - log, "Finalized or earlier block processed"; - "outcome" => format!("{:?}", outcome), - ); - // block reached our finalized slot or was earlier, move to the next block - } - BlockProcessingOutcome::GenesisBlock => { - debug!( - log, "Genesis block was processed"; - "outcome" => format!("{:?}", outcome), - ); - } - _ => { - warn!( - log, "Invalid block received"; - "msg" => "peer sent invalid block", - "outcome" => format!("{:?}", outcome), - ); - if successful_block_import { - run_fork_choice(chain, log); - } - return Err(format!("Invalid block at slot {}", block.slot())); - } + if let Some(chain) = chain.upgrade() { + match chain.process_chain_segment(batch.downloaded_blocks.clone()) { + Ok(roots) => { + trace!( + log, "Imported blocks from network"; + "count" => roots.len(), + ); + } + Err(BlockError::ParentUnknown(parent)) => { + // blocks should be sequential and all parents should exist + warn!( + log, "Parent block is unknown"; + "parent_root" => format!("{}", parent), + ); + } + Err(BlockError::BlockIsAlreadyKnown) => { + // this block is already known to us, move to the next + debug!( + log, "Imported a block that is already known"; + ); + } + Err(BlockError::FutureSlot { + present_slot, + block_slot, + }) => { + if present_slot + FUTURE_SLOT_TOLERANCE >= block_slot { + // The block is too far in the future, drop it. + warn!( + log, "Block is ahead of our slot clock"; + "msg" => "block for future slot rejected, check your time", + "present_slot" => present_slot, + "block_slot" => block_slot, + "FUTURE_SLOT_TOLERANCE" => FUTURE_SLOT_TOLERANCE, + ); + } else { + // The block is in the future, but not too far. + debug!( + log, "Block is slightly ahead of our slot clock, ignoring."; + "present_slot" => present_slot, + "block_slot" => block_slot, + "FUTURE_SLOT_TOLERANCE" => FUTURE_SLOT_TOLERANCE, + ); } - } else { + } + Err(BlockError::WouldRevertFinalizedSlot { .. }) => { + debug!( + log, "Finalized or earlier block processed"; + ); + // block reached our finalized slot or was earlier, move to the next block + } + Err(BlockError::GenesisBlock) => { + debug!( + log, "Genesis block was processed"; + ); + } + Err(BlockError::BeaconChainError(e)) => { warn!( log, "BlockProcessingFailure"; "msg" => "unexpected condition in processing block.", - "outcome" => format!("{:?}", processing_result) + "outcome" => format!("{:?}", e) + ); + } + other => { + warn!( + log, "Invalid block received"; + "msg" => "peer sent invalid block", + "outcome" => format!("{:?}", other), ); - if successful_block_import { - run_fork_choice(chain, log); - } - return Err(format!( - "Unexpected block processing error: {:?}", - processing_result - )); } - } else { - return Ok(()); // terminate early due to dropped beacon chain } + } else { + return Ok(()); // terminate early due to dropped beacon chain } // Batch completed successfully, run fork choice. diff --git a/beacon_node/network/src/sync/range_sync/chain.rs b/beacon_node/network/src/sync/range_sync/chain.rs index e548134f7..8516e8df3 100644 --- a/beacon_node/network/src/sync/range_sync/chain.rs +++ b/beacon_node/network/src/sync/range_sync/chain.rs @@ -17,7 +17,7 @@ use types::{Hash256, SignedBeaconBlock, Slot}; /// downvote peers with poor bandwidth. This can be set arbitrarily high, in which case the /// responder will fill the response up to the max request size, assuming they have the bandwidth /// to do so. -pub const BLOCKS_PER_BATCH: u64 = 50; +pub const BLOCKS_PER_BATCH: u64 = 64; /// The number of times to retry a batch before the chain is considered failed and removed. const MAX_BATCH_RETRIES: u8 = 5; @@ -141,7 +141,7 @@ impl SyncingChain { /// batch. pub fn on_block_response( &mut self, - network: &mut SyncNetworkContext, + network: &mut SyncNetworkContext, request_id: RequestId, beacon_block: &Option>, ) -> Option<()> { @@ -161,7 +161,7 @@ impl SyncingChain { /// failed indicating that further batches are required. fn handle_completed_batch( &mut self, - network: &mut SyncNetworkContext, + network: &mut SyncNetworkContext, batch: Batch, ) { // An entire batch of blocks has been received. This functions checks to see if it can be processed, @@ -255,7 +255,7 @@ impl SyncingChain { /// of the batch processor. pub fn on_batch_process_result( &mut self, - network: &mut SyncNetworkContext, + network: &mut SyncNetworkContext, processing_id: u64, batch: &mut Option>, result: &BatchProcessResult, @@ -385,7 +385,11 @@ impl SyncingChain { // TODO: Batches could have been partially downloaded due to RPC size-limit restrictions. We // need to add logic for partial batch downloads. Potentially, if another peer returns the same // batch, we try a partial download. - fn handle_invalid_batch(&mut self, network: &mut SyncNetworkContext, batch: Batch) { + fn handle_invalid_batch( + &mut self, + network: &mut SyncNetworkContext, + batch: Batch, + ) { // The current batch could not be processed, indicating either the current or previous // batches are invalid @@ -415,7 +419,11 @@ impl SyncingChain { /// /// If the re-downloaded batch is different to the original and can be processed, the original /// peer will be downvoted. - fn reprocess_batch(&mut self, network: &mut SyncNetworkContext, mut batch: Batch) { + fn reprocess_batch( + &mut self, + network: &mut SyncNetworkContext, + mut batch: Batch, + ) { // marks the batch as attempting to be reprocessed by hashing the downloaded blocks batch.original_hash = Some(batch.hash()); @@ -455,7 +463,11 @@ impl SyncingChain { /// This chain has been requested to start syncing. /// /// This could be new chain, or an old chain that is being resumed. - pub fn start_syncing(&mut self, network: &mut SyncNetworkContext, local_finalized_slot: Slot) { + pub fn start_syncing( + &mut self, + network: &mut SyncNetworkContext, + local_finalized_slot: Slot, + ) { // A local finalized slot is provided as other chains may have made // progress whilst this chain was Stopped or paused. If so, update the `processed_batch_id` to // accommodate potentially downloaded batches from other chains. Also prune any old batches @@ -490,7 +502,7 @@ impl SyncingChain { /// Add a peer to the chain. /// /// If the chain is active, this starts requesting batches from this peer. - pub fn add_peer(&mut self, network: &mut SyncNetworkContext, peer_id: PeerId) { + pub fn add_peer(&mut self, network: &mut SyncNetworkContext, peer_id: PeerId) { self.peer_pool.insert(peer_id.clone()); // do not request blocks if the chain is not syncing if let ChainSyncingState::Stopped = self.state { @@ -503,7 +515,7 @@ impl SyncingChain { } /// Sends a STATUS message to all peers in the peer pool. - pub fn status_peers(&self, network: &mut SyncNetworkContext) { + pub fn status_peers(&self, network: &mut SyncNetworkContext) { for peer_id in self.peer_pool.iter() { network.status_peer(self.chain.clone(), peer_id.clone()); } @@ -517,7 +529,7 @@ impl SyncingChain { /// this chain. pub fn inject_error( &mut self, - network: &mut SyncNetworkContext, + network: &mut SyncNetworkContext, peer_id: &PeerId, request_id: RequestId, ) -> Option { @@ -541,7 +553,7 @@ impl SyncingChain { /// `MAX_BATCH_RETRIES`. pub fn failed_batch( &mut self, - network: &mut SyncNetworkContext, + network: &mut SyncNetworkContext, mut batch: Batch, ) -> ProcessingResult { batch.retries += 1; @@ -575,7 +587,7 @@ impl SyncingChain { /// Attempts to request the next required batches from the peer pool if the chain is syncing. It will exhaust the peer /// pool and left over batches until the batch buffer is reached or all peers are exhausted. - fn request_batches(&mut self, network: &mut SyncNetworkContext) { + fn request_batches(&mut self, network: &mut SyncNetworkContext) { if let ChainSyncingState::Syncing = self.state { while self.send_range_request(network) {} } @@ -583,7 +595,7 @@ impl SyncingChain { /// Requests the next required batch from a peer. Returns true, if there was a peer available /// to send a request and there are batches to request, false otherwise. - fn send_range_request(&mut self, network: &mut SyncNetworkContext) -> bool { + fn send_range_request(&mut self, network: &mut SyncNetworkContext) -> bool { // find the next pending batch and request it from the peer if let Some(peer_id) = self.get_next_peer() { if let Some(batch) = self.get_next_batch(peer_id) { @@ -669,7 +681,11 @@ impl SyncingChain { } /// Requests the provided batch from the provided peer. - fn send_batch(&mut self, network: &mut SyncNetworkContext, batch: Batch) { + fn send_batch( + &mut self, + network: &mut SyncNetworkContext, + batch: Batch, + ) { let request = batch.to_blocks_by_range_request(); if let Ok(request_id) = network.blocks_by_range_request(batch.current_peer.clone(), request) { diff --git a/beacon_node/network/src/sync/range_sync/chain_collection.rs b/beacon_node/network/src/sync/range_sync/chain_collection.rs index beb39265a..8ab2627ee 100644 --- a/beacon_node/network/src/sync/range_sync/chain_collection.rs +++ b/beacon_node/network/src/sync/range_sync/chain_collection.rs @@ -4,7 +4,7 @@ //! with this struct to to simplify the logic of the other layers of sync. use super::chain::{ChainSyncingState, SyncingChain}; -use crate::message_processor::PeerSyncInfo; +use crate::router::processor::PeerSyncInfo; use crate::sync::manager::SyncMessage; use crate::sync::network_context::SyncNetworkContext; use beacon_chain::{BeaconChain, BeaconChainTypes}; @@ -103,7 +103,11 @@ impl ChainCollection { /// /// This removes any out-dated chains, swaps to any higher priority finalized chains and /// updates the state of the collection. - pub fn update_finalized(&mut self, network: &mut SyncNetworkContext, log: &slog::Logger) { + pub fn update_finalized( + &mut self, + network: &mut SyncNetworkContext, + log: &slog::Logger, + ) { let local_slot = match self.beacon_chain.upgrade() { Some(chain) => { let local = match PeerSyncInfo::from_chain(&chain) { @@ -197,7 +201,7 @@ impl ChainCollection { #[allow(clippy::too_many_arguments)] pub fn new_head_chain( &mut self, - network: &mut SyncNetworkContext, + network: &mut SyncNetworkContext, remote_finalized_slot: Slot, target_head: Hash256, target_slot: Slot, @@ -277,7 +281,11 @@ impl ChainCollection { /// /// This removes chains with no peers, or chains whose start block slot is less than our current /// finalized block slot. - pub fn purge_outdated_chains(&mut self, network: &mut SyncNetworkContext, log: &slog::Logger) { + pub fn purge_outdated_chains( + &mut self, + network: &mut SyncNetworkContext, + log: &slog::Logger, + ) { // Remove any chains that have no peers self.finalized_chains .retain(|chain| !chain.peer_pool.is_empty()); @@ -349,7 +357,7 @@ impl ChainCollection { /// This will re-status the chains peers on removal. The index must exist. pub fn remove_chain( &mut self, - network: &mut SyncNetworkContext, + network: &mut SyncNetworkContext, index: usize, log: &slog::Logger, ) { diff --git a/beacon_node/network/src/sync/range_sync/range.rs b/beacon_node/network/src/sync/range_sync/range.rs index 59c6ff598..2d6434251 100644 --- a/beacon_node/network/src/sync/range_sync/range.rs +++ b/beacon_node/network/src/sync/range_sync/range.rs @@ -42,7 +42,7 @@ use super::chain::ProcessingResult; use super::chain_collection::{ChainCollection, SyncState}; use super::{Batch, BatchProcessResult}; -use crate::message_processor::PeerSyncInfo; +use crate::router::processor::PeerSyncInfo; use crate::sync::manager::SyncMessage; use crate::sync::network_context::SyncNetworkContext; use beacon_chain::{BeaconChain, BeaconChainTypes}; @@ -108,7 +108,7 @@ impl RangeSync { /// prioritised by peer-pool size. pub fn add_peer( &mut self, - network: &mut SyncNetworkContext, + network: &mut SyncNetworkContext, peer_id: PeerId, remote: PeerSyncInfo, ) { @@ -228,7 +228,7 @@ impl RangeSync { /// This request could complete a chain or simply add to its progress. pub fn blocks_by_range_response( &mut self, - network: &mut SyncNetworkContext, + network: &mut SyncNetworkContext, peer_id: PeerId, request_id: RequestId, beacon_block: Option>, @@ -255,7 +255,7 @@ impl RangeSync { pub fn handle_block_process_result( &mut self, - network: &mut SyncNetworkContext, + network: &mut SyncNetworkContext, processing_id: u64, batch: Batch, result: BatchProcessResult, @@ -326,7 +326,11 @@ impl RangeSync { /// A peer has disconnected. This removes the peer from any ongoing chains and mappings. A /// disconnected peer could remove a chain - pub fn peer_disconnect(&mut self, network: &mut SyncNetworkContext, peer_id: &PeerId) { + pub fn peer_disconnect( + &mut self, + network: &mut SyncNetworkContext, + peer_id: &PeerId, + ) { // if the peer is in the awaiting head mapping, remove it self.awaiting_head_peers.remove(&peer_id); @@ -340,7 +344,7 @@ impl RangeSync { /// When a peer gets removed, both the head and finalized chains need to be searched to check which pool the peer is in. The chain may also have a batch or batches awaiting /// for this peer. If so we mark the batch as failed. The batch may then hit it's maximum /// retries. In this case, we need to remove the chain and re-status all the peers. - fn remove_peer(&mut self, network: &mut SyncNetworkContext, peer_id: &PeerId) { + fn remove_peer(&mut self, network: &mut SyncNetworkContext, peer_id: &PeerId) { if let Some((index, ProcessingResult::RemoveChain)) = self.chains.head_finalized_request(|chain| { if chain.peer_pool.remove(peer_id) { @@ -370,7 +374,7 @@ impl RangeSync { /// been too many failed attempts for the batch, remove the chain. pub fn inject_error( &mut self, - network: &mut SyncNetworkContext, + network: &mut SyncNetworkContext, peer_id: PeerId, request_id: RequestId, ) { diff --git a/beacon_node/rest_api/Cargo.toml b/beacon_node/rest_api/Cargo.toml index 2b2d2b829..c754ba481 100644 --- a/beacon_node/rest_api/Cargo.toml +++ b/beacon_node/rest_api/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "rest_api" -version = "0.1.0" -authors = ["Paul Hauner ", "Luke Anderson "] +version = "0.2.0" +authors = ["Paul Hauner ", "Age Manning ", "Luke Anderson "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] bls = { path = "../../eth2/utils/bls" } +rest_types = { path = "../../eth2/utils/rest_types" } beacon_chain = { path = "../beacon_chain" } network = { path = "../network" } eth2-libp2p = { path = "../eth2-libp2p" } @@ -24,7 +25,6 @@ state_processing = { path = "../../eth2/state_processing" } types = { path = "../../eth2/types" } http = "0.1" hyper = "0.12" -exit-future = "0.1.4" tokio = "0.1.22" url = "2.1" lazy_static = "1.3.0" @@ -35,6 +35,7 @@ hex = "0.3" parking_lot = "0.9" futures = "0.1.29" operation_pool = { path = "../../eth2/operation_pool" } +rayon = "1.3.0" [dev-dependencies] remote_beacon_node = { path = "../../eth2/utils/remote_beacon_node" } diff --git a/beacon_node/rest_api/src/beacon.rs b/beacon_node/rest_api/src/beacon.rs index 8b12628a4..69e3c6108 100644 --- a/beacon_node/rest_api/src/beacon.rs +++ b/beacon_node/rest_api/src/beacon.rs @@ -5,29 +5,17 @@ use crate::{ApiError, ApiResult, BoxFut, UrlQuery}; use beacon_chain::{BeaconChain, BeaconChainTypes, StateSkipConfig}; use futures::{Future, Stream}; use hyper::{Body, Request}; -use serde::{Deserialize, Serialize}; -use ssz_derive::{Decode, Encode}; +use rest_types::{ + BlockResponse, CanonicalHeadResponse, Committee, HeadBeaconBlock, StateResponse, + ValidatorRequest, ValidatorResponse, +}; use std::sync::Arc; use store::Store; use types::{ - AttesterSlashing, BeaconState, CommitteeIndex, EthSpec, Hash256, ProposerSlashing, - PublicKeyBytes, RelativeEpoch, SignedBeaconBlock, Slot, Validator, + AttesterSlashing, BeaconState, EthSpec, Hash256, ProposerSlashing, PublicKeyBytes, + RelativeEpoch, Slot, }; -/// Information about the block and state that are at head of the beacon chain. -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] -pub struct CanonicalHeadResponse { - pub slot: Slot, - pub block_root: Hash256, - pub state_root: Hash256, - pub finalized_slot: Slot, - pub finalized_block_root: Hash256, - pub justified_slot: Slot, - pub justified_block_root: Hash256, - pub previous_justified_slot: Slot, - pub previous_justified_block_root: Hash256, -} - /// HTTP handler to return a `BeaconBlock` at a given `root` or `slot`. pub fn get_head( req: Request, @@ -62,15 +50,7 @@ pub fn get_head( ResponseBuilder::new(&req)?.body(&head) } -/// Information about a block that is at the head of a chain. May or may not represent the -/// canonical head. -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] -pub struct HeadBeaconBlock { - pub beacon_block_root: Hash256, - pub beacon_block_slot: Slot, -} - -/// HTTP handler to return a list of head block roots. +/// HTTP handler to return a list of head BeaconBlocks. pub fn get_heads( req: Request, beacon_chain: Arc>, @@ -87,14 +67,7 @@ pub fn get_heads( ResponseBuilder::new(&req)?.body(&heads) } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] -#[serde(bound = "T: EthSpec")] -pub struct BlockResponse { - pub root: Hash256, - pub beacon_block: SignedBeaconBlock, -} - -/// HTTP handler to return a `SignedBeaconBlock` at a given `root` or `slot`. +/// HTTP handler to return a `BeaconBlock` at a given `root` or `slot`. pub fn get_block( req: Request, beacon_chain: Arc>, @@ -158,14 +131,6 @@ pub fn get_fork( ResponseBuilder::new(&req)?.body(&beacon_chain.head()?.beacon_state.fork) } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] -pub struct ValidatorResponse { - pub pubkey: PublicKeyBytes, - pub validator_index: Option, - pub balance: Option, - pub validator: Option, -} - /// HTTP handler to which accepts a query string of a list of validator pubkeys and maps it to a /// `ValidatorResponse`. /// @@ -246,13 +211,6 @@ pub fn get_active_validators( ResponseBuilder::new(&req)?.body(&validators) } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] -pub struct ValidatorRequest { - /// If set to `None`, uses the canonical head state. - pub state_root: Option, - pub pubkeys: Vec, -} - /// HTTP handler to which accepts a `ValidatorRequest` and returns a `ValidatorResponse` for /// each of the given `pubkeys`. When `state_root` is `None`, the canonical head is used. /// @@ -365,13 +323,6 @@ fn validator_response_by_pubkey( } } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] -pub struct Committee { - pub slot: Slot, - pub index: CommitteeIndex, - pub committee: Vec, -} - /// HTTP handler pub fn get_committees( req: Request, @@ -405,13 +356,6 @@ pub fn get_committees( ResponseBuilder::new(&req)?.body(&committees) } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] -#[serde(bound = "T: EthSpec")] -pub struct StateResponse { - pub root: Hash256, - pub beacon_state: BeaconState, -} - /// HTTP handler to return a `BeaconState` at a given `root` or `slot`. /// /// Will not return a state if the request slot is in the future. Will return states higher than diff --git a/beacon_node/rest_api/src/helpers.rs b/beacon_node/rest_api/src/helpers.rs index 8d014efbb..708b05221 100644 --- a/beacon_node/rest_api/src/helpers.rs +++ b/beacon_node/rest_api/src/helpers.rs @@ -1,20 +1,17 @@ -use crate::{ApiError, ApiResult}; +use crate::{ApiError, ApiResult, NetworkChannel}; use beacon_chain::{BeaconChain, BeaconChainTypes, StateSkipConfig}; use bls::PublicKeyBytes; -use eth2_libp2p::GossipTopic; -use eth2_libp2p::PubsubMessage; +use eth2_libp2p::types::GossipEncoding; +use eth2_libp2p::{PubsubData, PubsubMessage}; use hex; use http::header; use hyper::{Body, Request}; use network::NetworkMessage; -use parking_lot::RwLock; -use ssz::{Decode, Encode}; -use std::sync::Arc; +use ssz::Decode; use store::{iter::AncestorIter, Store}; -use tokio::sync::mpsc; use types::{ Attestation, BeaconState, CommitteeIndex, Epoch, EthSpec, Hash256, RelativeEpoch, Signature, - SignedBeaconBlock, Slot, + SignedAggregateAndProof, SignedBeaconBlock, Slot, }; /// Parse a slot. @@ -49,7 +46,7 @@ pub fn parse_committee_index(string: &str) -> Result { /// Checks the provided request to ensure that the `content-type` header. /// /// The content-type header should either be omitted, in which case JSON is assumed, or it should -/// explicity specify `application/json`. If anything else is provided, an error is returned. +/// explicitly specify `application/json`. If anything else is provided, an error is returned. pub fn check_content_type_for_json(req: &Request) -> Result<(), ApiError> { match req.headers().get(header::CONTENT_TYPE) { Some(h) if h == "application/json" => Ok(()), @@ -61,7 +58,7 @@ pub fn check_content_type_for_json(req: &Request) -> Result<(), ApiError> } } -/// Parse a signature from a `0x` preixed string. +/// Parse a signature from a `0x` prefixed string. pub fn parse_signature(string: &str) -> Result { const PREFIX: &str = "0x"; @@ -78,7 +75,7 @@ pub fn parse_signature(string: &str) -> Result { } } -/// Parse a root from a `0x` preixed string. +/// Parse a root from a `0x` prefixed string. /// /// E.g., `"0x0000000000000000000000000000000000000000000000000000000000000000"` pub fn parse_root(string: &str) -> Result { @@ -232,18 +229,17 @@ pub fn implementation_pending_response(_req: Request) -> ApiResult { } pub fn publish_beacon_block_to_network( - chan: Arc>>, + mut chan: NetworkChannel, block: SignedBeaconBlock, ) -> Result<(), ApiError> { - // create the network topic to send on - let topic = GossipTopic::BeaconBlock; - let message = PubsubMessage::Block(block.as_ssz_bytes()); + // send the block via SSZ encoding + let messages = vec![PubsubMessage::new( + GossipEncoding::SSZ, + PubsubData::BeaconBlock(Box::new(block)), + )]; // Publish the block to the p2p network via gossipsub. - if let Err(e) = chan.write().try_send(NetworkMessage::Publish { - topics: vec![topic.into()], - message, - }) { + if let Err(e) = chan.try_send(NetworkMessage::Publish { messages }) { return Err(ApiError::ServerError(format!( "Unable to send new block to network: {:?}", e @@ -253,19 +249,51 @@ pub fn publish_beacon_block_to_network( Ok(()) } -pub fn publish_attestation_to_network( - chan: Arc>>, - attestation: Attestation, +/// Publishes a raw un-aggregated attestation to the network. +pub fn publish_raw_attestations_to_network( + mut chan: NetworkChannel, + attestations: Vec>, ) -> Result<(), ApiError> { - // create the network topic to send on - let topic = GossipTopic::BeaconAttestation; - let message = PubsubMessage::Attestation(attestation.as_ssz_bytes()); + let messages = attestations + .into_iter() + .map(|attestation| { + // create the gossip message to send to the network + let subnet_id = attestation.subnet_id(); + PubsubMessage::new( + GossipEncoding::SSZ, + PubsubData::Attestation(Box::new((subnet_id, attestation))), + ) + }) + .collect::>(); - // Publish the attestation to the p2p network via gossipsub. - if let Err(e) = chan.write().try_send(NetworkMessage::Publish { - topics: vec![topic.into()], - message, - }) { + // Publish the attestations to the p2p network via gossipsub. + if let Err(e) = chan.try_send(NetworkMessage::Publish { messages }) { + return Err(ApiError::ServerError(format!( + "Unable to send new attestation to network: {:?}", + e + ))); + } + + Ok(()) +} + +/// Publishes an aggregated attestation to the network. +pub fn publish_aggregate_attestations_to_network( + mut chan: NetworkChannel, + signed_proofs: Vec>, +) -> Result<(), ApiError> { + let messages = signed_proofs + .into_iter() + .map(|signed_proof| { + PubsubMessage::new( + GossipEncoding::SSZ, + PubsubData::AggregateAndProofAttestation(Box::new(signed_proof)), + ) + }) + .collect::>(); + + // Publish the attestations to the p2p network via gossipsub. + if let Err(e) = chan.try_send(NetworkMessage::Publish { messages }) { return Err(ApiError::ServerError(format!( "Unable to send new attestation to network: {:?}", e diff --git a/beacon_node/rest_api/src/lib.rs b/beacon_node/rest_api/src/lib.rs index f4f13babc..4dc858c1d 100644 --- a/beacon_node/rest_api/src/lib.rs +++ b/beacon_node/rest_api/src/lib.rs @@ -21,38 +21,32 @@ mod validator; use beacon_chain::{BeaconChain, BeaconChainTypes}; use client_network::NetworkMessage; -use client_network::Service as NetworkService; pub use config::ApiEncodingFormat; use error::{ApiError, ApiResult}; use eth2_config::Eth2Config; +use eth2_libp2p::NetworkGlobals; use hyper::rt::Future; use hyper::server::conn::AddrStream; use hyper::service::{make_service_fn, service_fn}; use hyper::{Body, Request, Response, Server}; -use parking_lot::RwLock; use slog::{info, warn}; use std::net::SocketAddr; use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; use tokio::runtime::TaskExecutor; -use tokio::sync::mpsc; +use tokio::sync::{mpsc, oneshot}; use url_query::UrlQuery; pub use crate::helpers::parse_pubkey_bytes; -pub use beacon::{ - BlockResponse, CanonicalHeadResponse, Committee, HeadBeaconBlock, StateResponse, - ValidatorRequest, ValidatorResponse, -}; pub use config::Config; -pub use validator::{ValidatorDutiesRequest, ValidatorDuty}; pub type BoxFut = Box, Error = ApiError> + Send>; -pub type NetworkChannel = Arc>>; +pub type NetworkChannel = mpsc::UnboundedSender>; pub struct NetworkInfo { - pub network_service: Arc>, - pub network_chan: mpsc::UnboundedSender, + pub network_globals: Arc>, + pub network_chan: NetworkChannel, } // Allowing more than 7 arguments. @@ -66,7 +60,7 @@ pub fn start_server( freezer_db_path: PathBuf, eth2_config: Eth2Config, log: slog::Logger, -) -> Result<(exit_future::Signal, SocketAddr), hyper::Error> { +) -> Result<(oneshot::Sender<()>, SocketAddr), hyper::Error> { let inner_log = log.clone(); let eth2_config = Arc::new(eth2_config); @@ -75,8 +69,8 @@ pub fn start_server( let beacon_chain = beacon_chain.clone(); let log = inner_log.clone(); let eth2_config = eth2_config.clone(); - let network_service = network_info.network_service.clone(); - let network_channel = Arc::new(RwLock::new(network_info.network_chan.clone())); + let network_globals = network_info.network_globals.clone(); + let network_channel = network_info.network_chan.clone(); let db_path = db_path.clone(); let freezer_db_path = freezer_db_path.clone(); @@ -84,7 +78,7 @@ pub fn start_server( router::route( req, beacon_chain.clone(), - network_service.clone(), + network_globals.clone(), network_channel.clone(), eth2_config.clone(), log.clone(), @@ -104,7 +98,7 @@ pub fn start_server( let actual_listen_addr = server.local_addr(); // Build a channel to kill the HTTP server. - let (exit_signal, exit) = exit_future::signal(); + let (exit_signal, exit) = oneshot::channel(); let inner_log = log.clone(); let server_exit = exit.and_then(move |_| { info!(inner_log, "HTTP service shutdown"); diff --git a/beacon_node/rest_api/src/network.rs b/beacon_node/rest_api/src/network.rs index 1d8df29a3..1589c0368 100644 --- a/beacon_node/rest_api/src/network.rs +++ b/beacon_node/rest_api/src/network.rs @@ -1,6 +1,6 @@ use crate::error::ApiResult; use crate::response_builder::ResponseBuilder; -use crate::NetworkService; +use crate::NetworkGlobals; use beacon_chain::BeaconChainTypes; use eth2_libp2p::{Multiaddr, PeerId}; use hyper::{Body, Request}; @@ -11,7 +11,7 @@ use std::sync::Arc; /// Returns a list of `Multiaddr`, serialized according to their `serde` impl. pub fn get_listen_addresses( req: Request, - network: Arc>, + network: Arc>, ) -> ApiResult { let multiaddresses: Vec = network.listen_multiaddrs(); ResponseBuilder::new(&req)?.body_no_ssz(&multiaddresses) @@ -22,9 +22,9 @@ pub fn get_listen_addresses( /// Returns the TCP port number in its plain form (which is also valid JSON serialization) pub fn get_listen_port( req: Request, - network: Arc>, + network: Arc>, ) -> ApiResult { - ResponseBuilder::new(&req)?.body(&network.listen_port()) + ResponseBuilder::new(&req)?.body(&network.listen_port_tcp()) } /// HTTP handler to return the Discv5 ENR from the client's libp2p service. @@ -32,7 +32,7 @@ pub fn get_listen_port( /// ENR is encoded as base64 string. pub fn get_enr( req: Request, - network: Arc>, + network: Arc>, ) -> ApiResult { ResponseBuilder::new(&req)?.body_no_ssz( &network @@ -47,7 +47,7 @@ pub fn get_enr( /// PeerId is encoded as base58 string. pub fn get_peer_id( req: Request, - network: Arc>, + network: Arc>, ) -> ApiResult { ResponseBuilder::new(&req)?.body_no_ssz(&network.local_peer_id().to_base58()) } @@ -55,7 +55,7 @@ pub fn get_peer_id( /// HTTP handler to return the number of peers connected in the client's libp2p service. pub fn get_peer_count( req: Request, - network: Arc>, + network: Arc>, ) -> ApiResult { ResponseBuilder::new(&req)?.body(&network.connected_peers()) } @@ -65,11 +65,12 @@ pub fn get_peer_count( /// Peers are presented as a list of `PeerId::to_string()`. pub fn get_peer_list( req: Request, - network: Arc>, + network: Arc>, ) -> ApiResult { let connected_peers: Vec = network - .connected_peer_set() - .iter() + .connected_peer_set + .read() + .keys() .map(PeerId::to_string) .collect(); ResponseBuilder::new(&req)?.body_no_ssz(&connected_peers) diff --git a/beacon_node/rest_api/src/router.rs b/beacon_node/rest_api/src/router.rs index f7eb7fd15..db488ef0f 100644 --- a/beacon_node/rest_api/src/router.rs +++ b/beacon_node/rest_api/src/router.rs @@ -3,8 +3,8 @@ use crate::{ BoxFut, NetworkChannel, }; use beacon_chain::{BeaconChain, BeaconChainTypes}; -use client_network::Service as NetworkService; use eth2_config::Eth2Config; +use eth2_libp2p::NetworkGlobals; use futures::{Future, IntoFuture}; use hyper::{Body, Error, Method, Request, Response}; use slog::debug; @@ -25,8 +25,8 @@ where pub fn route( req: Request, beacon_chain: Arc>, - network_service: Arc>, - network_channel: NetworkChannel, + network_globals: Arc>, + network_channel: NetworkChannel, eth2_config: Arc, local_log: slog::Logger, db_path: PathBuf, @@ -49,22 +49,22 @@ pub fn route( // Methods for Network (&Method::GET, "/network/enr") => { - into_boxfut(network::get_enr::(req, network_service)) + into_boxfut(network::get_enr::(req, network_globals)) } (&Method::GET, "/network/peer_count") => { - into_boxfut(network::get_peer_count::(req, network_service)) + into_boxfut(network::get_peer_count::(req, network_globals)) } (&Method::GET, "/network/peer_id") => { - into_boxfut(network::get_peer_id::(req, network_service)) + into_boxfut(network::get_peer_id::(req, network_globals)) } (&Method::GET, "/network/peers") => { - into_boxfut(network::get_peer_list::(req, network_service)) + into_boxfut(network::get_peer_list::(req, network_globals)) } (&Method::GET, "/network/listen_port") => { - into_boxfut(network::get_listen_port::(req, network_service)) + into_boxfut(network::get_listen_port::(req, network_globals)) } (&Method::GET, "/network/listen_addresses") => { - into_boxfut(network::get_listen_addresses::(req, network_service)) + into_boxfut(network::get_listen_addresses::(req, network_globals)) } // Methods for Beacon Node @@ -121,6 +121,14 @@ pub fn route( drop(timer); into_boxfut(response) } + (&Method::POST, "/validator/subscribe") => { + validator::post_validator_subscriptions::( + req, + beacon_chain, + network_channel, + log, + ) + } (&Method::GET, "/validator/duties/all") => { into_boxfut(validator::get_all_validator_duties::(req, beacon_chain)) } @@ -144,10 +152,22 @@ pub fn route( drop(timer); into_boxfut(response) } - (&Method::POST, "/validator/attestation") => { - validator::publish_attestation::(req, beacon_chain, network_channel, log) + (&Method::GET, "/validator/aggregate_attestation") => { + into_boxfut(validator::get_aggregate_attestation::(req, beacon_chain)) + } + (&Method::POST, "/validator/attestations") => { + validator::publish_attestations::(req, beacon_chain, network_channel, log) + } + (&Method::POST, "/validator/aggregate_and_proofs") => { + validator::publish_aggregate_and_proofs::( + req, + beacon_chain, + network_channel, + log, + ) } + // Methods for consensus (&Method::GET, "/consensus/global_votes") => { into_boxfut(consensus::get_vote_count::(req, beacon_chain)) } diff --git a/beacon_node/rest_api/src/validator.rs b/beacon_node/rest_api/src/validator.rs index e4cc3a589..caa4b9120 100644 --- a/beacon_node/rest_api/src/validator.rs +++ b/beacon_node/rest_api/src/validator.rs @@ -1,47 +1,27 @@ use crate::helpers::{ - check_content_type_for_json, publish_attestation_to_network, publish_beacon_block_to_network, + check_content_type_for_json, publish_aggregate_attestations_to_network, + publish_beacon_block_to_network, publish_raw_attestations_to_network, }; use crate::response_builder::ResponseBuilder; use crate::{ApiError, ApiResult, BoxFut, NetworkChannel, UrlQuery}; use beacon_chain::{ - AttestationProcessingOutcome, BeaconChain, BeaconChainTypes, BlockProcessingOutcome, - StateSkipConfig, + AttestationProcessingOutcome, BeaconChain, BeaconChainTypes, BlockError, StateSkipConfig, }; use bls::PublicKeyBytes; use futures::{Future, Stream}; use hyper::{Body, Request}; -use serde::{Deserialize, Serialize}; +use network::NetworkMessage; +use rayon::prelude::*; +use rest_types::{ValidatorDutiesRequest, ValidatorDutyBytes, ValidatorSubscription}; use slog::{error, info, warn, Logger}; -use ssz_derive::{Decode, Encode}; use std::sync::Arc; use types::beacon_state::EthSpec; use types::{ - Attestation, BeaconState, CommitteeIndex, Epoch, RelativeEpoch, SignedBeaconBlock, Slot, + Attestation, BeaconState, Epoch, RelativeEpoch, SignedAggregateAndProof, SignedBeaconBlock, + Slot, }; -#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)] -pub struct ValidatorDuty { - /// The validator's BLS public key, uniquely identifying them. _48-bytes, hex encoded with 0x prefix, case insensitive._ - pub validator_pubkey: PublicKeyBytes, - /// The validator's index in `state.validators` - pub validator_index: Option, - /// The slot at which the validator must attest. - pub attestation_slot: Option, - /// The index of the committee within `slot` of which the validator is a member. - pub attestation_committee_index: Option, - /// The position of the validator in the committee. - pub attestation_committee_position: Option, - /// The slots in which a validator must propose a block (can be empty). - pub block_proposal_slots: Vec, -} - -#[derive(PartialEq, Debug, Serialize, Deserialize, Clone, Encode, Decode)] -pub struct ValidatorDutiesRequest { - pub epoch: Epoch, - pub pubkeys: Vec, -} - -/// HTTP Handler to retrieve a the duties for a set of validators during a particular epoch. This +/// HTTP Handler to retrieve the duties for a set of validators during a particular epoch. This /// method allows for collecting bulk sets of validator duties without risking exceeding the max /// URL length with query pairs. pub fn post_validator_duties( @@ -74,6 +54,79 @@ pub fn post_validator_duties( Box::new(future) } +/// HTTP Handler to retrieve subscriptions for a set of validators. This allows the node to +/// organise peer discovery and topic subscription for known validators. +pub fn post_validator_subscriptions( + req: Request, + beacon_chain: Arc>, + mut network_chan: NetworkChannel, + log: Logger, +) -> BoxFut { + try_future!(check_content_type_for_json(&req)); + let response_builder = ResponseBuilder::new(&req); + + let body = req.into_body(); + Box::new( + body.concat2() + .map_err(|e| ApiError::ServerError(format!("Unable to get request body: {:?}", e))) + .and_then(|chunks| { + serde_json::from_slice(&chunks).map_err(|e| { + ApiError::BadRequest(format!( + "Unable to parse JSON into ValidatorSubscriptions: {:?}", + e + )) + }) + }) + .and_then(move |subscriptions: Vec| { + let fork = beacon_chain + .wall_clock_state() + .map(|state| state.fork.clone()) + .map_err(|e| { + error!(log, "Unable to get current beacon state"); + ApiError::ServerError(format!("Error getting current beacon state {:?}", e)) + })?; + + // verify the signatures in parallel + subscriptions.par_iter().try_for_each(|subscription| { + if let Some(pubkey) = + &beacon_chain.validator_pubkey(subscription.validator_index as usize)? + { + if subscription.verify( + pubkey, + &beacon_chain.spec, + &fork, + T::EthSpec::slots_per_epoch(), + ) { + Ok(()) + } else { + error!(log, "HTTP RPC sent invalid signatures"); + Err(ApiError::ProcessingError(format!( + "Could not verify signatures" + ))) + } + } else { + error!(log, "HTTP RPC sent unknown validator"); + Err(ApiError::ProcessingError(format!( + "Could not verify signatures" + ))) + } + })?; + + // subscriptions are verified, send them to the network thread + network_chan + .try_send(NetworkMessage::Subscribe { subscriptions }) + .map_err(|e| { + ApiError::ServerError(format!( + "Unable to subscriptions to the network: {:?}", + e + )) + })?; + Ok(()) + }) + .and_then(|_| response_builder?.body_no_ssz(&())), + ) +} + /// HTTP Handler to retrieve all validator duties for the given epoch. pub fn get_all_validator_duties( req: Request, @@ -154,7 +207,7 @@ fn return_validator_duties( beacon_chain: Arc>, epoch: Epoch, validator_pubkeys: Vec, -) -> Result, ApiError> { +) -> Result, ApiError> { let mut state = get_state_for_epoch(&beacon_chain, epoch, StateSkipConfig::WithoutStateRoots)?; let relative_epoch = RelativeEpoch::from_epoch(state.current_epoch(), epoch) @@ -189,11 +242,24 @@ fn return_validator_duties( validator_pubkeys .into_iter() .map(|validator_pubkey| { - if let Some(validator_index) = - state.get_validator_index(&validator_pubkey).map_err(|e| { - ApiError::ServerError(format!("Unable to read pubkey cache: {:?}", e)) - })? - { + // The `beacon_chain` can return a validator index that does not exist in all states. + // Therefore, we must check to ensure that the validator index is valid for our + // `state`. + let validator_index = if let Some(i) = beacon_chain + .validator_index(&validator_pubkey) + .map_err(|e| { + ApiError::ServerError(format!("Unable to get validator index: {:?}", e)) + })? { + if i < state.validators.len() { + Some(i) + } else { + None + } + } else { + None + }; + + if let Some(validator_index) = validator_index { let duties = state .get_attestation_duties(validator_index, relative_epoch) .map_err(|e| { @@ -203,28 +269,39 @@ fn return_validator_duties( )) })?; + // Obtain the aggregator modulo + let aggregator_modulo = duties.map(|d| { + std::cmp::max( + 1, + d.committee_len as u64 + / &beacon_chain.spec.target_aggregators_per_committee, + ) + }); + let block_proposal_slots = validator_proposers .iter() .filter(|(i, _slot)| validator_index == *i) .map(|(_i, slot)| *slot) .collect(); - Ok(ValidatorDuty { + Ok(ValidatorDutyBytes { validator_pubkey, - validator_index: Some(validator_index), + validator_index: Some(validator_index as u64), attestation_slot: duties.map(|d| d.slot), attestation_committee_index: duties.map(|d| d.index), attestation_committee_position: duties.map(|d| d.committee_position), block_proposal_slots, + aggregator_modulo, }) } else { - Ok(ValidatorDuty { + Ok(ValidatorDutyBytes { validator_pubkey, validator_index: None, attestation_slot: None, attestation_committee_index: None, attestation_committee_position: None, block_proposal_slots: vec![], + aggregator_modulo: None, }) } }) @@ -264,7 +341,7 @@ pub fn get_new_beacon_block( pub fn publish_beacon_block( req: Request, beacon_chain: Arc>, - network_chan: NetworkChannel, + network_chan: NetworkChannel, log: Logger, ) -> BoxFut { try_future!(check_content_type_for_json(&req)); @@ -282,7 +359,7 @@ pub fn publish_beacon_block( .and_then(move |block: SignedBeaconBlock| { let slot = block.slot(); match beacon_chain.process_block(block.clone()) { - Ok(BlockProcessingOutcome::Processed { block_root }) => { + Ok(block_root) => { // Block was processed, publish via gossipsub info!( log, @@ -325,19 +402,7 @@ pub fn publish_beacon_block( Ok(()) } - Ok(outcome) => { - warn!( - log, - "Invalid block from local validator"; - "outcome" => format!("{:?}", outcome) - ); - - Err(ApiError::ProcessingError(format!( - "The SignedBeaconBlock could not be processed and has not been published: {:?}", - outcome - ))) - } - Err(e) => { + Err(BlockError::BeaconChainError(e)) => { error!( log, "Error whilst processing block"; @@ -349,6 +414,18 @@ pub fn publish_beacon_block( e ))) } + Err(other) => { + warn!( + log, + "Invalid block from local validator"; + "outcome" => format!("{:?}", other) + ); + + Err(ApiError::ProcessingError(format!( + "The SignedBeaconBlock could not be processed and has not been published: {:?}", + other + ))) + } } }) .and_then(|_| response_builder?.body_no_ssz(&())) @@ -372,11 +449,28 @@ pub fn get_new_attestation( ResponseBuilder::new(&req)?.body(&attestation) } -/// HTTP Handler to publish an Attestation, which has been signed by a validator. -pub fn publish_attestation( +/// HTTP Handler to retrieve the aggregate attestation for a slot +pub fn get_aggregate_attestation( req: Request, beacon_chain: Arc>, - network_chan: NetworkChannel, +) -> ApiResult { + let query = UrlQuery::from_request(&req)?; + + let slot = query.slot()?; + let index = query.committee_index()?; + + let aggregate_attestation = beacon_chain + .return_aggregate_attestation(slot, index) + .map_err(|e| ApiError::BadRequest(format!("Unable to produce attestation: {:?}", e)))?; + + ResponseBuilder::new(&req)?.body(&aggregate_attestation) +} + +/// HTTP Handler to publish a list of Attestations, which have been signed by a number of validators. +pub fn publish_attestations( + req: Request, + beacon_chain: Arc>, + network_chan: NetworkChannel, log: Logger, ) -> BoxFut { try_future!(check_content_type_for_json(&req)); @@ -390,13 +484,20 @@ pub fn publish_attestation( .and_then(|chunks| { serde_json::from_slice(&chunks.as_slice()).map_err(|e| { ApiError::BadRequest(format!( - "Unable to deserialize JSON into a SignedBeaconBlock: {:?}", + "Unable to deserialize JSON into a list of attestations: {:?}", e )) }) }) - .and_then(move |attestation: Attestation| { - match beacon_chain.process_attestation(attestation.clone()) { + .and_then(move |attestations: Vec>| { + // Note: This is a new attestation from a validator. We want to process this and + // inform the validator whether the attestation was valid. In doing so, we store + // this un-aggregated raw attestation in the op_pool by default. This is + // sub-optimal as if we have no validators needing to aggregate, these don't need + // to be stored in the op-pool. This is minimal however as the op_pool gets pruned + // every slot + attestations.par_iter().try_for_each(|attestation| { + match beacon_chain.process_attestation(attestation.clone(), Some(true)) { Ok(AttestationProcessingOutcome::Processed) => { // Block was processed, publish via gossipsub info!( @@ -407,7 +508,99 @@ pub fn publish_attestation( "index" => attestation.data.index, "slot" => attestation.data.slot, ); - publish_attestation_to_network::(network_chan, attestation) + Ok(()) + } + Ok(outcome) => { + warn!( + log, + "Invalid attestation from local validator"; + "outcome" => format!("{:?}", outcome) + ); + + Err(ApiError::ProcessingError(format!( + "An Attestation could not be processed and has not been published: {:?}", + outcome + ))) + } + Err(e) => { + error!( + log, + "Error whilst processing attestation"; + "error" => format!("{:?}", e) + ); + + Err(ApiError::ServerError(format!( + "Error while processing attestation: {:?}", + e + ))) + } + } + })?; + Ok(attestations) + }) + .and_then(|attestations| { + publish_raw_attestations_to_network::(network_chan, attestations) + }) + .and_then(|_| response_builder?.body_no_ssz(&())), + ) +} + +/// HTTP Handler to publish an Attestation, which has been signed by a validator. +pub fn publish_aggregate_and_proofs( + req: Request, + beacon_chain: Arc>, + network_chan: NetworkChannel, + log: Logger, +) -> BoxFut { + try_future!(check_content_type_for_json(&req)); + let response_builder = ResponseBuilder::new(&req); + + Box::new( + req.into_body() + .concat2() + .map_err(|e| ApiError::ServerError(format!("Unable to get request body: {:?}", e))) + .map(|chunk| chunk.iter().cloned().collect::>()) + .and_then(|chunks| { + serde_json::from_slice(&chunks.as_slice()).map_err(|e| { + ApiError::BadRequest(format!( + "Unable to deserialize JSON into a list of SignedAggregateAndProof: {:?}", + e + )) + }) + }) + .and_then(move |signed_proofs: Vec>| { + + // Verify the signatures for the aggregate and proof and if valid process the + // aggregate + // TODO: Double check speed and logic consistency of handling current fork vs + // validator fork for signatures. + // TODO: More efficient way of getting a fork? + let fork = &beacon_chain.head()?.beacon_state.fork; + + signed_proofs.par_iter().try_for_each(|signed_proof| { + let agg_proof = &signed_proof.message; + let validator_pubkey = &beacon_chain.validator_pubkey(agg_proof.aggregator_index as usize)?.ok_or_else(|| { + warn!( + log, + "Unknown validator from local validator client"; + ); + + ApiError::ProcessingError(format!("The validator is known")) + })?; + if signed_proof.is_valid(validator_pubkey, fork) { + let attestation = &agg_proof.aggregate; + match beacon_chain.process_attestation(attestation.clone(), Some(false)) { + Ok(AttestationProcessingOutcome::Processed) => { + // Block was processed, publish via gossipsub + info!( + log, + "Attestation from local validator"; + "target" => attestation.data.source.epoch, + "source" => attestation.data.source.epoch, + "index" => attestation.data.index, + "slot" => attestation.data.slot, + ); + Ok(()) } Ok(outcome) => { warn!( @@ -434,6 +627,21 @@ pub fn publish_attestation( ))) } } + + } else { + error!( + log, + "Invalid AggregateAndProof Signature" + ); + Err(ApiError::ServerError(format!( + "Invalid AggregateAndProof Signature" + ))) + } + })?; + Ok(signed_proofs) + }) + .and_then(move |signed_proofs| { + publish_aggregate_attestations_to_network::(network_chan, signed_proofs) }) .and_then(|_| response_builder?.body_no_ssz(&())), ) diff --git a/beacon_node/rest_api/tests/test.rs b/beacon_node/rest_api/tests/test.rs index 716541045..599b2dd7b 100644 --- a/beacon_node/rest_api/tests/test.rs +++ b/beacon_node/rest_api/tests/test.rs @@ -6,9 +6,9 @@ use node_test_rig::{ testing_client_config, ClientConfig, ClientGenesis, LocalBeaconNode, }; use remote_beacon_node::{ - Committee, HeadBeaconBlock, PersistedOperationPool, PublishStatus, ValidatorDuty, - ValidatorResponse, + Committee, HeadBeaconBlock, PersistedOperationPool, PublishStatus, ValidatorResponse, }; +use rest_types::ValidatorDutyBytes; use std::convert::TryInto; use std::sync::Arc; use types::{ @@ -141,7 +141,7 @@ fn validator_produce_attestation() { remote_node .http .validator() - .publish_attestation(attestation.clone()), + .publish_attestations(vec![attestation.clone()]), ) .expect("should publish attestation"); assert!( @@ -167,7 +167,7 @@ fn validator_produce_attestation() { remote_node .http .validator() - .publish_attestation(attestation), + .publish_attestations(vec![attestation]), ) .expect("should publish attestation"); assert!( @@ -229,7 +229,7 @@ fn validator_duties() { } fn check_duties( - duties: Vec, + duties: Vec, epoch: Epoch, validators: Vec, beacon_chain: Arc>, diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index bdf759281..4bad6d9d5 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -1,7 +1,7 @@ use clap::ArgMatches; use client::{config::DEFAULT_DATADIR, ClientConfig, ClientGenesis, Eth2Config}; use eth2_config::{read_from_file, write_to_file}; -use eth2_libp2p::{Enr, Multiaddr}; +use eth2_libp2p::{Enr, GossipTopic, Multiaddr}; use eth2_testnet_config::Eth2TestnetConfig; use genesis::recent_genesis_time; use rand::{distributions::Alphanumeric, Rng}; @@ -135,7 +135,12 @@ pub fn get_configs( } if let Some(topics_str) = cli_args.value_of("topics") { - client_config.network.topics = topics_str.split(',').map(|s| s.into()).collect(); + let mut topics = Vec::new(); + let topic_list = topics_str.split(',').collect::>(); + for topic_str in topic_list { + topics.push(GossipTopic::decode(topic_str)?); + } + client_config.network.topics = topics; } if let Some(discovery_address_str) = cli_args.value_of("discovery-address") { diff --git a/beacon_node/src/lib.rs b/beacon_node/src/lib.rs index ca758c8c3..e319f85f2 100644 --- a/beacon_node/src/lib.rs +++ b/beacon_node/src/lib.rs @@ -124,7 +124,7 @@ impl ProductionBeaconNode { .system_time_slot_clock()? .websocket_event_handler(client_config.websocket_server.clone())? .build_beacon_chain()? - .libp2p_network(&client_config.network)? + .network(&client_config.network)? .notifier()?; let builder = if client_config.rest_api.enabled { diff --git a/beacon_node/store/Cargo.toml b/beacon_node/store/Cargo.toml index ebb5cf499..36a34738a 100644 --- a/beacon_node/store/Cargo.toml +++ b/beacon_node/store/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "store" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/beacon_node/store/src/hot_cold_store.rs b/beacon_node/store/src/hot_cold_store.rs index 48329b1e3..0c3b2bc95 100644 --- a/beacon_node/store/src/hot_cold_store.rs +++ b/beacon_node/store/src/hot_cold_store.rs @@ -10,7 +10,7 @@ use crate::{ leveldb_store::LevelDB, DBColumn, Error, PartialBeaconState, SimpleStoreItem, Store, StoreItem, }; use lru::LruCache; -use parking_lot::{Mutex, RwLock}; +use parking_lot::RwLock; use slog::{debug, trace, warn, Logger}; use ssz::{Decode, Encode}; use ssz_derive::{Decode, Encode}; @@ -22,7 +22,6 @@ use std::convert::TryInto; use std::marker::PhantomData; use std::path::Path; use std::sync::Arc; -use types::beacon_state::CloneConfig; use types::*; /// 32-byte key for accessing the `split` of the freezer DB. @@ -46,9 +45,7 @@ pub struct HotColdDB { /// The hot database also contains all blocks. pub(crate) hot_db: LevelDB, /// LRU cache of deserialized blocks. Updated whenever a block is loaded. - block_cache: Mutex>>, - /// LRU cache of deserialized states. Updated whenever a state is loaded. - state_cache: Mutex>>, + block_cache: RwLock>>, /// Chain spec. spec: ChainSpec, /// Logger. @@ -112,7 +109,7 @@ impl Store for HotColdDB { self.put(block_root, &block)?; // Update cache. - self.block_cache.lock().put(*block_root, block); + self.block_cache.write().put(*block_root, block); Ok(()) } @@ -122,7 +119,7 @@ impl Store for HotColdDB { metrics::inc_counter(&metrics::BEACON_BLOCK_GET_COUNT); // Check the cache. - if let Some(block) = self.block_cache.lock().get(block_root) { + if let Some(block) = self.block_cache.write().get(block_root) { metrics::inc_counter(&metrics::BEACON_BLOCK_CACHE_HIT_COUNT); return Ok(Some(block.clone())); } @@ -131,7 +128,7 @@ impl Store for HotColdDB { match self.get::>(block_root)? { Some(block) => { // Add to cache. - self.block_cache.lock().put(*block_root, block.clone()); + self.block_cache.write().put(*block_root, block.clone()); Ok(Some(block)) } None => Ok(None), @@ -140,12 +137,12 @@ impl Store for HotColdDB { /// Delete a block from the store and the block cache. fn delete_block(&self, block_root: &Hash256) -> Result<(), Error> { - self.block_cache.lock().pop(block_root); + self.block_cache.write().pop(block_root); self.delete::>(block_root) } /// Store a state in the store. - fn put_state(&self, state_root: &Hash256, state: BeaconState) -> Result<(), Error> { + fn put_state(&self, state_root: &Hash256, state: &BeaconState) -> Result<(), Error> { if state.slot < self.get_split_slot() { self.store_cold_state(state_root, &state) } else { @@ -159,7 +156,7 @@ impl Store for HotColdDB { state_root: &Hash256, slot: Option, ) -> Result>, Error> { - self.get_state_with(state_root, slot, CloneConfig::all()) + self.get_state_with(state_root, slot) } /// Get a state from the store. @@ -169,7 +166,6 @@ impl Store for HotColdDB { &self, state_root: &Hash256, slot: Option, - clone_config: CloneConfig, ) -> Result>, Error> { metrics::inc_counter(&metrics::BEACON_STATE_GET_COUNT); @@ -177,10 +173,10 @@ impl Store for HotColdDB { if slot < self.get_split_slot() { self.load_cold_state_by_slot(slot).map(Some) } else { - self.load_hot_state(state_root, clone_config) + self.load_hot_state(state_root) } } else { - match self.load_hot_state(state_root, clone_config)? { + match self.load_hot_state(state_root)? { Some(state) => Ok(Some(state)), None => self.load_cold_state(state_root), } @@ -204,9 +200,6 @@ impl Store for HotColdDB { .key_delete(DBColumn::BeaconState.into(), state_root.as_bytes())?; } - // Delete from the cache. - self.state_cache.lock().pop(state_root); - Ok(()) } @@ -309,10 +302,7 @@ impl Store for HotColdDB { { // NOTE: minor inefficiency here because we load an unnecessary hot state summary let state = self - .load_hot_state( - &epoch_boundary_state_root, - CloneConfig::committee_caches_only(), - )? + .load_hot_state(&epoch_boundary_state_root)? .ok_or_else(|| { HotColdDBError::MissingEpochBoundaryState(epoch_boundary_state_root) })?; @@ -348,8 +338,7 @@ impl HotColdDB { split: RwLock::new(Split::default()), cold_db: LevelDB::open(cold_path)?, hot_db: LevelDB::open(hot_path)?, - block_cache: Mutex::new(LruCache::new(config.block_cache_size)), - state_cache: Mutex::new(LruCache::new(config.state_cache_size)), + block_cache: RwLock::new(LruCache::new(config.block_cache_size)), config, spec, log, @@ -371,7 +360,7 @@ impl HotColdDB { pub fn store_hot_state( &self, state_root: &Hash256, - state: BeaconState, + state: &BeaconState, ) -> Result<(), Error> { // On the epoch boundary, store the full state. if state.slot % E::slots_per_epoch() == 0 { @@ -387,10 +376,7 @@ impl HotColdDB { // Store a summary of the state. // We store one even for the epoch boundary states, as we may need their slots // when doing a look up by state root. - self.put_state_summary(state_root, HotStateSummary::new(state_root, &state)?)?; - - // Store the state in the cache. - self.state_cache.lock().put(*state_root, state); + self.put_state_summary(state_root, HotStateSummary::new(state_root, state)?)?; Ok(()) } @@ -398,24 +384,9 @@ impl HotColdDB { /// Load a post-finalization state from the hot database. /// /// Will replay blocks from the nearest epoch boundary. - pub fn load_hot_state( - &self, - state_root: &Hash256, - clone_config: CloneConfig, - ) -> Result>, Error> { + pub fn load_hot_state(&self, state_root: &Hash256) -> Result>, Error> { metrics::inc_counter(&metrics::BEACON_STATE_HOT_GET_COUNT); - // Check the cache. - if let Some(state) = self.state_cache.lock().get(state_root) { - metrics::inc_counter(&metrics::BEACON_STATE_CACHE_HIT_COUNT); - - let timer = metrics::start_timer(&metrics::BEACON_STATE_CACHE_CLONE_TIME); - let state = state.clone_with(clone_config); - metrics::stop_timer(timer); - - return Ok(Some(state)); - } - if let Some(HotStateSummary { slot, latest_block_root, @@ -439,9 +410,6 @@ impl HotColdDB { self.replay_blocks(boundary_state, blocks, slot)? }; - // Update the LRU cache. - self.state_cache.lock().put(*state_root, state.clone()); - Ok(Some(state)) } else { Ok(None) diff --git a/beacon_node/store/src/iter.rs b/beacon_node/store/src/iter.rs index d0c19f358..43bdd164d 100644 --- a/beacon_node/store/src/iter.rs +++ b/beacon_node/store/src/iter.rs @@ -345,7 +345,7 @@ mod test { let state_a_root = hashes.next().unwrap(); state_b.state_roots[0] = state_a_root; - store.put_state(&state_a_root, state_a).unwrap(); + store.put_state(&state_a_root, &state_a).unwrap(); let iter = BlockRootsIterator::new(store, &state_b); @@ -393,8 +393,8 @@ mod test { let state_a_root = Hash256::from_low_u64_be(slots_per_historical_root as u64); let state_b_root = Hash256::from_low_u64_be(slots_per_historical_root as u64 * 2); - store.put_state(&state_a_root, state_a).unwrap(); - store.put_state(&state_b_root, state_b.clone()).unwrap(); + store.put_state(&state_a_root, &state_a).unwrap(); + store.put_state(&state_b_root, &state_b.clone()).unwrap(); let iter = StateRootsIterator::new(store, &state_b); diff --git a/beacon_node/store/src/leveldb_store.rs b/beacon_node/store/src/leveldb_store.rs index 9ee296e62..4f519a77d 100644 --- a/beacon_node/store/src/leveldb_store.rs +++ b/beacon_node/store/src/leveldb_store.rs @@ -123,7 +123,7 @@ impl Store for LevelDB { } /// Store a state in the store. - fn put_state(&self, state_root: &Hash256, state: BeaconState) -> Result<(), Error> { + fn put_state(&self, state_root: &Hash256, state: &BeaconState) -> Result<(), Error> { store_full_state(self, state_root, &state) } diff --git a/beacon_node/store/src/lib.rs b/beacon_node/store/src/lib.rs index 80da2ced1..a8220b08c 100644 --- a/beacon_node/store/src/lib.rs +++ b/beacon_node/store/src/lib.rs @@ -38,7 +38,6 @@ pub use errors::Error; pub use impls::beacon_state::StorageContainer as BeaconStateStorageContainer; pub use metrics::scrape_for_metrics; pub use state_batch::StateBatch; -pub use types::beacon_state::CloneConfig; pub use types::*; /// An object capable of storing and retrieving objects implementing `StoreItem`. @@ -97,7 +96,7 @@ pub trait Store: Sync + Send + Sized + 'static { } /// Store a state in the store. - fn put_state(&self, state_root: &Hash256, state: BeaconState) -> Result<(), Error>; + fn put_state(&self, state_root: &Hash256, state: &BeaconState) -> Result<(), Error>; /// Store a state summary in the store. // NOTE: this is a hack for the HotColdDb, we could consider splitting this @@ -122,7 +121,6 @@ pub trait Store: Sync + Send + Sized + 'static { &self, state_root: &Hash256, slot: Option, - _clone_config: CloneConfig, ) -> Result>, Error> { // Default impl ignores config. Overriden in `HotColdDb`. self.get_state(state_root, slot) diff --git a/beacon_node/store/src/memory_store.rs b/beacon_node/store/src/memory_store.rs index 81826b31f..7216ca6da 100644 --- a/beacon_node/store/src/memory_store.rs +++ b/beacon_node/store/src/memory_store.rs @@ -76,7 +76,7 @@ impl Store for MemoryStore { } /// Store a state in the store. - fn put_state(&self, state_root: &Hash256, state: BeaconState) -> Result<(), Error> { + fn put_state(&self, state_root: &Hash256, state: &BeaconState) -> Result<(), Error> { store_full_state(self, state_root, &state) } diff --git a/beacon_node/store/src/state_batch.rs b/beacon_node/store/src/state_batch.rs index a33e07225..c19173861 100644 --- a/beacon_node/store/src/state_batch.rs +++ b/beacon_node/store/src/state_batch.rs @@ -38,7 +38,7 @@ impl StateBatch { /// May fail to write the full batch if any of the items error (i.e. not atomic!) pub fn commit>(self, store: &S) -> Result<(), Error> { self.items.into_iter().try_for_each(|item| match item { - BatchItem::Full(state_root, state) => store.put_state(&state_root, state), + BatchItem::Full(state_root, state) => store.put_state(&state_root, &state), BatchItem::Summary(state_root, summary) => { store.put_state_summary(&state_root, summary) } diff --git a/beacon_node/timer/Cargo.toml b/beacon_node/timer/Cargo.toml new file mode 100644 index 000000000..a0c132cbe --- /dev/null +++ b/beacon_node/timer/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "timer" +version = "0.2.0" +authors = ["Age Manning "] +edition = "2018" + +[dependencies] +beacon_chain = { path = "../beacon_chain" } +types = { path = "../../eth2/types" } +slot_clock = { path = "../../eth2/utils/slot_clock" } +tokio = "0.1.22" +slog = "2.5.2" +parking_lot = "0.10.0" +futures = "0.1.29" diff --git a/beacon_node/timer/src/lib.rs b/beacon_node/timer/src/lib.rs new file mode 100644 index 000000000..27e7bc642 --- /dev/null +++ b/beacon_node/timer/src/lib.rs @@ -0,0 +1,97 @@ +//! A timer service for the beacon node. +//! +//! This service allows task execution on the beacon node for various functionality. + +use beacon_chain::{BeaconChain, BeaconChainTypes}; +use futures::prelude::*; +use slog::warn; +use slot_clock::SlotClock; +use std::sync::Arc; +use std::time::{Duration, Instant}; +use tokio::runtime::TaskExecutor; +use tokio::timer::Interval; +use types::EthSpec; + +/// A collection of timers that can execute actions on the beacon node. +/// +/// This currently only has a per-slot timer, although others may be added in the future +struct Timer { + /// Beacon chain associated. + beacon_chain: Arc>, + /// A timer that fires every slot. + per_slot_timer: Interval, + /// The logger for the timer. + log: slog::Logger, +} + +impl Timer { + pub fn new( + beacon_chain: Arc>, + milliseconds_per_slot: u64, + log: slog::Logger, + ) -> Result { + let duration_to_next_slot = beacon_chain + .slot_clock + .duration_to_next_slot() + .ok_or_else(|| "slot_notifier unable to determine time to next slot")?; + + let slot_duration = Duration::from_millis(milliseconds_per_slot); + // A per-slot timer + let start_instant = Instant::now() + duration_to_next_slot; + let per_slot_timer = Interval::new(start_instant, slot_duration); + + Ok(Timer { + beacon_chain, + per_slot_timer, + log, + }) + } + + /// Tasks that occur on a per-slot basis. + pub fn per_slot_task(&self) { + self.beacon_chain.per_slot_task(); + } + + pub fn per_epoch_task(&self) { + self.beacon_chain.per_epoch_task(); + } +} + +/// Spawns a timer service which periodically executes tasks for the beacon chain +pub fn spawn( + executor: &TaskExecutor, + beacon_chain: Arc>, + milliseconds_per_slot: u64, + log: slog::Logger, +) -> Result, &'static str> { + //let thread_log = log.clone(); + let mut timer = Timer::new(beacon_chain, milliseconds_per_slot, log)?; + let (exit_signal, mut exit) = tokio::sync::oneshot::channel(); + + executor.spawn(futures::future::poll_fn(move || -> Result<_, ()> { + if let Ok(Async::Ready(_)) | Err(_) = exit.poll() { + // notifier is terminating, end the process + return Ok(Async::Ready(())); + } + + while let Async::Ready(_) = timer + .per_slot_timer + .poll() + .map_err(|e| warn!(timer.log, "Per slot timer error"; "error" => format!("{:?}", e)))? + { + timer.per_slot_task(); + match timer + .beacon_chain + .slot_clock + .now() + .map(|slot| (slot % T::EthSpec::slots_per_epoch()).as_u64()) + { + Some(0) => timer.per_epoch_task(), + _ => {} + } + } + Ok(Async::NotReady) + })); + + Ok(exit_signal) +} diff --git a/beacon_node/version/Cargo.toml b/beacon_node/version/Cargo.toml index 0497408f1..030aebb49 100644 --- a/beacon_node/version/Cargo.toml +++ b/beacon_node/version/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "version" -version = "0.1.0" +version = "0.2.0" authors = ["Age Manning "] edition = "2018" diff --git a/beacon_node/websocket_server/Cargo.toml b/beacon_node/websocket_server/Cargo.toml index f45c718e1..0ed8d628c 100644 --- a/beacon_node/websocket_server/Cargo.toml +++ b/beacon_node/websocket_server/Cargo.toml @@ -1,13 +1,12 @@ [package] name = "websocket_server" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -exit-future = "0.1.4" futures = "0.1.29" serde = "1.0.102" serde_derive = "1.0.102" diff --git a/beacon_node/websocket_server/src/lib.rs b/beacon_node/websocket_server/src/lib.rs index 26736c573..01b48ab18 100644 --- a/beacon_node/websocket_server/src/lib.rs +++ b/beacon_node/websocket_server/src/lib.rs @@ -40,7 +40,14 @@ pub fn start_server( config: &Config, executor: &TaskExecutor, log: &Logger, -) -> Result<(WebSocketSender, exit_future::Signal, SocketAddr), String> { +) -> Result< + ( + WebSocketSender, + tokio::sync::oneshot::Sender<()>, + SocketAddr, + ), + String, +> { let server_string = format!("{}:{}", config.listen_address, config.port); // Create a server that simply ignores any incoming messages. @@ -64,29 +71,31 @@ pub fn start_server( let broadcaster = server.broadcaster(); // Produce a signal/channel that can gracefully shutdown the websocket server. - let exit_signal = { - let (exit_signal, exit) = exit_future::signal(); + let exit_channel = { + let (exit_channel, exit) = tokio::sync::oneshot::channel(); let log_inner = log.clone(); let broadcaster_inner = server.broadcaster(); - let exit_future = exit.and_then(move |_| { - if let Err(e) = broadcaster_inner.shutdown() { - warn!( - log_inner, - "Websocket server errored on shutdown"; - "error" => format!("{:?}", e) - ); - } else { - info!(log_inner, "Websocket server shutdown"); - } - Ok(()) - }); + let exit_future = exit + .and_then(move |_| { + if let Err(e) = broadcaster_inner.shutdown() { + warn!( + log_inner, + "Websocket server errored on shutdown"; + "error" => format!("{:?}", e) + ); + } else { + info!(log_inner, "Websocket server shutdown"); + } + Ok(()) + }) + .map_err(|_| ()); // Place a future on the executor that will shutdown the websocket server when the // application exits. executor.spawn(exit_future); - exit_signal + exit_channel }; let log_inner = log.clone(); @@ -118,7 +127,7 @@ pub fn start_server( sender: Some(broadcaster), _phantom: PhantomData, }, - exit_signal, + exit_channel, actual_listen_addr, )) } diff --git a/book/src/http_validator.md b/book/src/http_validator.md index 633bbffa2..27902e741 100644 --- a/book/src/http_validator.md +++ b/book/src/http_validator.md @@ -5,16 +5,23 @@ client to connect to the beacon node and produce blocks and attestations. ## Endpoints -HTTP Path | Description | +HTTP Path | HTTP Method | Description | | --- | -- | -[`/validator/duties`](#validatorduties) | Provides block and attestation production information for validators. -[`/validator/duties/all`](#validatordutiesall) | Provides block and attestation production information for all validators. -[`/validator/duties/active`](#validatordutiesactive) | Provides block and attestation production information for all active validators. -[`/validator/block`](#validatorblock) | Produces a `BeaconBlock` object from current state. -[`/validator/attestation`](#validatorattestation) | Produces an unsigned `Attestation` object from current state. -[`/validator/block`](#validatorblock) | Processes a `SignedBeaconBlock` object and publishes it to the network. -[`/validator/attestation`](#validatorattestation) | Processes a signed `Attestation` and publishes it to the network. - +[`/validator/duties`](#validatorduties) | GET | Provides block and attestation production information for validators. +[`/validator/duties/all`](#validatordutiesall) | GET |Provides block and attestation production information for all validators. +[`/validator/duties/active`](#validatordutiesactive) | GET | Provides block and attestation production information for all active validators. +[`/validator/block`](#validatorblockget) | GET | Retrieves the current beacon +block for the validator to publish. +[`/validator/block`](#validatorblockpost) | POST | Publishes a signed block to the +network. +[`/validator/attestation`](#validatorattestation) | GET | Retrieves the current best attestation for a validator to publish. +[`/validator/attestations`](#validatorattestations) | POST | Publishes a list +of raw unaggregated attestations to their appropriate subnets +[`/validator/aggregate_attestation`](#validatoraggregateattestation) | GET | Gets an aggregate attestation for validators to sign and publish. +[`/validator/aggregate_attestations`](#validatoraggregateattestation) | POST | +Publishes a list of aggregated attestations for validators who are aggregators +[`/validator/subscribe`](#validatorsubscribe) | POST | Subscribes a list of +validators to the beacon node for a particular duty/slot. ## `/validator/duties` @@ -81,7 +88,8 @@ _Note: for demonstration purposes the second pubkey is some unknown pubkey._ "attestation_slot": 38511, "attestation_committee_index": 3, "attestation_committee_position": 39, - "block_proposal_slots": [] + "block_proposal_slots": [], + "aggregator_modulo": 5, }, { "validator_pubkey": "0x42f87bc7c8fa10408425bbeeeb3dc3874242b4bd92f57775b60b39142426f9ec80b273a64269332d97bdb7d93ae05a42", @@ -90,6 +98,7 @@ _Note: for demonstration purposes the second pubkey is some unknown pubkey._ "attestation_committee_index": null, "attestation_committee_position": null, "block_proposal_slots": [] + "aggregator_modulo": null, } ] ``` diff --git a/eth2/operation_pool/Cargo.toml b/eth2/operation_pool/Cargo.toml index 7bfc86063..0f6b2e0b9 100644 --- a/eth2/operation_pool/Cargo.toml +++ b/eth2/operation_pool/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "operation_pool" -version = "0.1.0" +version = "0.2.0" authors = ["Michael Sproul "] edition = "2018" diff --git a/eth2/operation_pool/src/lib.rs b/eth2/operation_pool/src/lib.rs index 02f545779..99a81fbad 100644 --- a/eth2/operation_pool/src/lib.rs +++ b/eth2/operation_pool/src/lib.rs @@ -10,8 +10,8 @@ use attestation_id::AttestationId; use max_cover::maximum_cover; use parking_lot::RwLock; use state_processing::per_block_processing::errors::{ - AttestationValidationError, AttesterSlashingValidationError, ExitValidationError, - ProposerSlashingValidationError, + AttestationInvalid, AttestationValidationError, AttesterSlashingValidationError, + ExitValidationError, ProposerSlashingValidationError, }; use state_processing::per_block_processing::{ get_slashable_indices_modular, verify_attestation_for_block_inclusion, @@ -22,25 +22,43 @@ use std::collections::{hash_map, HashMap, HashSet}; use std::marker::PhantomData; use types::{ typenum::Unsigned, Attestation, AttesterSlashing, BeaconState, BeaconStateError, ChainSpec, - EthSpec, Fork, ProposerSlashing, RelativeEpoch, SignedVoluntaryExit, Validator, + CommitteeIndex, Epoch, EthSpec, Fork, ProposerSlashing, RelativeEpoch, SignedVoluntaryExit, + Slot, Validator, }; +/// The number of slots we keep shard subnet attestations in the operation pool for. A value of 0 +/// means we remove the attestation pool as soon as the slot ends. +const ATTESTATION_SUBNET_SLOT_DURATION: u64 = 1; + #[derive(Default, Debug)] pub struct OperationPool { - /// Map from attestation ID (see below) to vectors of attestations. - attestations: RwLock>>>, + /// Map from attestation ID (see `attestation_id`) to vectors of attestations. + /// + /// These are collected from the aggregate channel. They should already be aggregated but we + /// check for disjoint attestations in the unlikely event we receive disjoint attestations. + aggregate_attestations: RwLock>>>, + /// A collection of aggregated attestations for a particular slot and committee index. + /// + /// Un-aggregated attestations are collected on a shard subnet and if a connected validator is + /// required to aggregate these attestations they are aggregated and stored here until the + /// validator is required to publish the aggregate attestation. + /// This segregates attestations into (slot,committee_index) then by `AttestationId`. + committee_attestations: + RwLock>>>, /// Map from two attestation IDs to a slashing for those IDs. attester_slashings: RwLock>>, /// Map from proposer index to slashing. proposer_slashings: RwLock>, /// Map from exiting validator to their exit data. voluntary_exits: RwLock>, + /// Marker to pin the generics. _phantom: PhantomData, } #[derive(Debug, PartialEq)] pub enum OpPoolError { GetAttestationsTotalBalanceError(BeaconStateError), + NoAttestationsForSlotCommittee, } impl OperationPool { @@ -49,12 +67,13 @@ impl OperationPool { Self::default() } - /// Insert an attestation into the pool, aggregating it with existing attestations if possible. + /// Insert an attestation from the aggregate channel into the pool, checking if the + /// aggregate can be further aggregated /// /// ## Note /// /// This function assumes the given `attestation` is valid. - pub fn insert_attestation( + pub fn insert_aggregate_attestation( &self, attestation: Attestation, fork: &Fork, @@ -63,7 +82,7 @@ impl OperationPool { let id = AttestationId::from_data(&attestation.data, fork, spec); // Take a write lock on the attestations map. - let mut attestations = self.attestations.write(); + let mut attestations = self.aggregate_attestations.write(); let existing_attestations = match attestations.entry(id) { hash_map::Entry::Vacant(entry) => { @@ -90,9 +109,90 @@ impl OperationPool { Ok(()) } - /// Total number of attestations in the pool, including attestations for the same data. + /// Insert a raw un-aggregated attestation into the pool, for a given (slot, committee_index). + /// + /// ## Note + /// + /// It would be a fair assumption that all attestations here are unaggregated and we + /// therefore do not need to check if `signers_disjoint_form`. However the cost of doing + /// so is low, so we perform this check for added safety. + pub fn insert_raw_attestation( + &self, + attestation: Attestation, + fork: &Fork, + spec: &ChainSpec, + ) -> Result<(), AttestationValidationError> { + let id = AttestationId::from_data(&attestation.data, fork, spec); + + let slot = attestation.data.slot.clone(); + let committee_index = attestation.data.index.clone(); + + // Take a write lock on the attestations map. + let mut attestations = self.committee_attestations.write(); + + let slot_index_map = attestations + .entry((slot, committee_index)) + .or_insert_with(|| HashMap::new()); + + let existing_attestation = match slot_index_map.entry(id) { + hash_map::Entry::Vacant(entry) => { + entry.insert(attestation); + return Ok(()); + } + hash_map::Entry::Occupied(entry) => entry.into_mut(), + }; + + if existing_attestation.signers_disjoint_from(&attestation) { + existing_attestation.aggregate(&attestation); + } else if *existing_attestation != attestation { + return Err(AttestationValidationError::Invalid( + AttestationInvalid::NotDisjoint, + )); + } + + Ok(()) + } + + /// Total number of aggregate attestations in the pool from the aggregate channel, including attestations for the same data. pub fn num_attestations(&self) -> usize { - self.attestations.read().values().map(Vec::len).sum() + self.aggregate_attestations + .read() + .values() + .map(Vec::len) + .sum() + } + + /// Total number of attestations in the pool, including attestations for the same data. + pub fn total_num_attestations(&self) -> usize { + self.num_attestations().saturating_add( + self.committee_attestations + .read() + .values() + .map(|map| map.values().len()) + .sum(), + ) + } + + /// Get the aggregated raw attestations for a (slot, committee) + //TODO: Check this logic and optimize + pub fn get_raw_aggregated_attestations( + &self, + slot: &Slot, + index: &CommitteeIndex, + state: &BeaconState, + spec: &ChainSpec, + ) -> Result, OpPoolError> { + let curr_domain_bytes = + AttestationId::compute_domain_bytes(state.current_epoch(), &state.fork, spec); + self.committee_attestations + .read() + .get(&(*slot, *index)) + .ok_or_else(|| OpPoolError::NoAttestationsForSlotCommittee)? + .iter() + .filter(|(key, _)| key.domain_bytes_match(&curr_domain_bytes)) + .next() + .map(|(_key, attestation)| attestation.clone()) + .ok_or_else(|| OpPoolError::NoAttestationsForSlotCommittee) } /// Get a list of attestations for inclusion in a block. @@ -109,7 +209,7 @@ impl OperationPool { let prev_domain_bytes = AttestationId::compute_domain_bytes(prev_epoch, &state.fork, spec); let curr_domain_bytes = AttestationId::compute_domain_bytes(current_epoch, &state.fork, spec); - let reader = self.attestations.read(); + let reader = self.aggregate_attestations.read(); let active_indices = state .get_cached_active_validator_indices(RelativeEpoch::Current) .map_err(OpPoolError::GetAttestationsTotalBalanceError)?; @@ -141,19 +241,38 @@ impl OperationPool { )) } - /// Remove attestations which are too old to be included in a block. - pub fn prune_attestations(&self, finalized_state: &BeaconState) { + /// Removes aggregate attestations which are too old to be included in a block. + /// + /// This leaves the committee_attestations intact. The committee attestations have their own + /// prune function as these are not for block inclusion and can be pruned more frequently. + /// See `prune_committee_attestations`. + //TODO: Michael to check this before merge + pub fn prune_attestations(&self, current_epoch: &Epoch) { // We know we can include an attestation if: // state.slot <= attestation_slot + SLOTS_PER_EPOCH // We approximate this check using the attestation's epoch, to avoid computing // the slot or relying on the committee cache of the finalized state. - self.attestations.write().retain(|_, attestations| { - // All the attestations in this bucket have the same data, so we only need to - // check the first one. - attestations.first().map_or(false, |att| { - finalized_state.current_epoch() <= att.data.target.epoch + 1 - }) - }); + self.aggregate_attestations + .write() + .retain(|_, attestations| { + // All the attestations in this bucket have the same data, so we only need to + // check the first one. + attestations + .first() + .map_or(false, |att| *current_epoch <= att.data.target.epoch + 1) + }); + } + + /// Removes old committee attestations. These should be used in the slot that they are + /// collected. We keep these around for one extra slot (i.e current_slot + 1) to account for + /// potential delays. + /// + /// The beacon chain should call this function every slot with the current slot as the + /// parameter. + pub fn prune_committee_attestations(&self, current_slot: &Slot) { + self.committee_attestations + .write() + .retain(|(slot, _), _| *slot + ATTESTATION_SUBNET_SLOT_DURATION >= *current_slot) } /// Insert a proposer slashing into the pool. @@ -332,8 +451,8 @@ impl OperationPool { } /// Prune all types of transactions given the latest finalized state. + // TODO: Michael - Can we shift these to per-epoch? pub fn prune_all(&self, finalized_state: &BeaconState, spec: &ChainSpec) { - self.prune_attestations(finalized_state); self.prune_proposer_slashings(finalized_state); self.prune_attester_slashings(finalized_state, spec); self.prune_voluntary_exits(finalized_state); @@ -383,7 +502,8 @@ fn prune_validator_hash_map( /// Compare two operation pools. impl PartialEq for OperationPool { fn eq(&self, other: &Self) -> bool { - *self.attestations.read() == *other.attestations.read() + *self.aggregate_attestations.read() == *other.aggregate_attestations.read() + && *self.committee_attestations.read() == *other.committee_attestations.read() && *self.attester_slashings.read() == *other.attester_slashings.read() && *self.proposer_slashings.read() == *other.proposer_slashings.read() && *self.voluntary_exits.read() == *other.voluntary_exits.read() @@ -397,6 +517,7 @@ mod release_tests { use super::*; use state_processing::common::{get_attesting_indices, get_base_reward}; use std::collections::BTreeSet; + use std::iter::FromIterator; use types::test_utils::*; use types::*; @@ -820,11 +941,15 @@ mod release_tests { let committee = state .get_beacon_committee(att.data.slot, att.data.index) .expect("should get beacon committee"); - let att_indices = get_attesting_indices::( - committee.committee, - &fresh_validators_bitlist, - ) - .unwrap(); + + let att_indices = BTreeSet::from_iter( + get_attesting_indices::( + committee.committee, + &fresh_validators_bitlist, + ) + .unwrap(), + ); + let fresh_indices = &att_indices - &seen_indices; let rewards = fresh_indices diff --git a/eth2/operation_pool/src/persistence.rs b/eth2/operation_pool/src/persistence.rs index 592d4d18b..ebb2fb7ba 100644 --- a/eth2/operation_pool/src/persistence.rs +++ b/eth2/operation_pool/src/persistence.rs @@ -17,7 +17,9 @@ pub struct PersistedOperationPool { /// Mapping from attestation ID to attestation mappings. // We could save space by not storing the attestation ID, but it might // be difficult to make that roundtrip due to eager aggregation. - attestations: Vec<(AttestationId, Vec>)>, + // Note: That we don't store the committee attestations as these are short lived and not worth + // persisting + aggregate_attestations: Vec<(AttestationId, Vec>)>, /// Attester slashings. attester_slashings: Vec>, /// Proposer slashings. @@ -29,8 +31,8 @@ pub struct PersistedOperationPool { impl PersistedOperationPool { /// Convert an `OperationPool` into serializable form. pub fn from_operation_pool(operation_pool: &OperationPool) -> Self { - let attestations = operation_pool - .attestations + let aggregate_attestations = operation_pool + .aggregate_attestations .read() .iter() .map(|(att_id, att)| (att_id.clone(), att.clone())) @@ -58,7 +60,7 @@ impl PersistedOperationPool { .collect(); Self { - attestations, + aggregate_attestations, attester_slashings, proposer_slashings, voluntary_exits, @@ -67,7 +69,7 @@ impl PersistedOperationPool { /// Reconstruct an `OperationPool`. pub fn into_operation_pool(self, state: &BeaconState, spec: &ChainSpec) -> OperationPool { - let attestations = RwLock::new(self.attestations.into_iter().collect()); + let aggregate_attestations = RwLock::new(self.aggregate_attestations.into_iter().collect()); let attester_slashings = RwLock::new( self.attester_slashings .into_iter() @@ -93,7 +95,8 @@ impl PersistedOperationPool { ); OperationPool { - attestations, + aggregate_attestations, + committee_attestations: Default::default(), attester_slashings, proposer_slashings, voluntary_exits, diff --git a/eth2/proto_array_fork_choice/Cargo.toml b/eth2/proto_array_fork_choice/Cargo.toml index 687b6aefc..f17515acc 100644 --- a/eth2/proto_array_fork_choice/Cargo.toml +++ b/eth2/proto_array_fork_choice/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "proto_array_fork_choice" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/eth2/state_processing/Cargo.toml b/eth2/state_processing/Cargo.toml index c8ae888aa..e407b18b2 100644 --- a/eth2/state_processing/Cargo.toml +++ b/eth2/state_processing/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "state_processing" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" @@ -15,7 +15,6 @@ serde = "1.0.102" serde_derive = "1.0.102" lazy_static = "1.4.0" serde_yaml = "0.8.11" -eth2_ssz = "0.1.2" beacon_chain = { path = "../../beacon_node/beacon_chain" } store = { path = "../../beacon_node/store" } @@ -24,6 +23,7 @@ store = { path = "../../beacon_node/store" } bls = { path = "../utils/bls" } integer-sqrt = "0.1.2" itertools = "0.8.1" +eth2_ssz = "0.1.2" eth2_ssz_types = { path = "../utils/ssz_types" } merkle_proof = { path = "../utils/merkle_proof" } log = "0.4.8" diff --git a/eth2/state_processing/src/common/get_attesting_indices.rs b/eth2/state_processing/src/common/get_attesting_indices.rs index 1bfbcabd5..b48bb8b5a 100644 --- a/eth2/state_processing/src/common/get_attesting_indices.rs +++ b/eth2/state_processing/src/common/get_attesting_indices.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeSet; use types::*; /// Returns validator indices which participated in the attestation, sorted by increasing index. @@ -7,17 +6,20 @@ use types::*; pub fn get_attesting_indices( committee: &[usize], bitlist: &BitList, -) -> Result, BeaconStateError> { +) -> Result, BeaconStateError> { if bitlist.len() != committee.len() { return Err(BeaconStateError::InvalidBitfield); } - Ok(committee - .iter() - .enumerate() - .filter_map(|(i, validator_index)| match bitlist.get(i) { - Ok(true) => Some(*validator_index), - _ => None, - }) - .collect()) + let mut indices = Vec::with_capacity(bitlist.num_set_bits()); + + for (i, validator_index) in committee.iter().enumerate() { + if let Ok(true) = bitlist.get(i) { + indices.push(*validator_index) + } + } + + indices.sort_unstable(); + + Ok(indices) } diff --git a/eth2/state_processing/src/common/initiate_validator_exit.rs b/eth2/state_processing/src/common/initiate_validator_exit.rs index efb26be1c..e9ff644f0 100644 --- a/eth2/state_processing/src/common/initiate_validator_exit.rs +++ b/eth2/state_processing/src/common/initiate_validator_exit.rs @@ -10,7 +10,7 @@ pub fn initiate_validator_exit( spec: &ChainSpec, ) -> Result<(), Error> { if index >= state.validators.len() { - return Err(Error::UnknownValidator); + return Err(Error::UnknownValidator(index as u64)); } // Return if the validator already initiated exit diff --git a/eth2/state_processing/src/common/slash_validator.rs b/eth2/state_processing/src/common/slash_validator.rs index e308c8346..86ac82d05 100644 --- a/eth2/state_processing/src/common/slash_validator.rs +++ b/eth2/state_processing/src/common/slash_validator.rs @@ -12,7 +12,7 @@ pub fn slash_validator( spec: &ChainSpec, ) -> Result<(), Error> { if slashed_index >= state.validators.len() || slashed_index >= state.balances.len() { - return Err(BeaconStateError::UnknownValidator); + return Err(BeaconStateError::UnknownValidator(slashed_index as u64)); } let epoch = state.current_epoch(); diff --git a/eth2/state_processing/src/lib.rs b/eth2/state_processing/src/lib.rs index e02f04ec1..63c5e2550 100644 --- a/eth2/state_processing/src/lib.rs +++ b/eth2/state_processing/src/lib.rs @@ -10,8 +10,8 @@ pub mod test_utils; pub use genesis::{initialize_beacon_state_from_eth1, is_valid_genesis_state, process_activations}; pub use per_block_processing::{ - errors::BlockProcessingError, per_block_processing, signature_sets, BlockSignatureStrategy, - VerifySignatures, + block_signature_verifier, errors::BlockProcessingError, per_block_processing, signature_sets, + BlockSignatureStrategy, BlockSignatureVerifier, VerifySignatures, }; pub use per_epoch_processing::{errors::EpochProcessingError, per_epoch_processing}; pub use per_slot_processing::{per_slot_processing, Error as SlotProcessingError}; diff --git a/eth2/state_processing/src/per_block_processing.rs b/eth2/state_processing/src/per_block_processing.rs index 7285f2dac..0e3728de5 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::{initiate_validator_exit, slash_validator}; use errors::{BlockOperationError, BlockProcessingError, HeaderInvalid, IntoWithIndex}; use rayon::prelude::*; -use signature_sets::{block_proposal_signature_set, randao_signature_set}; +use signature_sets::{block_proposal_signature_set, get_pubkey_from_state, randao_signature_set}; use std::convert::TryInto; use tree_hash::TreeHash; use types::*; @@ -21,7 +21,7 @@ pub use verify_deposit::{ pub use verify_exit::{verify_exit, verify_exit_time_independent_only}; pub mod block_processing_builder; -mod block_signature_verifier; +pub mod block_signature_verifier; pub mod errors; mod is_valid_indexed_attestation; pub mod signature_sets; @@ -83,8 +83,14 @@ pub fn per_block_processing( BlockSignatureStrategy::VerifyBulk => { // Verify all signatures in the block at once. block_verify!( - BlockSignatureVerifier::verify_entire_block(state, signed_block, block_root, spec) - .is_ok(), + BlockSignatureVerifier::verify_entire_block( + state, + |i| get_pubkey_from_state(state, i), + signed_block, + block_root, + spec + ) + .is_ok(), BlockProcessingError::BulkSignatureVerificationFailed ); VerifySignatures::False @@ -176,7 +182,14 @@ pub fn verify_block_signature( spec: &ChainSpec, ) -> Result<(), BlockOperationError> { verify!( - block_proposal_signature_set(state, block, block_root, spec)?.is_valid(), + block_proposal_signature_set( + state, + |i| get_pubkey_from_state(state, i), + block, + block_root, + spec + )? + .is_valid(), HeaderInvalid::ProposalSignatureInvalid ); @@ -196,7 +209,8 @@ pub fn process_randao( if verify_signatures.is_true() { // Verify RANDAO reveal signature. block_verify!( - randao_signature_set(state, block, spec)?.is_valid(), + randao_signature_set(state, |i| get_pubkey_from_state(state, i), block, spec)? + .is_valid(), BlockProcessingError::RandaoSignatureInvalid ); } diff --git a/eth2/state_processing/src/per_block_processing/block_signature_verifier.rs b/eth2/state_processing/src/per_block_processing/block_signature_verifier.rs index 51be38ff9..d0e34f53f 100644 --- a/eth2/state_processing/src/per_block_processing/block_signature_verifier.rs +++ b/eth2/state_processing/src/per_block_processing/block_signature_verifier.rs @@ -1,14 +1,16 @@ use super::signature_sets::{Error as SignatureSetError, Result as SignatureSetResult, *}; - use crate::common::get_indexed_attestation; use crate::per_block_processing::errors::{AttestationInvalid, BlockOperationError}; use bls::{verify_signature_sets, SignatureSet}; use rayon::prelude::*; +use std::borrow::Cow; use types::{ BeaconState, BeaconStateError, ChainSpec, EthSpec, Hash256, IndexedAttestation, SignedBeaconBlock, }; +pub use bls::G1Point; + pub type Result = std::result::Result; #[derive(Debug, PartialEq)] @@ -46,23 +48,27 @@ impl From> for Error { /// /// This allows for optimizations related to batch BLS operations (see the /// `Self::verify_entire_block(..)` function). -pub struct BlockSignatureVerifier<'a, T: EthSpec> { - block: &'a SignedBeaconBlock, +pub struct BlockSignatureVerifier<'a, T, F> +where + T: EthSpec, + F: Fn(usize) -> Option> + Clone, +{ + get_pubkey: Box, state: &'a BeaconState, spec: &'a ChainSpec, sets: Vec>, } -impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> { +impl<'a, T, F> BlockSignatureVerifier<'a, T, F> +where + T: EthSpec, + F: Fn(usize) -> Option> + Clone, +{ /// Create a new verifier without any included signatures. See the `include...` functions to /// add signatures, and the `verify` - pub fn new( - state: &'a BeaconState, - block: &'a SignedBeaconBlock, - spec: &'a ChainSpec, - ) -> Self { + pub fn new(state: &'a BeaconState, get_pubkey: F, spec: &'a ChainSpec) -> Self { Self { - block, + get_pubkey: Box::new(get_pubkey), state, spec, sets: vec![], @@ -78,22 +84,13 @@ impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> { /// See `Self::verify` for more detail. pub fn verify_entire_block( state: &'a BeaconState, + get_pubkey: F, block: &'a SignedBeaconBlock, block_root: Option, spec: &'a ChainSpec, ) -> Result<()> { - let mut verifier = Self::new(state, block, spec); - - verifier.include_block_proposal(block_root)?; - verifier.include_randao_reveal()?; - verifier.include_proposer_slashings()?; - verifier.include_attester_slashings()?; - verifier.include_attestations()?; - /* - * Deposits are not included because they can legally have invalid signatures. - */ - verifier.include_exits()?; - + let mut verifier = Self::new(state, get_pubkey, spec); + verifier.include_all_signatures(block, block_root)?; verifier.verify() } @@ -127,31 +124,82 @@ impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> { } } + /// Includes all signatures on the block (except the deposit signatures) for verification. + pub fn include_all_signatures( + &mut self, + block: &'a SignedBeaconBlock, + block_root: Option, + ) -> Result<()> { + self.include_block_proposal(block, block_root)?; + self.include_randao_reveal(block)?; + self.include_proposer_slashings(block)?; + self.include_attester_slashings(block)?; + self.include_attestations(block)?; + // Deposits are not included because they can legally have invalid signatures. + self.include_exits(block)?; + + Ok(()) + } + + /// Includes all signatures on the block (except the deposit signatures and the proposal + /// signature) for verification. + pub fn include_all_signatures_except_proposal( + &mut self, + block: &'a SignedBeaconBlock, + ) -> Result<()> { + self.include_randao_reveal(block)?; + self.include_proposer_slashings(block)?; + self.include_attester_slashings(block)?; + self.include_attestations(block)?; + // Deposits are not included because they can legally have invalid signatures. + self.include_exits(block)?; + + Ok(()) + } + /// Includes the block signature for `self.block` for verification. - fn include_block_proposal(&mut self, block_root: Option) -> Result<()> { - let set = block_proposal_signature_set(self.state, self.block, block_root, self.spec)?; + pub fn include_block_proposal( + &mut self, + block: &'a SignedBeaconBlock, + block_root: Option, + ) -> Result<()> { + let set = block_proposal_signature_set( + self.state, + self.get_pubkey.clone(), + block, + block_root, + self.spec, + )?; self.sets.push(set); Ok(()) } /// Includes the randao signature for `self.block` for verification. - fn include_randao_reveal(&mut self) -> Result<()> { - let set = randao_signature_set(self.state, &self.block.message, self.spec)?; + pub fn include_randao_reveal(&mut self, block: &'a SignedBeaconBlock) -> Result<()> { + let set = randao_signature_set( + self.state, + self.get_pubkey.clone(), + &block.message, + self.spec, + )?; self.sets.push(set); Ok(()) } /// Includes all signatures in `self.block.body.proposer_slashings` for verification. - fn include_proposer_slashings(&mut self) -> Result<()> { - let mut sets: Vec = self - .block + pub fn include_proposer_slashings(&mut self, block: &'a SignedBeaconBlock) -> Result<()> { + let mut sets: Vec = block .message .body .proposer_slashings .iter() .map(|proposer_slashing| { - let (set_1, set_2) = - proposer_slashing_signature_set(self.state, proposer_slashing, self.spec)?; + let (set_1, set_2) = proposer_slashing_signature_set( + self.state, + self.get_pubkey.clone(), + proposer_slashing, + self.spec, + )?; Ok(vec![set_1, set_2]) }) .collect::>>>()? @@ -164,15 +212,19 @@ impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> { } /// Includes all signatures in `self.block.body.attester_slashings` for verification. - fn include_attester_slashings(&mut self) -> Result<()> { - self.block + pub fn include_attester_slashings(&mut self, block: &'a SignedBeaconBlock) -> Result<()> { + block .message .body .attester_slashings .iter() .try_for_each(|attester_slashing| { - let (set_1, set_2) = - attester_slashing_signature_sets(&self.state, attester_slashing, &self.spec)?; + let (set_1, set_2) = attester_slashing_signature_sets( + &self.state, + self.get_pubkey.clone(), + attester_slashing, + &self.spec, + )?; self.sets.push(set_1); self.sets.push(set_2); @@ -182,8 +234,11 @@ impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> { } /// Includes all signatures in `self.block.body.attestations` for verification. - fn include_attestations(&mut self) -> Result>> { - self.block + pub fn include_attestations( + &mut self, + block: &'a SignedBeaconBlock, + ) -> Result>> { + block .message .body .attestations @@ -197,6 +252,7 @@ impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> { self.sets.push(indexed_attestation_signature_set( &self.state, + self.get_pubkey.clone(), &attestation.signature, &indexed_attestation, &self.spec, @@ -209,14 +265,13 @@ impl<'a, T: EthSpec> BlockSignatureVerifier<'a, T> { } /// Includes all signatures in `self.block.body.voluntary_exits` for verification. - fn include_exits(&mut self) -> Result<()> { - let mut sets = self - .block + pub fn include_exits(&mut self, block: &'a SignedBeaconBlock) -> Result<()> { + let mut sets = block .message .body .voluntary_exits .iter() - .map(|exit| exit_signature_set(&self.state, exit, &self.spec)) + .map(|exit| exit_signature_set(&self.state, self.get_pubkey.clone(), exit, &self.spec)) .collect::>()?; self.sets.append(&mut sets); diff --git a/eth2/state_processing/src/per_block_processing/errors.rs b/eth2/state_processing/src/per_block_processing/errors.rs index 609c57bdd..f7c51ebcc 100644 --- a/eth2/state_processing/src/per_block_processing/errors.rs +++ b/eth2/state_processing/src/per_block_processing/errors.rs @@ -235,6 +235,8 @@ pub enum AttestationInvalid { committee_len: usize, bitfield_len: usize, }, + /// The attestation was not disjoint compared to already seen attestations. + NotDisjoint, /// The validator index was unknown. UnknownValidator(u64), /// The attestation signature verification failed. diff --git a/eth2/state_processing/src/per_block_processing/is_valid_indexed_attestation.rs b/eth2/state_processing/src/per_block_processing/is_valid_indexed_attestation.rs index 323f0c5bf..202745ce0 100644 --- a/eth2/state_processing/src/per_block_processing/is_valid_indexed_attestation.rs +++ b/eth2/state_processing/src/per_block_processing/is_valid_indexed_attestation.rs @@ -1,5 +1,5 @@ use super::errors::{BlockOperationError, IndexedAttestationInvalid as Invalid}; -use super::signature_sets::indexed_attestation_signature_set; +use super::signature_sets::{get_pubkey_from_state, indexed_attestation_signature_set}; use crate::VerifySignatures; use types::*; @@ -43,6 +43,7 @@ pub fn is_valid_indexed_attestation( verify!( indexed_attestation_signature_set( state, + |i| get_pubkey_from_state(state, i), &indexed_attestation.signature, &indexed_attestation, spec diff --git a/eth2/state_processing/src/per_block_processing/signature_sets.rs b/eth2/state_processing/src/per_block_processing/signature_sets.rs index a91749af9..4c64863c1 100644 --- a/eth2/state_processing/src/per_block_processing/signature_sets.rs +++ b/eth2/state_processing/src/per_block_processing/signature_sets.rs @@ -3,6 +3,7 @@ //! //! This module exposes one function to extract each type of `SignatureSet` from a `BeaconBlock`. use bls::{G1Point, G1Ref, SignatureSet, SignedMessage}; +use ssz::DecodeError; use std::borrow::Cow; use std::convert::TryInto; use tree_hash::TreeHash; @@ -18,7 +19,7 @@ pub type Result = std::result::Result; #[derive(Debug, PartialEq, Clone)] pub enum Error { /// Signature verification failed. The block is invalid. - SignatureInvalid, + SignatureInvalid(DecodeError), /// There was an error attempting to read from a `BeaconState`. Block /// validity was not determined. BeaconStateError(BeaconStateError), @@ -39,13 +40,36 @@ impl From for Error { } } -/// A signature set that is valid if a block was signed by the expected block producer. -pub fn block_proposal_signature_set<'a, T: EthSpec>( +/// Helper function to get a public key from a `state`. +pub fn get_pubkey_from_state<'a, T>( state: &'a BeaconState, + validator_index: usize, +) -> Option> +where + T: EthSpec, +{ + state + .validators + .get(validator_index) + .and_then(|v| { + let pk: Option = (&v.pubkey).try_into().ok(); + pk + }) + .map(|pk| Cow::Owned(pk.into_point())) +} + +/// A signature set that is valid if a block was signed by the expected block producer. +pub fn block_proposal_signature_set<'a, T, F>( + state: &'a BeaconState, + get_pubkey: F, signed_block: &'a SignedBeaconBlock, block_root: Option, spec: &'a ChainSpec, -) -> Result> { +) -> Result> +where + T: EthSpec, + F: Fn(usize) -> Option>, +{ let block = &signed_block.message; let proposer_index = state.get_beacon_proposer_index(block.slot, spec)?; @@ -67,17 +91,22 @@ pub fn block_proposal_signature_set<'a, T: EthSpec>( Ok(SignatureSet::single( &signed_block.signature, - validator_pubkey(state, proposer_index)?, + get_pubkey(proposer_index).ok_or_else(|| Error::ValidatorUnknown(proposer_index as u64))?, message.as_bytes().to_vec(), )) } /// A signature set that is valid if the block proposers randao reveal signature is correct. -pub fn randao_signature_set<'a, T: EthSpec>( +pub fn randao_signature_set<'a, T, F>( state: &'a BeaconState, + get_pubkey: F, block: &'a BeaconBlock, spec: &'a ChainSpec, -) -> Result> { +) -> Result> +where + T: EthSpec, + F: Fn(usize) -> Option>, +{ let proposer_index = state.get_beacon_proposer_index(block.slot, spec)?; let domain = spec.get_domain( @@ -86,34 +115,41 @@ pub fn randao_signature_set<'a, T: EthSpec>( &state.fork, ); - let message = state.current_epoch().signing_root(domain); + let message = block.slot.epoch(T::slots_per_epoch()).signing_root(domain); Ok(SignatureSet::single( &block.body.randao_reveal, - validator_pubkey(state, proposer_index)?, + get_pubkey(proposer_index).ok_or_else(|| Error::ValidatorUnknown(proposer_index as u64))?, message.as_bytes().to_vec(), )) } /// Returns two signature sets, one for each `BlockHeader` included in the `ProposerSlashing`. -pub fn proposer_slashing_signature_set<'a, T: EthSpec>( +pub fn proposer_slashing_signature_set<'a, T, F>( state: &'a BeaconState, + get_pubkey: F, proposer_slashing: &'a ProposerSlashing, spec: &'a ChainSpec, -) -> Result<(SignatureSet<'a>, SignatureSet<'a>)> { +) -> Result<(SignatureSet<'a>, SignatureSet<'a>)> +where + T: EthSpec, + F: Fn(usize) -> Option>, +{ let proposer_index = proposer_slashing.proposer_index as usize; Ok(( block_header_signature_set( state, &proposer_slashing.signed_header_1, - validator_pubkey(state, proposer_index)?, + get_pubkey(proposer_index) + .ok_or_else(|| Error::ValidatorUnknown(proposer_index as u64))?, spec, )?, block_header_signature_set( state, &proposer_slashing.signed_header_2, - validator_pubkey(state, proposer_index)?, + get_pubkey(proposer_index) + .ok_or_else(|| Error::ValidatorUnknown(proposer_index as u64))?, spec, )?, )) @@ -146,16 +182,24 @@ fn block_header_signature_set<'a, T: EthSpec>( } /// Returns the signature set for the given `indexed_attestation`. -pub fn indexed_attestation_signature_set<'a, 'b, T: EthSpec>( +pub fn indexed_attestation_signature_set<'a, 'b, T, F>( state: &'a BeaconState, + get_pubkey: F, signature: &'a AggregateSignature, indexed_attestation: &'b IndexedAttestation, spec: &'a ChainSpec, -) -> Result> { +) -> Result> +where + T: EthSpec, + F: Fn(usize) -> Option>, +{ let pubkeys = indexed_attestation .attesting_indices .into_iter() - .map(|&validator_idx| Ok(validator_pubkey(state, validator_idx as usize)?)) + .map(|&validator_idx| { + Ok(get_pubkey(validator_idx as usize) + .ok_or_else(|| Error::ValidatorUnknown(validator_idx))?) + }) .collect::>()?; let domain = spec.get_domain( @@ -172,17 +216,25 @@ pub fn indexed_attestation_signature_set<'a, 'b, T: EthSpec>( /// Returns the signature set for the given `indexed_attestation` but pubkeys are supplied directly /// instead of from the state. -pub fn indexed_attestation_signature_set_from_pubkeys<'a, 'b, T: EthSpec>( - pubkeys: Vec<&'a PublicKey>, +pub fn indexed_attestation_signature_set_from_pubkeys<'a, 'b, T, F>( + get_pubkey: F, signature: &'a AggregateSignature, indexed_attestation: &'b IndexedAttestation, fork: &Fork, spec: &'a ChainSpec, -) -> Result> { - let pubkeys = pubkeys +) -> Result> +where + T: EthSpec, + F: Fn(usize) -> Option>, +{ + let pubkeys = indexed_attestation + .attesting_indices .into_iter() - .map(|pubkey| Cow::Borrowed(&pubkey.as_raw().point)) - .collect(); + .map(|&validator_idx| { + Ok(get_pubkey(validator_idx as usize) + .ok_or_else(|| Error::ValidatorUnknown(validator_idx))?) + }) + .collect::>()?; let domain = spec.get_domain( indexed_attestation.data.target.epoch, @@ -197,20 +249,27 @@ pub fn indexed_attestation_signature_set_from_pubkeys<'a, 'b, T: EthSpec>( } /// Returns the signature set for the given `attester_slashing` and corresponding `pubkeys`. -pub fn attester_slashing_signature_sets<'a, T: EthSpec>( +pub fn attester_slashing_signature_sets<'a, T, F>( state: &'a BeaconState, + get_pubkey: F, attester_slashing: &'a AttesterSlashing, spec: &'a ChainSpec, -) -> Result<(SignatureSet<'a>, SignatureSet<'a>)> { +) -> Result<(SignatureSet<'a>, SignatureSet<'a>)> +where + T: EthSpec, + F: Fn(usize) -> Option> + Clone, +{ Ok(( indexed_attestation_signature_set( state, + get_pubkey.clone(), &attester_slashing.attestation_1.signature, &attester_slashing.attestation_1, spec, )?, indexed_attestation_signature_set( state, + get_pubkey, &attester_slashing.attestation_2.signature, &attester_slashing.attestation_2, spec, @@ -250,11 +309,16 @@ pub fn deposit_signature_set<'a>( /// Returns a signature set that is valid if the `SignedVoluntaryExit` was signed by the indicated /// validator. -pub fn exit_signature_set<'a, T: EthSpec>( +pub fn exit_signature_set<'a, T, F>( state: &'a BeaconState, + get_pubkey: F, signed_exit: &'a SignedVoluntaryExit, spec: &'a ChainSpec, -) -> Result> { +) -> Result> +where + T: EthSpec, + F: Fn(usize) -> Option>, +{ let exit = &signed_exit.message; let proposer_index = exit.validator_index as usize; @@ -264,30 +328,7 @@ pub fn exit_signature_set<'a, T: EthSpec>( Ok(SignatureSet::single( &signed_exit.signature, - validator_pubkey(state, proposer_index)?, + get_pubkey(proposer_index).ok_or_else(|| Error::ValidatorUnknown(proposer_index as u64))?, message, )) } - -/// Maps a validator index to a `PublicKey`. -pub fn validator_pubkey<'a, T: EthSpec>( - state: &'a BeaconState, - validator_index: usize, -) -> Result> { - let pubkey_bytes = &state - .validators - .get(validator_index) - .ok_or_else(|| Error::ValidatorUnknown(validator_index as u64))? - .pubkey; - - if let Some(pubkey) = pubkey_bytes.decompressed() { - Ok(Cow::Borrowed(&pubkey.as_raw().point)) - } else { - pubkey_bytes - .try_into() - .map(|pubkey: PublicKey| Cow::Owned(pubkey.as_raw().point.clone())) - .map_err(|_| Error::BadBlsBytes { - validator_index: validator_index as u64, - }) - } -} 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 a2d185402..d44b31f04 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,8 @@ use super::errors::{BlockOperationError, ExitInvalid}; -use crate::per_block_processing::{signature_sets::exit_signature_set, VerifySignatures}; +use crate::per_block_processing::{ + signature_sets::{exit_signature_set, get_pubkey_from_state}, + VerifySignatures, +}; use types::*; type Result = std::result::Result>; @@ -84,7 +87,13 @@ fn verify_exit_parametric( if verify_signatures.is_true() { verify!( - exit_signature_set(state, signed_exit, spec)?.is_valid(), + exit_signature_set( + state, + |i| get_pubkey_from_state(state, i), + signed_exit, + spec + )? + .is_valid(), ExitInvalid::BadSignature ); } 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 268e56c14..ff692d563 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::{BlockOperationError, ProposerSlashingInvalid as Invalid}; -use super::signature_sets::proposer_slashing_signature_set; +use super::signature_sets::{get_pubkey_from_state, proposer_slashing_signature_set}; use crate::VerifySignatures; use types::*; @@ -49,8 +49,12 @@ pub fn verify_proposer_slashing( ); if verify_signatures.is_true() { - let (signature_set_1, signature_set_2) = - proposer_slashing_signature_set(state, proposer_slashing, spec)?; + let (signature_set_1, signature_set_2) = proposer_slashing_signature_set( + state, + |i| get_pubkey_from_state(state, i), + proposer_slashing, + spec, + )?; verify!(signature_set_1.is_valid(), Invalid::BadProposal1Signature); verify!(signature_set_2.is_valid(), Invalid::BadProposal2Signature); } diff --git a/eth2/types/Cargo.toml b/eth2/types/Cargo.toml index e52ad8032..fdd97736f 100644 --- a/eth2/types/Cargo.toml +++ b/eth2/types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "types" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner ", "Age Manning "] edition = "2018" diff --git a/eth2/types/src/aggregate_and_proof.rs b/eth2/types/src/aggregate_and_proof.rs new file mode 100644 index 000000000..d814349e8 --- /dev/null +++ b/eth2/types/src/aggregate_and_proof.rs @@ -0,0 +1,80 @@ +use super::{Attestation, Domain, EthSpec, Fork, PublicKey, SecretKey, Signature, SignedRoot}; +use crate::test_utils::TestRandom; +use serde_derive::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use test_random_derive::TestRandom; +use tree_hash_derive::TreeHash; + +/// A Validators aggregate attestation and selection proof. +/// +/// Spec v0.10.1 +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)] +#[serde(bound = "T: EthSpec")] +pub struct AggregateAndProof { + /// The index of the validator that created the attestation. + pub aggregator_index: u64, + /// The aggregate attestation. + pub aggregate: Attestation, + /// A proof provided by the validator that permits them to publish on the + /// `beacon_aggregate_and_proof` gossipsub topic. + pub selection_proof: Signature, +} + +impl AggregateAndProof { + pub fn is_valid_selection_proof(&self, validator_pubkey: &PublicKey, fork: &Fork) -> bool { + let target_epoch = self.aggregate.data.slot.epoch(T::slots_per_epoch()); + let domain = T::default_spec().get_domain(target_epoch, Domain::SelectionProof, fork); + let message = self.aggregate.data.slot.signing_root(domain); + self.selection_proof + .verify(message.as_bytes(), validator_pubkey) + } + + /// Converts Self into a SignedAggregateAndProof. + pub fn into_signed(self, secret_key: &SecretKey, fork: &Fork) -> SignedAggregateAndProof { + let target_epoch = self.aggregate.data.slot.epoch(T::slots_per_epoch()); + let domain = T::default_spec().get_domain(target_epoch, Domain::AggregateAndProof, fork); + let sign_message = self.signing_root(domain); + let signature = Signature::new(sign_message.as_bytes(), &secret_key); + + SignedAggregateAndProof { + message: self, + signature, + } + } +} + +impl SignedRoot for AggregateAndProof {} + +/// A Validators signed aggregate proof to publish on the `beacon_aggregate_and_proof` +/// gossipsub topic. +/// +/// Spec v0.10.1 +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)] +#[serde(bound = "T: EthSpec")] +pub struct SignedAggregateAndProof { + /// The `AggregateAndProof` that was signed. + pub message: AggregateAndProof, + /// The aggregate attestation. + pub signature: Signature, +} + +impl SignedRoot for SignedAggregateAndProof {} + +impl SignedAggregateAndProof { + /// Verifies the signature of the `AggregateAndProof` + pub fn is_valid_signature(&self, validator_pubkey: &PublicKey, fork: &Fork) -> bool { + let target_epoch = self.message.aggregate.data.slot.epoch(T::slots_per_epoch()); + let domain = T::default_spec().get_domain(target_epoch, Domain::AggregateAndProof, fork); + let message = self.signing_root(domain); + self.signature.verify(message.as_bytes(), validator_pubkey) + } + + /// Verifies the signature of the `AggregateAndProof` as well the underlying selection_proof in + /// the contained `AggregateAndProof`. + pub fn is_valid(&self, validator_pubkey: &PublicKey, fork: &Fork) -> bool { + self.is_valid_signature(validator_pubkey, fork) + && self + .message + .is_valid_selection_proof(validator_pubkey, fork) + } +} diff --git a/eth2/types/src/attestation.rs b/eth2/types/src/attestation.rs index 40b479853..c858c7474 100644 --- a/eth2/types/src/attestation.rs +++ b/eth2/types/src/attestation.rs @@ -1,6 +1,6 @@ use super::{ AggregateSignature, AttestationData, BitList, ChainSpec, Domain, EthSpec, Fork, SecretKey, - Signature, SignedRoot, + Signature, SignedRoot, SubnetId, }; use crate::test_utils::TestRandom; @@ -75,6 +75,14 @@ impl Attestation { Ok(()) } } + + /// Returns the subnet id associated with the attestation. + /// + /// Note, this will return the subnet id for an aggregated attestation. This is done + /// to avoid checking aggregate bits every time we wish to get an id. + pub fn subnet_id(&self) -> SubnetId { + SubnetId::new(self.data.index % T::default_spec().attestation_subnet_count) + } } #[cfg(test)] diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index 45c71774f..f387611e3 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -11,6 +11,7 @@ use serde_derive::{Deserialize, Serialize}; use ssz::ssz_encode; use ssz_derive::{Decode, Encode}; use ssz_types::{typenum::Unsigned, BitVector, FixedVector}; +use std::convert::TryInto; use swap_or_not_shuffle::compute_shuffled_index; use test_random_derive::TestRandom; use tree_hash::TreeHash; @@ -36,7 +37,7 @@ const MAX_RANDOM_BYTE: u64 = (1 << 8) - 1; pub enum Error { EpochOutOfBounds, SlotOutOfBounds, - UnknownValidator, + UnknownValidator(u64), UnableToDetermineProducer, InvalidBitfield, ValidatorIsWithdrawable, @@ -332,6 +333,7 @@ impl BeaconState { /// /// Spec v0.10.1 pub fn get_active_validator_indices(&self, epoch: Epoch) -> Vec { + // FIXME(sproul): put a bounds check on here based on the maximum lookahead get_active_validator_indices(&self.validators, epoch) } @@ -427,6 +429,30 @@ impl BeaconState { } } + /// Return `true` if the validator who produced `slot_signature` is eligible to aggregate. + /// + /// Spec v0.10.1 + pub fn is_aggregator( + &self, + slot: Slot, + index: CommitteeIndex, + slot_signature: &Signature, + spec: &ChainSpec, + ) -> Result { + let committee = self.get_beacon_committee(slot, index)?; + let modulo = std::cmp::max( + 1, + committee.committee.len() as u64 / spec.target_aggregators_per_committee, + ); + let signature_hash = hash(&slot_signature.as_bytes()); + let signature_hash_int = u64::from_le_bytes( + signature_hash[0..8] + .try_into() + .expect("first 8 bytes of signature should always convert to fixed array"), + ); + Ok(signature_hash_int % modulo == 0) + } + /// Returns the beacon proposer index for the `slot` in the given `relative_epoch`. /// /// Spec v0.10.1 @@ -710,7 +736,7 @@ impl BeaconState { self.validators .get(validator_index) .map(|v| v.effective_balance) - .ok_or_else(|| Error::UnknownValidator) + .ok_or_else(|| Error::UnknownValidator(validator_index as u64)) } /// Return the epoch at which an activation or exit triggered in ``epoch`` takes effect. @@ -734,7 +760,7 @@ impl BeaconState { )) } - /// Returns the `slot`, `index` and `committee_position` for which a validator must produce an + /// Returns the `slot`, `index`, `committee_position` and `committee_len` for which a validator must produce an /// attestation. /// /// Note: Utilizes the cache and will fail if the appropriate cache is not initialized. @@ -770,7 +796,6 @@ impl BeaconState { self.update_pubkey_cache()?; self.build_tree_hash_cache()?; self.exit_cache.build(&self.validators, spec)?; - self.decompress_validator_pubkeys()?; Ok(()) } @@ -938,23 +963,6 @@ impl BeaconState { self.tree_hash_cache = None; } - /// Iterate through all validators and decompress their public key, unless it has already been - /// decompressed. - /// - /// Does not check the validity of already decompressed keys. - pub fn decompress_validator_pubkeys(&mut self) -> Result<(), Error> { - self.validators.iter_mut().try_for_each(|validator| { - if validator.pubkey.decompressed().is_none() { - validator - .pubkey - .decompress() - .map_err(Error::InvalidValidatorPubkey) - } else { - Ok(()) - } - }) - } - /// Clone the state whilst preserving only the selected caches. pub fn clone_with(&self, config: CloneConfig) -> Self { BeaconState { diff --git a/eth2/types/src/chain_spec.rs b/eth2/types/src/chain_spec.rs index 188d5842a..f0ad2f07e 100644 --- a/eth2/types/src/chain_spec.rs +++ b/eth2/types/src/chain_spec.rs @@ -17,6 +17,8 @@ pub enum Domain { Randao, Deposit, VoluntaryExit, + SelectionProof, + AggregateAndProof, } /// Holds all the "constants" for a BeaconChain. @@ -93,6 +95,8 @@ pub struct ChainSpec { domain_randao: u32, domain_deposit: u32, domain_voluntary_exit: u32, + domain_selection_proof: u32, + domain_aggregate_and_proof: u32, /* * Fork choice @@ -105,8 +109,17 @@ pub struct ChainSpec { pub eth1_follow_distance: u64, pub seconds_per_eth1_block: u64, + /* + * Networking + */ pub boot_nodes: Vec, pub network_id: u8, + pub attestation_propagation_slot_range: u64, + pub maximum_gossip_clock_disparity_millis: u64, + pub target_aggregators_per_committee: u64, + pub attestation_subnet_count: u64, + pub random_subnets_per_validator: u64, + pub epochs_per_random_subnet_subscription: u64, } impl ChainSpec { @@ -120,6 +133,8 @@ impl ChainSpec { Domain::Randao => self.domain_randao, Domain::Deposit => self.domain_deposit, Domain::VoluntaryExit => self.domain_voluntary_exit, + Domain::SelectionProof => self.domain_selection_proof, + Domain::AggregateAndProof => self.domain_aggregate_and_proof, } } @@ -223,6 +238,8 @@ impl ChainSpec { domain_randao: 2, domain_deposit: 3, domain_voluntary_exit: 4, + domain_selection_proof: 5, + domain_aggregate_and_proof: 6, /* * Fork choice @@ -240,6 +257,12 @@ impl ChainSpec { */ boot_nodes: vec![], network_id: 1, // mainnet network id + attestation_propagation_slot_range: 32, + attestation_subnet_count: 64, + random_subnets_per_validator: 1, + maximum_gossip_clock_disparity_millis: 500, + target_aggregators_per_committee: 16, + epochs_per_random_subnet_subscription: 256, } } diff --git a/eth2/types/src/eth_spec.rs b/eth2/types/src/eth_spec.rs index 5a86d390d..15b6b06ad 100644 --- a/eth2/types/src/eth_spec.rs +++ b/eth2/types/src/eth_spec.rs @@ -12,6 +12,7 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq { */ type GenesisEpoch: Unsigned + Clone + Sync + Send + Debug + PartialEq; type JustificationBitsLength: Unsigned + Clone + Sync + Send + Debug + PartialEq + Default; + type SubnetBitfieldLength: Unsigned + Clone + Sync + Send + Debug + PartialEq + Default; /* * Misc */ @@ -125,6 +126,7 @@ pub struct MainnetEthSpec; impl EthSpec for MainnetEthSpec { type JustificationBitsLength = U4; + type SubnetBitfieldLength = U64; type MaxValidatorsPerCommittee = U2048; type GenesisEpoch = U0; type SlotsPerEpoch = U32; @@ -164,6 +166,7 @@ impl EthSpec for MinimalEthSpec { params_from_eth_spec!(MainnetEthSpec { JustificationBitsLength, + SubnetBitfieldLength, MaxValidatorsPerCommittee, GenesisEpoch, HistoricalRootsLimit, @@ -196,6 +199,7 @@ impl EthSpec for InteropEthSpec { params_from_eth_spec!(MainnetEthSpec { JustificationBitsLength, + SubnetBitfieldLength, MaxValidatorsPerCommittee, GenesisEpoch, HistoricalRootsLimit, diff --git a/eth2/types/src/lib.rs b/eth2/types/src/lib.rs index 6418d19d6..bf399b551 100644 --- a/eth2/types/src/lib.rs +++ b/eth2/types/src/lib.rs @@ -6,6 +6,7 @@ #[macro_use] pub mod test_utils; +pub mod aggregate_and_proof; pub mod attestation; pub mod attestation_data; pub mod attestation_duty; @@ -39,10 +40,12 @@ pub mod voluntary_exit; #[macro_use] pub mod slot_epoch_macros; pub mod slot_epoch; +pub mod subnet_id; mod tree_hash_impls; use ethereum_types::{H160, H256}; +pub use crate::aggregate_and_proof::{AggregateAndProof, SignedAggregateAndProof}; pub use crate::attestation::{Attestation, Error as AttestationError}; pub use crate::attestation_data::AttestationData; pub use crate::attestation_duty::AttestationDuty; @@ -70,6 +73,7 @@ pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader; pub use crate::signed_voluntary_exit::SignedVoluntaryExit; pub use crate::signing_root::{SignedRoot, SigningRoot}; pub use crate::slot_epoch::{Epoch, Slot}; +pub use crate::subnet_id::SubnetId; pub use crate::validator::Validator; pub use crate::voluntary_exit::VoluntaryExit; diff --git a/eth2/types/src/slot_epoch.rs b/eth2/types/src/slot_epoch.rs index 35dce8e38..f77ea2d7d 100644 --- a/eth2/types/src/slot_epoch.rs +++ b/eth2/types/src/slot_epoch.rs @@ -94,6 +94,7 @@ impl Epoch { } impl SignedRoot for Epoch {} +impl SignedRoot for Slot {} pub struct SlotIter<'a> { current_iteration: u64, diff --git a/eth2/types/src/subnet_id.rs b/eth2/types/src/subnet_id.rs new file mode 100644 index 000000000..6699d6cc0 --- /dev/null +++ b/eth2/types/src/subnet_id.rs @@ -0,0 +1,26 @@ +//! Identifies each shard by an integer identifier. +use serde_derive::{Deserialize, Serialize}; +use std::ops::{Deref, DerefMut}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct SubnetId(u64); + +impl SubnetId { + pub fn new(id: u64) -> Self { + SubnetId(id) + } +} + +impl Deref for SubnetId { + type Target = u64; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for SubnetId { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} diff --git a/eth2/utils/bls/Cargo.toml b/eth2/utils/bls/Cargo.toml index e568e9715..f22263e31 100644 --- a/eth2/utils/bls/Cargo.toml +++ b/eth2/utils/bls/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bls" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/eth2/utils/bls/src/fake_public_key.rs b/eth2/utils/bls/src/fake_public_key.rs index 7395612e7..b78145cff 100644 --- a/eth2/utils/bls/src/fake_public_key.rs +++ b/eth2/utils/bls/src/fake_public_key.rs @@ -85,6 +85,14 @@ impl FakePublicKey { pub fn as_raw(&self) -> &Self { self } + + pub fn as_point(&self) -> &G1Point { + &self.point + } + + pub fn into_point(self) -> G1Point { + self.point + } } impl fmt::Display for FakePublicKey { diff --git a/eth2/utils/bls/src/macros.rs b/eth2/utils/bls/src/macros.rs index f60832193..4eddaf27c 100644 --- a/eth2/utils/bls/src/macros.rs +++ b/eth2/utils/bls/src/macros.rs @@ -92,7 +92,6 @@ macro_rules! bytes_struct { #[derive(Clone)] pub struct $name { bytes: [u8; $byte_size], - decompressed: Option<$type> } }; ($name: ident, $type: ty, $byte_size: expr, $small_name: expr) => { @@ -103,14 +102,12 @@ macro_rules! bytes_struct { pub fn from_bytes(bytes: &[u8]) -> Result { Ok(Self { bytes: Self::get_bytes(bytes)?, - decompressed: None }) } pub fn empty() -> Self { Self { bytes: [0; $byte_size], - decompressed: None } } @@ -134,15 +131,6 @@ macro_rules! bytes_struct { Ok(result) } } - - pub fn decompress(&mut self) -> Result<(), ssz::DecodeError> { - self.decompressed = Some(<&Self as std::convert::TryInto<$type>>::try_into(self)?); - Ok(()) - } - - pub fn decompressed(&self) -> &Option<$type> { - &self.decompressed - } } impl std::fmt::Debug for $name { @@ -180,7 +168,44 @@ macro_rules! bytes_struct { } } - impl_ssz!($name, $byte_size, "$type"); + impl ssz::Encode for $name { + fn is_ssz_fixed_len() -> bool { + true + } + + fn ssz_fixed_len() -> usize { + $byte_size + } + + fn ssz_bytes_len(&self) -> usize { + $byte_size + } + + fn ssz_append(&self, buf: &mut Vec) { + buf.extend_from_slice(&self.bytes) + } + } + + impl ssz::Decode for $name { + 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 { + Self::from_bytes(bytes) + } + } + } impl tree_hash::TreeHash for $name { fn tree_hash_type() -> tree_hash::TreeHashType { diff --git a/eth2/utils/bls/src/public_key.rs b/eth2/utils/bls/src/public_key.rs index 42ed592ef..70ad37f35 100644 --- a/eth2/utils/bls/src/public_key.rs +++ b/eth2/utils/bls/src/public_key.rs @@ -1,5 +1,5 @@ use super::{SecretKey, BLS_PUBLIC_KEY_BYTE_SIZE}; -use milagro_bls::PublicKey as RawPublicKey; +use milagro_bls::{G1Point, PublicKey as RawPublicKey}; use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_hex::{encode as hex_encode, PrefixedHexVisitor}; @@ -24,11 +24,21 @@ impl PublicKey { Self(raw) } - /// Returns the underlying signature. + /// Returns a reference to the underlying signature. pub fn as_raw(&self) -> &RawPublicKey { &self.0 } + /// Consumes self and returns the underlying signature. + pub fn as_point(&self) -> &G1Point { + &self.0.point + } + + /// Consumes self and returns the underlying signature. + pub fn into_point(self) -> G1Point { + self.0.point + } + /// Returns the underlying point as compressed bytes. /// /// Identical to `self.as_uncompressed_bytes()`. diff --git a/eth2/utils/compare_fields/Cargo.toml b/eth2/utils/compare_fields/Cargo.toml index 33826c71d..ee5fe5c23 100644 --- a/eth2/utils/compare_fields/Cargo.toml +++ b/eth2/utils/compare_fields/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "compare_fields" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/eth2/utils/compare_fields_derive/Cargo.toml b/eth2/utils/compare_fields_derive/Cargo.toml index 8832e26d3..485b2708d 100644 --- a/eth2/utils/compare_fields_derive/Cargo.toml +++ b/eth2/utils/compare_fields_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "compare_fields_derive" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/eth2/utils/deposit_contract/Cargo.toml b/eth2/utils/deposit_contract/Cargo.toml index 1d28546da..84ade2cfd 100644 --- a/eth2/utils/deposit_contract/Cargo.toml +++ b/eth2/utils/deposit_contract/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deposit_contract" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/eth2/utils/eth2_config/Cargo.toml b/eth2/utils/eth2_config/Cargo.toml index f186a90a0..c9af2fef3 100644 --- a/eth2/utils/eth2_config/Cargo.toml +++ b/eth2/utils/eth2_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "eth2_config" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/eth2/utils/eth2_interop_keypairs/Cargo.toml b/eth2/utils/eth2_interop_keypairs/Cargo.toml index f6a6cd346..641f82c25 100644 --- a/eth2/utils/eth2_interop_keypairs/Cargo.toml +++ b/eth2/utils/eth2_interop_keypairs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "eth2_interop_keypairs" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/eth2/utils/eth2_testnet_config/Cargo.toml b/eth2/utils/eth2_testnet_config/Cargo.toml index 13c4d387f..3df6897a4 100644 --- a/eth2/utils/eth2_testnet_config/Cargo.toml +++ b/eth2/utils/eth2_testnet_config/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "eth2_testnet_config" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/eth2/utils/hashmap_delay/Cargo.toml b/eth2/utils/hashmap_delay/Cargo.toml new file mode 100644 index 000000000..918a8568f --- /dev/null +++ b/eth2/utils/hashmap_delay/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "hashmap_delay" +version = "0.2.0" +authors = ["Age Manning "] +edition = "2018" + +[dependencies] +tokio-timer = "0.2.12" +futures = "0.1.29" diff --git a/eth2/utils/hashmap_delay/src/hashmap_delay.rs b/eth2/utils/hashmap_delay/src/hashmap_delay.rs new file mode 100644 index 000000000..ea4fa1457 --- /dev/null +++ b/eth2/utils/hashmap_delay/src/hashmap_delay.rs @@ -0,0 +1,161 @@ +//! A simple hashmap object coupled with a `delay_queue` which has entries that expire after a +//! fixed time. +//! +//! A `HashMapDelay` implements `Stream` which removes expired items from the map. + +/// The default delay for entries, in seconds. This is only used when `insert()` is used to add +/// entries. +const DEFAULT_DELAY: u64 = 30; + +use futures::prelude::*; +use std::collections::HashMap; +use std::time::Duration; +use tokio_timer::delay_queue::{self, DelayQueue}; + +pub struct HashMapDelay +where + K: std::cmp::Eq + std::hash::Hash + std::clone::Clone, +{ + /// The given entries. + entries: HashMap>, + /// A queue holding the timeouts of each entry. + expirations: DelayQueue, + /// The default expiration timeout of an entry. + default_entry_timeout: Duration, +} + +/// A wrapping around entries that adds the link to the entry's expiration, via a `delay_queue` key. +struct MapEntry { + /// The expiration key for the entry. + key: delay_queue::Key, + /// The actual entry. + value: V, +} + +impl Default for HashMapDelay +where + K: std::cmp::Eq + std::hash::Hash + std::clone::Clone, +{ + fn default() -> Self { + HashMapDelay::new(Duration::from_secs(DEFAULT_DELAY)) + } +} + +impl HashMapDelay +where + K: std::cmp::Eq + std::hash::Hash + std::clone::Clone, +{ + /// Creates a new instance of `HashMapDelay`. + pub fn new(default_entry_timeout: Duration) -> Self { + HashMapDelay { + entries: HashMap::new(), + expirations: DelayQueue::new(), + default_entry_timeout, + } + } + + /// Insert an entry into the mapping. Entries will expire after the `default_entry_timeout`. + pub fn insert(&mut self, key: K, value: V) { + self.insert_at(key, value, self.default_entry_timeout); + } + + /// Inserts an entry that will expire at a given instant. + pub fn insert_at(&mut self, key: K, value: V, entry_duration: Duration) { + let delay_key = self.expirations.insert(key.clone(), entry_duration); + let entry = MapEntry { + key: delay_key, + value, + }; + self.entries.insert(key, entry); + } + + /// Gets a reference to an entry if it exists. + /// + /// Returns None if the entry does not exist. + pub fn get(&self, key: &K) -> Option<&V> { + self.entries.get(key).map(|entry| &entry.value) + } + + /// Gets a mutable reference to an entry if it exists. + /// + /// Returns None if the entry does not exist. + pub fn get_mut(&mut self, key: &K) -> Option<&mut V> { + self.entries.get_mut(key).map(|entry| &mut entry.value) + } + + /// Returns true if the key exists, false otherwise. + pub fn contains_key(&self, key: &K) -> bool { + self.entries.contains_key(key) + } + + /// Returns the length of the mapping. + pub fn len(&self) -> usize { + self.entries.len() + } + + /// Updates the timeout for a given key. Returns true if the key existed, false otherwise. + /// + /// Panics if the duration is too far in the future. + pub fn update_timeout(&mut self, key: &K, timeout: Duration) -> bool { + if let Some(entry) = self.entries.get(key) { + self.expirations.reset(&entry.key, timeout); + true + } else { + false + } + } + + /// Removes a key from the map returning the value associated with the key that was in the map. + /// + /// Return None if the key was not in the map. + pub fn remove(&mut self, key: &K) -> Option { + if let Some(entry) = self.entries.remove(key) { + self.expirations.remove(&entry.key); + return Some(entry.value); + } + return None; + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all pairs `(k, v)` such that `f(&k,&mut v)` returns false. + pub fn retain bool>(&mut self, mut f: F) { + let expiration = &mut self.expirations; + self.entries.retain(|key, entry| { + let result = f(key, &mut entry.value); + if !result { + expiration.remove(&entry.key); + } + result + }) + } + + /// Removes all entries from the map. + pub fn clear(&mut self) { + self.entries.clear(); + self.expirations.clear(); + } +} + +impl Stream for HashMapDelay +where + K: std::cmp::Eq + std::hash::Hash + std::clone::Clone, +{ + type Item = (K, V); + type Error = &'static str; + + fn poll(&mut self) -> Poll, Self::Error> { + match self.expirations.poll() { + Ok(Async::Ready(Some(key))) => { + let key = key.into_inner(); + match self.entries.remove(&key) { + Some(entry) => Ok(Async::Ready(Some((key, entry.value)))), + None => Err("Value no longer exists in expirations"), + } + } + Ok(Async::Ready(None)) => Ok(Async::Ready(None)), + Ok(Async::NotReady) => Ok(Async::NotReady), + Err(_) => Err("Error polling HashMapDelay"), + } + } +} diff --git a/eth2/utils/hashmap_delay/src/hashset_delay.rs b/eth2/utils/hashmap_delay/src/hashset_delay.rs new file mode 100644 index 000000000..1ef0bdf65 --- /dev/null +++ b/eth2/utils/hashmap_delay/src/hashset_delay.rs @@ -0,0 +1,157 @@ +//NOTE: This is just a specific case of a HashMapDelay. +// The code has been copied to make unique `insert` and `insert_at` functions. + +/// The default delay for entries, in seconds. This is only used when `insert()` is used to add +/// entries. +const DEFAULT_DELAY: u64 = 30; + +use futures::prelude::*; +use std::collections::HashMap; +use std::time::{Duration, Instant}; +use tokio_timer::delay_queue::{self, DelayQueue}; + +pub struct HashSetDelay +where + K: std::cmp::Eq + std::hash::Hash + std::clone::Clone, +{ + /// The given entries. + entries: HashMap, + /// A queue holding the timeouts of each entry. + expirations: DelayQueue, + /// The default expiration timeout of an entry. + default_entry_timeout: Duration, +} + +/// A wrapping around entries that adds the link to the entry's expiration, via a `delay_queue` key. +struct MapEntry { + /// The expiration key for the entry. + key: delay_queue::Key, + /// The actual entry. + value: Instant, +} + +impl Default for HashSetDelay +where + K: std::cmp::Eq + std::hash::Hash + std::clone::Clone, +{ + fn default() -> Self { + HashSetDelay::new(Duration::from_secs(DEFAULT_DELAY)) + } +} + +impl HashSetDelay +where + K: std::cmp::Eq + std::hash::Hash + std::clone::Clone, +{ + /// Creates a new instance of `HashSetDelay`. + pub fn new(default_entry_timeout: Duration) -> Self { + HashSetDelay { + entries: HashMap::new(), + expirations: DelayQueue::new(), + default_entry_timeout, + } + } + + /// Insert an entry into the mapping. Entries will expire after the `default_entry_timeout`. + pub fn insert(&mut self, key: K) { + self.insert_at(key, self.default_entry_timeout); + } + + /// Inserts an entry that will expire at a given instant. + pub fn insert_at(&mut self, key: K, entry_duration: Duration) { + let delay_key = self.expirations.insert(key.clone(), entry_duration.clone()); + let entry = MapEntry { + key: delay_key, + value: Instant::now() + entry_duration, + }; + self.entries.insert(key, entry); + } + + /// Gets a reference to an entry if it exists. + /// + /// Returns None if the entry does not exist. + pub fn get(&self, key: &K) -> Option<&Instant> { + self.entries.get(key).map(|entry| &entry.value) + } + + /// Returns true if the key exists, false otherwise. + pub fn contains(&self, key: &K) -> bool { + self.entries.contains_key(key) + } + + /// Returns the length of the mapping. + pub fn len(&self) -> usize { + self.entries.len() + } + + /// Updates the timeout for a given key. Returns true if the key existed, false otherwise. + /// + /// Panics if the duration is too far in the future. + pub fn update_timeout(&mut self, key: &K, timeout: Duration) -> bool { + if let Some(entry) = self.entries.get(key) { + self.expirations.reset(&entry.key, timeout); + true + } else { + false + } + } + + /// Removes a key from the map returning the value associated with the key that was in the map. + /// + /// Return false if the key was not in the map. + pub fn remove(&mut self, key: &K) -> bool { + if let Some(entry) = self.entries.remove(key) { + self.expirations.remove(&entry.key); + return true; + } + return false; + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all pairs `(k, v)` such that `f(&k,&mut v)` returns false. + pub fn retain bool>(&mut self, mut f: F) { + let expiration = &mut self.expirations; + self.entries.retain(|key, entry| { + let result = f(key); + if !result { + expiration.remove(&entry.key); + } + result + }) + } + + /// Removes all entries from the map. + pub fn clear(&mut self) { + self.entries.clear(); + self.expirations.clear(); + } + + /// Returns a vector of referencing all keys in the map. + pub fn keys_vec(&self) -> Vec<&K> { + self.entries.keys().collect() + } +} + +impl Stream for HashSetDelay +where + K: std::cmp::Eq + std::hash::Hash + std::clone::Clone, +{ + type Item = K; + type Error = &'static str; + + fn poll(&mut self) -> Poll, Self::Error> { + match self.expirations.poll() { + Ok(Async::Ready(Some(key))) => { + let key = key.into_inner(); + match self.entries.remove(&key) { + Some(_) => Ok(Async::Ready(Some(key))), + None => Err("Value no longer exists in expirations"), + } + } + Ok(Async::Ready(None)) => Ok(Async::Ready(None)), + Ok(Async::NotReady) => Ok(Async::NotReady), + Err(_) => Err("Error polling HashSetDelay"), + } + } +} diff --git a/eth2/utils/hashmap_delay/src/lib.rs b/eth2/utils/hashmap_delay/src/lib.rs new file mode 100644 index 000000000..140106b42 --- /dev/null +++ b/eth2/utils/hashmap_delay/src/lib.rs @@ -0,0 +1,21 @@ +//! This crate provides two objects: +//! - `HashMapDelay` +//! - `HashSetDelay` +//! +//! # HashMapDelay +//! +//! This provides a `HashMap` coupled with a `DelayQueue`. Objects that are inserted into +//! the map are inserted with an expiry. `Stream` is implemented on the `HashMapDelay` +//! which return objects that have expired. These objects are removed from the mapping. +//! +//! # HashSetDelay +//! +//! This is similar to a `HashMapDelay` except the mapping maps to the expiry time. This +//! allows users to add objects and check their expiry deadlines before the `Stream` +//! consumes them. + +mod hashmap_delay; +mod hashset_delay; + +pub use crate::hashmap_delay::HashMapDelay; +pub use crate::hashset_delay::HashSetDelay; diff --git a/eth2/utils/int_to_bytes/Cargo.toml b/eth2/utils/int_to_bytes/Cargo.toml index 48c52548b..c24f657c6 100644 --- a/eth2/utils/int_to_bytes/Cargo.toml +++ b/eth2/utils/int_to_bytes/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "int_to_bytes" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/eth2/utils/lighthouse_bootstrap/Cargo.toml b/eth2/utils/lighthouse_bootstrap/Cargo.toml index 0e1bbc744..460d12d85 100644 --- a/eth2/utils/lighthouse_bootstrap/Cargo.toml +++ b/eth2/utils/lighthouse_bootstrap/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lighthouse_bootstrap" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/eth2/utils/lighthouse_metrics/Cargo.toml b/eth2/utils/lighthouse_metrics/Cargo.toml index 3b01c63e4..ed4b49253 100644 --- a/eth2/utils/lighthouse_metrics/Cargo.toml +++ b/eth2/utils/lighthouse_metrics/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lighthouse_metrics" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/eth2/utils/logging/Cargo.toml b/eth2/utils/logging/Cargo.toml index 0fe056663..c7ccd3617 100644 --- a/eth2/utils/logging/Cargo.toml +++ b/eth2/utils/logging/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "logging" -version = "0.1.0" +version = "0.2.0" authors = ["blacktemplar "] edition = "2018" diff --git a/eth2/utils/merkle_proof/Cargo.toml b/eth2/utils/merkle_proof/Cargo.toml index a342b5bea..2692fced3 100644 --- a/eth2/utils/merkle_proof/Cargo.toml +++ b/eth2/utils/merkle_proof/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "merkle_proof" -version = "0.1.0" +version = "0.2.0" authors = ["Michael Sproul "] edition = "2018" diff --git a/eth2/utils/remote_beacon_node/Cargo.toml b/eth2/utils/remote_beacon_node/Cargo.toml index ad1b8d469..cb4323578 100644 --- a/eth2/utils/remote_beacon_node/Cargo.toml +++ b/eth2/utils/remote_beacon_node/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "remote_beacon_node" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" @@ -12,7 +12,7 @@ url = "1.2" serde = "1.0" futures = "0.1.25" types = { path = "../../../eth2/types" } -rest_api = { path = "../../../beacon_node/rest_api" } +rest_types = { path = "../rest_types" } hex = "0.3" eth2_ssz = { path = "../../../eth2/utils/ssz" } serde_json = "^1.0" diff --git a/eth2/utils/remote_beacon_node/src/lib.rs b/eth2/utils/remote_beacon_node/src/lib.rs index 64791e8ad..25baf9906 100644 --- a/eth2/utils/remote_beacon_node/src/lib.rs +++ b/eth2/utils/remote_beacon_node/src/lib.rs @@ -15,15 +15,16 @@ use std::marker::PhantomData; use std::time::Duration; use types::{ Attestation, AttesterSlashing, BeaconBlock, BeaconState, CommitteeIndex, Epoch, EthSpec, Fork, - Hash256, ProposerSlashing, PublicKey, Signature, SignedBeaconBlock, Slot, + Hash256, ProposerSlashing, PublicKey, Signature, SignedAggregateAndProof, SignedBeaconBlock, + Slot, }; use url::Url; pub use operation_pool::PersistedOperationPool; pub use proto_array_fork_choice::core::ProtoArray; -pub use rest_api::{ - CanonicalHeadResponse, Committee, HeadBeaconBlock, ValidatorDutiesRequest, ValidatorDuty, - ValidatorRequest, ValidatorResponse, +pub use rest_types::{ + CanonicalHeadResponse, Committee, HeadBeaconBlock, ValidatorDutiesRequest, ValidatorDutyBytes, + ValidatorRequest, ValidatorResponse, ValidatorSubscription, }; // Setting a long timeout for debug ensures that crypto-heavy operations can still succeed. @@ -63,6 +64,8 @@ pub enum Error { SerdeJsonError(serde_json::Error), /// The server responded to the request, however it did not return a 200-type success code. DidNotSucceed { status: StatusCode, body: String }, + /// The request input was invalid. + InvalidInput, } #[derive(Clone)] @@ -166,7 +169,7 @@ pub enum PublishStatus { Valid, /// The object was not valid and may or may not have been published to the network. Invalid(String), - /// The server responsed with an unknown status code. The object may or may not have been + /// The server responded with an unknown status code. The object may or may not have been /// published to the network. Unknown, } @@ -178,7 +181,7 @@ impl PublishStatus { } } -/// Provides the functions on the `/beacon` endpoint of the node. +/// Provides the functions on the `/validator` endpoint of the node. #[derive(Clone)] pub struct Validator(HttpClient); @@ -207,13 +210,30 @@ impl Validator { .and_then(move |url| client.json_get(url, query_params)) } - /// Posts an attestation to the beacon node, expecting it to verify it and publish it to the network. - pub fn publish_attestation( + /// Produces an aggregate attestation. + pub fn produce_aggregate_attestation( &self, - attestation: Attestation, + slot: Slot, + committee_index: CommitteeIndex, + ) -> impl Future, Error = Error> { + let query_params = vec![ + ("slot".into(), format!("{}", slot)), + ("committee_index".into(), format!("{}", committee_index)), + ]; + + let client = self.0.clone(); + self.url("aggregate_attestation") + .into_future() + .and_then(move |url| client.json_get(url, query_params)) + } + + /// Posts a list of attestations to the beacon node, expecting it to verify it and publish it to the network. + pub fn publish_attestations( + &self, + attestation: Vec>, ) -> impl Future { let client = self.0.clone(); - self.url("attestation") + self.url("attestations") .into_future() .and_then(move |url| client.json_post::<_>(url, attestation)) .and_then(|mut response| { @@ -232,12 +252,37 @@ impl Validator { }) } + /// Posts a list of signed aggregates and proofs to the beacon node, expecting it to verify it and publish it to the network. + pub fn publish_aggregate_and_proof( + &self, + signed_aggregate_and_proofs: Vec>, + ) -> impl Future { + let client = self.0.clone(); + self.url("aggregate_and_proofs") + .into_future() + .and_then(move |url| client.json_post::<_>(url, signed_aggregate_and_proofs)) + .and_then(|mut response| { + response + .text() + .map(|text| (response, text)) + .map_err(Error::from) + }) + .and_then(|(response, text)| match response.status() { + StatusCode::OK => Ok(PublishStatus::Valid), + StatusCode::ACCEPTED => Ok(PublishStatus::Invalid(text)), + _ => response + .error_for_status() + .map_err(Error::from) + .map(|_| PublishStatus::Unknown), + }) + } + /// Returns the duties required of the given validator pubkeys in the given epoch. pub fn get_duties( &self, epoch: Epoch, validator_pubkeys: &[PublicKey], - ) -> impl Future, Error = Error> { + ) -> impl Future, Error = Error> { let client = self.0.clone(); let bulk_request = ValidatorDutiesRequest { @@ -297,6 +342,31 @@ impl Validator { ) }) } + + /// Subscribes a list of validators to particular slots for attestation production/publication. + pub fn subscribe( + &self, + subscriptions: Vec, + ) -> impl Future { + let client = self.0.clone(); + self.url("subscribe") + .into_future() + .and_then(move |url| client.json_post::<_>(url, subscriptions)) + .and_then(|mut response| { + response + .text() + .map(|text| (response, text)) + .map_err(Error::from) + }) + .and_then(|(response, text)| match response.status() { + StatusCode::OK => Ok(PublishStatus::Valid), + StatusCode::ACCEPTED => Ok(PublishStatus::Invalid(text)), + _ => response + .error_for_status() + .map_err(Error::from) + .map(|_| PublishStatus::Unknown), + }) + } } /// Provides the functions on the `/beacon` endpoint of the node. diff --git a/eth2/utils/rest_types/Cargo.toml b/eth2/utils/rest_types/Cargo.toml new file mode 100644 index 000000000..4613d0a04 --- /dev/null +++ b/eth2/utils/rest_types/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rest_types" +version = "0.2.0" +authors = ["Age Manning "] +edition = "2018" + +[dependencies] +types = { path = "../../types" } +eth2_ssz_derive = { path = "../ssz_derive" } +eth2_ssz = { path = "../ssz" } +eth2_hashing = { path = "../eth2_hashing" } +tree_hash = { path = "../tree_hash" } +bls = { path = "../bls" } +serde = { version = "1.0.102", features = ["derive"] } +rayon = "1.3.0" diff --git a/eth2/utils/rest_types/src/beacon.rs b/eth2/utils/rest_types/src/beacon.rs new file mode 100644 index 000000000..0a141ea28 --- /dev/null +++ b/eth2/utils/rest_types/src/beacon.rs @@ -0,0 +1,65 @@ +//! A collection of REST API types for interaction with the beacon node. + +use bls::PublicKeyBytes; +use serde::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use types::beacon_state::EthSpec; +use types::{BeaconState, CommitteeIndex, Hash256, SignedBeaconBlock, Slot, Validator}; + +/// Information about a block that is at the head of a chain. May or may not represent the +/// canonical head. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] +pub struct HeadBeaconBlock { + pub beacon_block_root: Hash256, + pub beacon_block_slot: Slot, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] +#[serde(bound = "T: EthSpec")] +pub struct BlockResponse { + pub root: Hash256, + pub beacon_block: SignedBeaconBlock, +} + +/// Information about the block and state that are at head of the beacon chain. +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] +pub struct CanonicalHeadResponse { + pub slot: Slot, + pub block_root: Hash256, + pub state_root: Hash256, + pub finalized_slot: Slot, + pub finalized_block_root: Hash256, + pub justified_slot: Slot, + pub justified_block_root: Hash256, + pub previous_justified_slot: Slot, + pub previous_justified_block_root: Hash256, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] +pub struct ValidatorResponse { + pub pubkey: PublicKeyBytes, + pub validator_index: Option, + pub balance: Option, + pub validator: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] +pub struct ValidatorRequest { + /// If set to `None`, uses the canonical head state. + pub state_root: Option, + pub pubkeys: Vec, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] +pub struct Committee { + pub slot: Slot, + pub index: CommitteeIndex, + pub committee: Vec, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Encode, Decode)] +#[serde(bound = "T: EthSpec")] +pub struct StateResponse { + pub root: Hash256, + pub beacon_state: BeaconState, +} diff --git a/eth2/utils/rest_types/src/lib.rs b/eth2/utils/rest_types/src/lib.rs new file mode 100644 index 000000000..5fab2c1dc --- /dev/null +++ b/eth2/utils/rest_types/src/lib.rs @@ -0,0 +1,15 @@ +//! A collection of types used to pass data across the rest HTTP API. +//! +//! This is primarily used by the validator client and the beacon node rest API. + +mod beacon; +mod validator; + +pub use beacon::{ + BlockResponse, CanonicalHeadResponse, Committee, HeadBeaconBlock, StateResponse, + ValidatorRequest, ValidatorResponse, +}; + +pub use validator::{ + ValidatorDutiesRequest, ValidatorDuty, ValidatorDutyBytes, ValidatorSubscription, +}; diff --git a/eth2/utils/rest_types/src/validator.rs b/eth2/utils/rest_types/src/validator.rs new file mode 100644 index 000000000..0666ffd87 --- /dev/null +++ b/eth2/utils/rest_types/src/validator.rs @@ -0,0 +1,108 @@ +use bls::{PublicKey, PublicKeyBytes, Signature}; +use eth2_hashing::hash; +use serde::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use std::convert::TryInto; +use types::{ChainSpec, CommitteeIndex, Domain, Epoch, Fork, SignedRoot, Slot}; + +/// A Validator duty with the validator public key represented a `PublicKeyBytes`. +pub type ValidatorDutyBytes = ValidatorDutyBase; +/// A validator duty with the pubkey represented as a `PublicKey`. +pub type ValidatorDuty = ValidatorDutyBase; + +#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)] +pub struct ValidatorDutyBase { + /// The validator's BLS public key, uniquely identifying them. _48-bytes, hex encoded with 0x prefix, case insensitive._ + pub validator_pubkey: T, + /// The validator's index in `state.validators` + pub validator_index: Option, + /// The slot at which the validator must attest. + pub attestation_slot: Option, + /// The index of the committee within `slot` of which the validator is a member. + pub attestation_committee_index: Option, + /// The position of the validator in the committee. + pub attestation_committee_position: Option, + /// The slots in which a validator must propose a block (can be empty). + pub block_proposal_slots: Vec, + /// This provides the modulo: `max(1, len(committee) // TARGET_AGGREGATORS_PER_COMMITTEE)` + /// which allows the validator client to determine if this duty requires the validator to be + /// aggregate attestations. + pub aggregator_modulo: Option, +} + +impl ValidatorDutyBase { + /// Given a `slot_signature` determines if the validator of this duty is an aggregator. + // Note that we assume the signature is for the associated pubkey to avoid the signature + // verification + pub fn is_aggregator(&self, slot_signature: &Signature) -> bool { + if let Some(modulo) = self.aggregator_modulo { + let signature_hash = hash(&slot_signature.as_bytes()); + let signature_hash_int = u64::from_le_bytes( + signature_hash[0..8] + .try_into() + .expect("first 8 bytes of signature should always convert to fixed array"), + ); + signature_hash_int % modulo == 0 + } else { + false + } + } +} + +#[derive(PartialEq, Debug, Serialize, Deserialize, Clone, Encode, Decode)] +pub struct ValidatorDutiesRequest { + pub epoch: Epoch, + pub pubkeys: Vec, +} + +/// A validator subscription, created when a validator subscribes to a slot to perform optional aggregation +/// duties. +#[derive(PartialEq, Debug, Serialize, Deserialize, Clone, Encode, Decode)] +pub struct ValidatorSubscription { + /// The validators index. + pub validator_index: u64, + /// The index of the committee within `slot` of which the validator is a member. Used by the + /// beacon node to quickly evaluate the associated `SubnetId`. + pub attestation_committee_index: CommitteeIndex, + /// The slot the validator is signing. + pub slot: Slot, + /// The signature of the slot by the validator. + pub slot_signature: Signature, +} + +impl ValidatorSubscription { + pub fn new( + validator_index: u64, + attestation_committee_index: CommitteeIndex, + slot: Slot, + slot_signature: Signature, + ) -> Self { + ValidatorSubscription { + validator_index, + attestation_committee_index, + slot, + slot_signature, + } + } + + /// Verifies the subscription signature. + pub fn verify( + &self, + pubkey: &PublicKey, + spec: &ChainSpec, + fork: &Fork, + slots_per_epoch: u64, + ) -> bool { + let domain = spec.get_domain( + self.slot.epoch(slots_per_epoch), + Domain::SelectionProof, + &fork, + ); + let message = self.slot.signing_root(domain); + if self.slot_signature.verify(message.as_bytes(), pubkey) { + true + } else { + false + } + } +} diff --git a/eth2/utils/serde_hex/Cargo.toml b/eth2/utils/serde_hex/Cargo.toml index 06102f24e..b4d7bf619 100644 --- a/eth2/utils/serde_hex/Cargo.toml +++ b/eth2/utils/serde_hex/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "serde_hex" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/eth2/utils/slot_clock/Cargo.toml b/eth2/utils/slot_clock/Cargo.toml index e27395e42..81a7b57a9 100644 --- a/eth2/utils/slot_clock/Cargo.toml +++ b/eth2/utils/slot_clock/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "slot_clock" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" @@ -8,3 +8,4 @@ edition = "2018" types = { path = "../../types" } lazy_static = "1.4.0" lighthouse_metrics = { path = "../lighthouse_metrics" } +parking_lot = "0.9.0" diff --git a/eth2/utils/slot_clock/src/lib.rs b/eth2/utils/slot_clock/src/lib.rs index b85b5a72c..0990ec141 100644 --- a/eth2/utils/slot_clock/src/lib.rs +++ b/eth2/utils/slot_clock/src/lib.rs @@ -1,14 +1,15 @@ #[macro_use] extern crate lazy_static; +mod manual_slot_clock; mod metrics; mod system_time_slot_clock; -mod testing_slot_clock; use std::time::Duration; +pub use crate::manual_slot_clock::ManualSlotClock; +pub use crate::manual_slot_clock::ManualSlotClock as TestingSlotClock; pub use crate::system_time_slot_clock::SystemTimeSlotClock; -pub use crate::testing_slot_clock::TestingSlotClock; pub use metrics::scrape_for_metrics; pub use types::Slot; @@ -16,13 +17,21 @@ pub use types::Slot; /// /// The clock is not required to be monotonically increasing and may go backwards. pub trait SlotClock: Send + Sync + Sized { - /// Creates a new slot clock where the first slot is `genesis_slot`, genesis occured + /// Creates a new slot clock where the first slot is `genesis_slot`, genesis occurred /// `genesis_duration` after the `UNIX_EPOCH` and each slot is `slot_duration` apart. fn new(genesis_slot: Slot, genesis_duration: Duration, slot_duration: Duration) -> Self; /// Returns the slot at this present time. fn now(&self) -> Option; + /// Returns the present time as a duration since the UNIX epoch. + /// + /// Returns `None` if the present time is before the UNIX epoch (unlikely). + fn now_duration(&self) -> Option; + + /// Returns the slot of the given duration since the UNIX epoch. + fn slot_of(&self, now: Duration) -> Option; + /// Returns the duration between slots fn slot_duration(&self) -> Duration; diff --git a/eth2/utils/slot_clock/src/manual_slot_clock.rs b/eth2/utils/slot_clock/src/manual_slot_clock.rs new file mode 100644 index 000000000..69109f49b --- /dev/null +++ b/eth2/utils/slot_clock/src/manual_slot_clock.rs @@ -0,0 +1,165 @@ +use super::SlotClock; +use parking_lot::RwLock; +use std::convert::TryInto; +use std::time::Duration; +use types::Slot; + +/// Determines the present slot based upon a manually-incremented UNIX timestamp. +pub struct ManualSlotClock { + genesis_slot: Slot, + /// Duration from UNIX epoch to genesis. + genesis_duration: Duration, + /// Duration from UNIX epoch to right now. + current_time: RwLock, + /// The length of each slot. + slot_duration: Duration, +} + +impl Clone for ManualSlotClock { + fn clone(&self) -> Self { + ManualSlotClock { + genesis_slot: self.genesis_slot.clone(), + genesis_duration: self.genesis_duration.clone(), + current_time: RwLock::new(self.current_time.read().clone()), + slot_duration: self.slot_duration.clone(), + } + } +} + +impl ManualSlotClock { + pub fn set_slot(&self, slot: u64) { + let slots_since_genesis = slot + .checked_sub(self.genesis_slot.as_u64()) + .expect("slot must be post-genesis") + .try_into() + .expect("slot must fit within a u32"); + *self.current_time.write() = + self.genesis_duration + self.slot_duration * slots_since_genesis; + } + + pub fn advance_slot(&self) { + self.set_slot(self.now().unwrap().as_u64() + 1) + } + + pub fn duration_to_next_slot_from(&self, now: Duration) -> Option { + let genesis = self.genesis_duration; + + let slot_start = |slot: Slot| -> Duration { + let slot = slot.as_u64() as u32; + genesis + slot * self.slot_duration + }; + + if now >= genesis { + Some( + slot_start(self.slot_of(now)? + 1) + .checked_sub(now) + .expect("The next slot cannot start before now"), + ) + } else { + Some( + genesis + .checked_sub(now) + .expect("Control flow ensures genesis is greater than or equal to now"), + ) + } + } + + pub fn duration_to_next_epoch_from( + &self, + now: Duration, + slots_per_epoch: u64, + ) -> Option { + let genesis = self.genesis_duration; + + let slot_start = |slot: Slot| -> Duration { + let slot = slot.as_u64() as u32; + genesis + slot * self.slot_duration + }; + + let epoch_start_slot = self + .now() + .map(|slot| slot.epoch(slots_per_epoch)) + .map(|epoch| (epoch + 1).start_slot(slots_per_epoch))?; + + if now >= genesis { + Some( + slot_start(epoch_start_slot) + .checked_sub(now) + .expect("The next epoch cannot start before now"), + ) + } else { + Some( + genesis + .checked_sub(now) + .expect("Control flow ensures genesis is greater than or equal to now"), + ) + } + } +} + +impl SlotClock for ManualSlotClock { + fn new(genesis_slot: Slot, genesis_duration: Duration, slot_duration: Duration) -> Self { + if slot_duration.as_millis() == 0 { + panic!("ManualSlotClock cannot have a < 1ms slot duration"); + } + + Self { + genesis_slot, + current_time: RwLock::new(genesis_duration.clone()), + genesis_duration, + slot_duration, + } + } + + fn now(&self) -> Option { + self.slot_of(*self.current_time.read()) + } + + fn now_duration(&self) -> Option { + Some(*self.current_time.read()) + } + + fn slot_of(&self, now: Duration) -> Option { + let genesis = self.genesis_duration; + + if now >= genesis { + let since_genesis = now + .checked_sub(genesis) + .expect("Control flow ensures now is greater than or equal to genesis"); + let slot = + Slot::from((since_genesis.as_millis() / self.slot_duration.as_millis()) as u64); + Some(slot + self.genesis_slot) + } else { + None + } + } + + fn duration_to_next_slot(&self) -> Option { + self.duration_to_next_slot_from(*self.current_time.read()) + } + + fn duration_to_next_epoch(&self, slots_per_epoch: u64) -> Option { + self.duration_to_next_epoch_from(*self.current_time.read(), slots_per_epoch) + } + + fn slot_duration(&self) -> Duration { + self.slot_duration + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_slot_now() { + let clock = ManualSlotClock::new( + Slot::new(10), + Duration::from_secs(0), + Duration::from_secs(1), + ); + assert_eq!(clock.now(), Some(Slot::new(10))); + clock.set_slot(123); + assert_eq!(clock.now(), Some(Slot::new(123))); + } +} diff --git a/eth2/utils/slot_clock/src/system_time_slot_clock.rs b/eth2/utils/slot_clock/src/system_time_slot_clock.rs index 5e4151528..a66b11265 100644 --- a/eth2/utils/slot_clock/src/system_time_slot_clock.rs +++ b/eth2/utils/slot_clock/src/system_time_slot_clock.rs @@ -1,4 +1,4 @@ -use super::SlotClock; +use super::{ManualSlotClock, SlotClock}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use types::Slot; @@ -7,95 +7,41 @@ pub use std::time::SystemTimeError; /// Determines the present slot based upon the present system time. #[derive(Clone)] pub struct SystemTimeSlotClock { - genesis_slot: Slot, - genesis_duration: Duration, - slot_duration: Duration, + clock: ManualSlotClock, } impl SlotClock for SystemTimeSlotClock { fn new(genesis_slot: Slot, genesis_duration: Duration, slot_duration: Duration) -> Self { - if slot_duration.as_millis() == 0 { - panic!("SystemTimeSlotClock cannot have a < 1ms slot duration."); - } - Self { - genesis_slot, - genesis_duration, - slot_duration, + clock: ManualSlotClock::new(genesis_slot, genesis_duration, slot_duration), } } fn now(&self) -> Option { let now = SystemTime::now().duration_since(UNIX_EPOCH).ok()?; - let genesis = self.genesis_duration; + self.clock.slot_of(now) + } - if now >= genesis { - let since_genesis = now - .checked_sub(genesis) - .expect("Control flow ensures now is greater than or equal to genesis"); - let slot = - Slot::from((since_genesis.as_millis() / self.slot_duration.as_millis()) as u64); - Some(slot + self.genesis_slot) - } else { - None - } + fn now_duration(&self) -> Option { + SystemTime::now().duration_since(UNIX_EPOCH).ok() + } + + fn slot_of(&self, now: Duration) -> Option { + self.clock.slot_of(now) } fn duration_to_next_slot(&self) -> Option { let now = SystemTime::now().duration_since(UNIX_EPOCH).ok()?; - let genesis = self.genesis_duration; - - let slot_start = |slot: Slot| -> Duration { - let slot = slot.as_u64() as u32; - genesis + slot * self.slot_duration - }; - - if now >= genesis { - Some( - slot_start(self.now()? + 1) - .checked_sub(now) - .expect("The next slot cannot start before now"), - ) - } else { - Some( - genesis - .checked_sub(now) - .expect("Control flow ensures genesis is greater than or equal to now"), - ) - } + self.clock.duration_to_next_slot_from(now) } fn duration_to_next_epoch(&self, slots_per_epoch: u64) -> Option { let now = SystemTime::now().duration_since(UNIX_EPOCH).ok()?; - let genesis = self.genesis_duration; - - let slot_start = |slot: Slot| -> Duration { - let slot = slot.as_u64() as u32; - genesis + slot * self.slot_duration - }; - - let epoch_start_slot = self - .now() - .map(|slot| slot.epoch(slots_per_epoch)) - .map(|epoch| (epoch + 1).start_slot(slots_per_epoch))?; - - if now >= genesis { - Some( - slot_start(epoch_start_slot) - .checked_sub(now) - .expect("The next epoch cannot start before now"), - ) - } else { - Some( - genesis - .checked_sub(now) - .expect("Control flow ensures genesis is greater than or equal to now"), - ) - } + self.clock.duration_to_next_epoch_from(now, slots_per_epoch) } fn slot_duration(&self) -> Duration { - self.slot_duration + self.clock.slot_duration() } } diff --git a/eth2/utils/slot_clock/src/testing_slot_clock.rs b/eth2/utils/slot_clock/src/testing_slot_clock.rs deleted file mode 100644 index 7eaee4a1b..000000000 --- a/eth2/utils/slot_clock/src/testing_slot_clock.rs +++ /dev/null @@ -1,64 +0,0 @@ -use super::SlotClock; -use std::sync::RwLock; -use std::time::Duration; -use types::Slot; - -/// A slot clock where the slot is manually set instead of being determined by the system time. -/// -/// Useful for testing scenarios. -pub struct TestingSlotClock { - slot: RwLock, -} - -impl TestingSlotClock { - pub fn set_slot(&self, slot: u64) { - *self.slot.write().expect("TestingSlotClock poisoned.") = Slot::from(slot); - } - - pub fn advance_slot(&self) { - self.set_slot(self.now().unwrap().as_u64() + 1) - } -} - -impl SlotClock for TestingSlotClock { - fn new(genesis_slot: Slot, _genesis_duration: Duration, _slot_duration: Duration) -> Self { - TestingSlotClock { - slot: RwLock::new(genesis_slot), - } - } - - fn now(&self) -> Option { - let slot = *self.slot.read().expect("TestingSlotClock poisoned."); - Some(slot) - } - - /// Always returns a duration of 1 second. - fn duration_to_next_slot(&self) -> Option { - Some(Duration::from_secs(1)) - } - - /// Always returns a duration of `1 * slots_per_epoch` second. - fn duration_to_next_epoch(&self, slots_per_epoch: u64) -> Option { - Some(Duration::from_secs(slots_per_epoch)) - } - - /// Always returns a slot duration of 0 seconds. - fn slot_duration(&self) -> Duration { - Duration::from_secs(0) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_slot_now() { - let null = Duration::from_secs(0); - - let clock = TestingSlotClock::new(Slot::new(10), null, null); - assert_eq!(clock.now(), Some(Slot::new(10))); - clock.set_slot(123); - assert_eq!(clock.now(), Some(Slot::new(123))); - } -} diff --git a/eth2/utils/ssz_types/src/bitfield.rs b/eth2/utils/ssz_types/src/bitfield.rs index 974cdb228..4192a8a4f 100644 --- a/eth2/utils/ssz_types/src/bitfield.rs +++ b/eth2/utils/ssz_types/src/bitfield.rs @@ -302,7 +302,7 @@ impl Bitfield { /// Returns the value of the `i`'th bit. /// - /// Returns `None` if `i` is out-of-bounds of `self`. + /// Returns `Error` if `i` is out-of-bounds of `self`. pub fn get(&self, i: usize) -> Result { if i < self.len { let byte = self diff --git a/eth2/utils/swap_or_not_shuffle/Cargo.toml b/eth2/utils/swap_or_not_shuffle/Cargo.toml index a106ff87e..ef86d2569 100644 --- a/eth2/utils/swap_or_not_shuffle/Cargo.toml +++ b/eth2/utils/swap_or_not_shuffle/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swap_or_not_shuffle" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/eth2/utils/test_random_derive/Cargo.toml b/eth2/utils/test_random_derive/Cargo.toml index 4559befaf..494e9d8eb 100644 --- a/eth2/utils/test_random_derive/Cargo.toml +++ b/eth2/utils/test_random_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "test_random_derive" -version = "0.1.0" +version = "0.2.0" authors = ["thojest "] edition = "2018" description = "Procedural derive macros for implementation of TestRandom trait" diff --git a/lcli/Cargo.toml b/lcli/Cargo.toml index a3ec8909b..f67efc783 100644 --- a/lcli/Cargo.toml +++ b/lcli/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "lcli" description = "Lighthouse CLI (modeled after zcli)" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/lighthouse/Cargo.toml b/lighthouse/Cargo.toml index 134f6719f..f22f79097 100644 --- a/lighthouse/Cargo.toml +++ b/lighthouse/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lighthouse" -version = "0.1.1" +version = "0.2.0" authors = ["Sigma Prime "] edition = "2018" diff --git a/lighthouse/environment/Cargo.toml b/lighthouse/environment/Cargo.toml index 6e693d12a..f28812eaa 100644 --- a/lighthouse/environment/Cargo.toml +++ b/lighthouse/environment/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "environment" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/tests/ef_tests/Cargo.toml b/tests/ef_tests/Cargo.toml index e893ea8e2..77aabac04 100644 --- a/tests/ef_tests/Cargo.toml +++ b/tests/ef_tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ef_tests" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/tests/eth1_test_rig/Cargo.toml b/tests/eth1_test_rig/Cargo.toml index 8038fd51d..a949a9d8b 100644 --- a/tests/eth1_test_rig/Cargo.toml +++ b/tests/eth1_test_rig/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "eth1_test_rig" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/tests/node_test_rig/Cargo.toml b/tests/node_test_rig/Cargo.toml index c8e1ebcc6..013cbe027 100644 --- a/tests/node_test_rig/Cargo.toml +++ b/tests/node_test_rig/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "node_test_rig" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/tests/simulator/Cargo.toml b/tests/simulator/Cargo.toml index 189c24f63..65b661470 100644 --- a/tests/simulator/Cargo.toml +++ b/tests/simulator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "simulator" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner "] edition = "2018" diff --git a/validator_client/Cargo.toml b/validator_client/Cargo.toml index b38bfff39..34e2d3e79 100644 --- a/validator_client/Cargo.toml +++ b/validator_client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "validator_client" -version = "0.1.0" +version = "0.2.0" authors = ["Paul Hauner ", "Age Manning ", "Luke Anderson "] edition = "2018" @@ -16,6 +16,7 @@ clap = "2.33.0" lighthouse_bootstrap = { path = "../eth2/utils/lighthouse_bootstrap" } eth2_interop_keypairs = { path = "../eth2/utils/eth2_interop_keypairs" } slot_clock = { path = "../eth2/utils/slot_clock" } +rest_types = { path = "../eth2/utils/rest_types" } types = { path = "../eth2/types" } serde = "1.0.102" serde_derive = "1.0.102" diff --git a/validator_client/src/attestation_service.rs b/validator_client/src/attestation_service.rs index cf3507cd7..0f63a2a03 100644 --- a/validator_client/src/attestation_service.rs +++ b/validator_client/src/attestation_service.rs @@ -1,19 +1,20 @@ use crate::{ - duties_service::{DutiesService, ValidatorDuty}, + duties_service::{DutiesService, DutyAndState}, validator_store::ValidatorStore, }; use environment::RuntimeContext; use exit_future::Signal; use futures::{Future, Stream}; use remote_beacon_node::{PublishStatus, RemoteBeaconNode}; +use rest_types::{ValidatorDuty, ValidatorSubscription}; use slog::{crit, info, trace}; use slot_clock::SlotClock; use std::collections::HashMap; use std::ops::Deref; use std::sync::Arc; use std::time::{Duration, Instant}; -use tokio::timer::Interval; -use types::{ChainSpec, CommitteeIndex, EthSpec, Slot}; +use tokio::timer::{Delay, Interval}; +use types::{AggregateAndProof, ChainSpec, CommitteeIndex, EthSpec, Slot}; /// Builds an `AttestationService`. pub struct AttestationServiceBuilder { @@ -123,13 +124,13 @@ impl AttestationService { let context = &self.context; let log = context.log.clone(); + let slot_duration = Duration::from_millis(spec.milliseconds_per_slot); let duration_to_next_slot = self .slot_clock .duration_to_next_slot() .ok_or_else(|| "Unable to determine duration to next slot".to_string())?; let interval = { - let slot_duration = Duration::from_millis(spec.milliseconds_per_slot); Interval::new( Instant::now() + duration_to_next_slot + slot_duration / 3, slot_duration, @@ -154,7 +155,7 @@ impl AttestationService { } }) .for_each(move |_| { - if let Err(e) = service.spawn_attestation_tasks() { + if let Err(e) = service.spawn_attestation_tasks(slot_duration) { crit!( log_2, "Failed to spawn attestation tasks"; @@ -178,30 +179,73 @@ impl AttestationService { /// For each each required attestation, spawn a new task that downloads, signs and uploads the /// attestation to the beacon node. - fn spawn_attestation_tasks(&self) -> Result<(), String> { + fn spawn_attestation_tasks(&self, slot_duration: Duration) -> Result<(), String> { let service = self.clone(); let slot = service .slot_clock .now() .ok_or_else(|| "Failed to read slot clock".to_string())?; + let duration_to_next_slot = service + .slot_clock + .duration_to_next_slot() + .ok_or_else(|| "Unable to determine duration to next slot".to_string())?; + // If a validator needs to publish an aggregate attestation, they must do so at 2/3 + // through the slot. This delay triggers at this time + let aggregator_delay_instant = { + if duration_to_next_slot <= slot_duration / 3 { + Instant::now() + } else { + Instant::now() + duration_to_next_slot - (slot_duration / 3) + } + }; + + let epoch = slot.epoch(E::slots_per_epoch()); + // Check if any attestation subscriptions are required. If there a new attestation duties for + // this epoch or the next, send them to the beacon node + let mut duties_to_subscribe = service.duties_service.unsubscribed_epoch_duties(&epoch); + duties_to_subscribe.append( + &mut service + .duties_service + .unsubscribed_epoch_duties(&(epoch + 1)), + ); + + // spawn a task to subscribe all the duties + service + .context + .executor + .spawn(self.clone().send_subscriptions(duties_to_subscribe)); + + // Builds a map of committee index and spawn individual tasks to process raw attestations + // and aggregated attestations let mut committee_indices: HashMap> = HashMap::new(); + let mut aggregator_committee_indices: HashMap> = + HashMap::new(); service .duties_service .attesters(slot) .into_iter() - .for_each(|duty| { - if let Some(committee_index) = duty.attestation_committee_index { + .for_each(|duty_and_state| { + if let Some(committee_index) = duty_and_state.duty.attestation_committee_index { let validator_duties = committee_indices .entry(committee_index) .or_insert_with(|| vec![]); + validator_duties.push(duty_and_state.duty.clone()); - validator_duties.push(duty); + // If this duty entails the validator aggregating attestations, perform + // aggregation tasks + if duty_and_state.is_aggregator() { + let validator_duties = aggregator_committee_indices + .entry(committee_index) + .or_insert_with(|| vec![]); + validator_duties.push(duty_and_state); + } } }); + // spawns tasks for all required raw attestations production committee_indices .into_iter() .for_each(|(committee_index, validator_duties)| { @@ -213,11 +257,112 @@ impl AttestationService { )); }); + // spawns tasks for all aggregate attestation production + aggregator_committee_indices + .into_iter() + .for_each(|(committee_index, validator_duties)| { + // Spawn a separate task for each aggregate attestation. + service + .context + .executor + .spawn(self.clone().do_aggregate_attestation( + slot, + committee_index, + validator_duties, + Delay::new(aggregator_delay_instant.clone()), + )); + }); Ok(()) } - /// For a given `committee_index`, download the attestation, have it signed by all validators - /// in `validator_duties` then upload it. + /// Subscribes any required validators to the beacon node for a particular slot. + /// + /// This informs the beacon node that the validator has a duty on a particular + /// slot allowing the beacon node to connect to the required subnet and determine + /// if attestations need to be aggregated. + fn send_subscriptions(&self, duties: Vec) -> impl Future { + let mut validator_subscriptions = Vec::new(); + let mut successful_duties = Vec::new(); + + let service_1 = self.clone(); + let duties_no = duties.len(); + + let log_1 = self.context.log.clone(); + let log_2 = self.context.log.clone(); + + // builds a list of subscriptions + for duty in duties { + if let Some((slot, attestation_committee_index, _, validator_index)) = + attestation_duties(&duty) + { + if let Some(slot_signature) = + self.validator_store.sign_slot(&duty.validator_pubkey, slot) + { + let is_aggregator_proof = if duty.is_aggregator(&slot_signature) { + Some(slot_signature.clone()) + } else { + None + }; + + let subscription = ValidatorSubscription::new( + validator_index, + attestation_committee_index, + slot, + slot_signature, + ); + validator_subscriptions.push(subscription); + + // add successful duties to the list, along with whether they are aggregation + // duties or not + successful_duties.push((duty, is_aggregator_proof)); + } + } else { + crit!(log_2, "Validator duty doesn't have required fields"); + } + } + + let failed_duties = duties_no - successful_duties.len(); + + self.beacon_node + .http + .validator() + .subscribe(validator_subscriptions) + .map_err(|e| format!("Failed to subscribe validators: {:?}", e)) + .map(move |publish_status| match publish_status { + PublishStatus::Valid => info!( + log_1, + "Successfully subscribed validators"; + "validators" => duties_no, + "failed_validators" => failed_duties, + ), + PublishStatus::Invalid(msg) => crit!( + log_1, + "Validator Subscription was invalid"; + "message" => msg, + ), + PublishStatus::Unknown => { + crit!(log_1, "Unknown condition when publishing attestation") + } + }) + .and_then(move |_| { + for (duty, is_aggregator_proof) in successful_duties { + service_1 + .duties_service + .subscribe_duty(&duty, is_aggregator_proof); + } + Ok(()) + }) + .map_err(move |e| { + crit!( + log_2, + "Error during attestation production"; + "error" => e + ) + }) + } + + /// For a given `committee_index`, download the attestation, have each validator in + /// `validator_duties` sign it and send the collection back to the beacon node. fn do_attestation( &self, slot: Slot, @@ -235,28 +380,32 @@ impl AttestationService { .produce_attestation(slot, committee_index) .map_err(|e| format!("Failed to produce attestation: {:?}", e)) .map(move |attestation| { - validator_duties - .iter() - .fold(attestation, |mut attestation, duty| { + validator_duties.iter().fold( + (Vec::new(), attestation), + |(mut attestation_list, attestation), duty| { let log = service_1.context.log.clone(); if let Some(( duty_slot, duty_committee_index, validator_committee_position, + _, )) = attestation_duties(duty) { + let mut raw_attestation = attestation.clone(); if duty_slot == slot && duty_committee_index == committee_index { if service_1 .validator_store .sign_attestation( &duty.validator_pubkey, validator_committee_position, - &mut attestation, + &mut raw_attestation, ) .is_none() { crit!(log, "Failed to sign attestation"); + } else { + attestation_list.push(raw_attestation); } } else { crit!(log, "Inconsistent validator duties during signing"); @@ -265,22 +414,134 @@ impl AttestationService { crit!(log, "Missing validator duties when signing"); } - attestation - }) + (attestation_list, attestation) + }, + ) }) - .and_then(move |attestation| { + .and_then(move |(attestation_list, attestation)| { service_2 .beacon_node .http .validator() - .publish_attestation(attestation.clone()) + .publish_attestations(attestation_list.clone()) + .map(|publish_status| (attestation_list, attestation, publish_status)) + .map_err(|e| format!("Failed to publish attestations: {:?}", e)) + }) + .map( + move |(attestation_list, attestation, publish_status)| match publish_status { + PublishStatus::Valid => info!( + log_1, + "Successfully published attestation"; + "signatures" => attestation_list.len(), + "head_block" => format!("{}", attestation.data.beacon_block_root), + "committee_index" => attestation.data.index, + "slot" => attestation.data.slot.as_u64(), + ), + PublishStatus::Invalid(msg) => crit!( + log_1, + "Published attestation was invalid"; + "message" => msg, + "committee_index" => attestation.data.index, + "slot" => attestation.data.slot.as_u64(), + ), + PublishStatus::Unknown => { + crit!(log_1, "Unknown condition when publishing attestation") + } + }, + ) + .map_err(move |e| { + crit!( + log_2, + "Error during attestation production"; + "error" => e + ) + }) + } + + /// For a given `committee_index`, download the aggregate attestation, have it signed by all validators + /// in `validator_duties` then upload it. + fn do_aggregate_attestation( + &self, + slot: Slot, + committee_index: CommitteeIndex, + validator_duties: Vec, + aggregator_delay: Delay, + ) -> impl Future { + let service_1 = self.clone(); + let service_2 = self.clone(); + let log_1 = self.context.log.clone(); + let log_2 = self.context.log.clone(); + + self.beacon_node + .http + .validator() + .produce_aggregate_attestation(slot, committee_index) + .map_err(|e| format!("Failed to produce an aggregate attestation: {:?}", e)) + .map(move |attestation| { + validator_duties.iter().fold( + (Vec::new(), attestation), + |(mut aggregate_and_proof_list, attestation), duty_and_state| { + let log = service_1.context.log.clone(); + + match ( + duty_and_state.selection_proof(), + attestation_duties(&duty_and_state.duty), + ) { + ( + Some(selection_proof), + Some((duty_slot, duty_committee_index, _, aggregator_index)), + ) => { + let raw_attestation = attestation.clone(); + if duty_slot == slot && duty_committee_index == committee_index { + // build the `AggregateAndProof` struct for each validator + let aggregate_and_proof = AggregateAndProof { + aggregator_index, + aggregate: raw_attestation, + selection_proof, + }; + + if let Some(signed_aggregate_and_proof) = + service_1.validator_store.sign_aggregate_and_proof( + &duty_and_state.duty.validator_pubkey, + aggregate_and_proof, + ) + { + aggregate_and_proof_list.push(signed_aggregate_and_proof); + } else { + crit!(log, "Failed to sign attestation"); + } + } else { + crit!(log, "Inconsistent validator duties during signing"); + } + } + _ => crit!( + log, + "Missing validator duties or not aggregate duty when signing" + ), + } + + (aggregate_and_proof_list, attestation) + }, + ) + }) + .and_then(move |(aggregate_and_proof_list, attestation)| { + aggregator_delay + .map(move |_| (aggregate_and_proof_list, attestation)) + .map_err(move |e| format!("Error during aggregator delay: {:?}", e)) + }) + .and_then(move |(aggregate_and_proof_list, attestation)| { + service_2 + .beacon_node + .http + .validator() + .publish_aggregate_and_proof(aggregate_and_proof_list) .map(|publish_status| (attestation, publish_status)) - .map_err(|e| format!("Failed to publish attestation: {:?}", e)) + .map_err(|e| format!("Failed to publish aggregate and proofs: {:?}", e)) }) .map(move |(attestation, publish_status)| match publish_status { PublishStatus::Valid => info!( log_1, - "Successfully published attestation"; + "Successfully published aggregate attestations"; "signatures" => attestation.aggregation_bits.num_set_bits(), "head_block" => format!("{}", attestation.data.beacon_block_root), "committee_index" => attestation.data.index, @@ -307,10 +568,11 @@ impl AttestationService { } } -fn attestation_duties(duty: &ValidatorDuty) -> Option<(Slot, CommitteeIndex, usize)> { +fn attestation_duties(duty: &ValidatorDuty) -> Option<(Slot, CommitteeIndex, usize, u64)> { Some(( duty.attestation_slot?, duty.attestation_committee_index?, duty.attestation_committee_position?, + duty.validator_index?, )) } diff --git a/validator_client/src/duties_service.rs b/validator_client/src/duties_service.rs index bbbe04592..7360c173d 100644 --- a/validator_client/src/duties_service.rs +++ b/validator_client/src/duties_service.rs @@ -1,9 +1,11 @@ use crate::validator_store::ValidatorStore; +use bls::Signature; use environment::RuntimeContext; use exit_future::Signal; use futures::{future, Future, IntoFuture, Stream}; use parking_lot::RwLock; use remote_beacon_node::RemoteBeaconNode; +use rest_types::{ValidatorDuty, ValidatorDutyBytes}; use slog::{crit, debug, error, info, trace, warn}; use slot_clock::SlotClock; use std::collections::HashMap; @@ -12,7 +14,7 @@ use std::ops::Deref; use std::sync::Arc; use std::time::{Duration, Instant}; use tokio::timer::Interval; -use types::{ChainSpec, CommitteeIndex, Epoch, EthSpec, PublicKey, Slot}; +use types::{ChainSpec, Epoch, EthSpec, PublicKey, Slot}; /// Delay this period of time after the slot starts. This allows the node to process the new slot. const TIME_DELAY_FROM_SLOT: Duration = Duration::from_millis(100); @@ -20,35 +22,74 @@ const TIME_DELAY_FROM_SLOT: Duration = Duration::from_millis(100); /// Remove any duties where the `duties_epoch < current_epoch - PRUNE_DEPTH`. const PRUNE_DEPTH: u64 = 4; -type BaseHashMap = HashMap>; +type BaseHashMap = HashMap>; -/// Stores the duties for some validator for an epoch. -#[derive(PartialEq, Debug, Clone)] -pub struct ValidatorDuty { - /// The validator's BLS public key, uniquely identifying them. _48-bytes, hex encoded with 0x prefix, case insensitive._ - pub validator_pubkey: PublicKey, - /// The slot at which the validator must attest. - pub attestation_slot: Option, - /// The index of the committee within `slot` of which the validator is a member. - pub attestation_committee_index: Option, - /// The position of the validator in the committee. - pub attestation_committee_position: Option, - /// The slots in which a validator must propose a block (can be empty). - pub block_proposal_slots: Vec, +#[derive(Debug, Clone)] +pub struct DutyAndState { + /// The validator duty. + pub duty: ValidatorDuty, + /// The current state of the validator duty. + state: DutyState, } -impl TryInto for remote_beacon_node::ValidatorDuty { +#[derive(Debug, Clone)] +pub enum DutyState { + /// This duty has not been subscribed to the beacon node. + NotSubscribed, + /// The duty has been subscribed to the beacon node. + Subscribed, + /// The duty has been subscribed and the validator is an aggregator for this duty. The + /// selection proof is provided to construct the `AggregateAndProof` struct. + SubscribedAggregator(Signature), +} + +impl DutyAndState { + /// Returns true if the duty is an aggregation duty (the validator must aggregate all + /// attestations. + pub fn is_aggregator(&self) -> bool { + match self.state { + DutyState::NotSubscribed => false, + DutyState::Subscribed => false, + DutyState::SubscribedAggregator(_) => true, + } + } + + /// Returns the selection proof if the duty is an aggregation duty. + pub fn selection_proof(&self) -> Option { + match &self.state { + DutyState::SubscribedAggregator(proof) => Some(proof.clone()), + _ => None, + } + } + + /// Returns true if the this duty has been subscribed with the beacon node. + pub fn is_subscribed(&self) -> bool { + match self.state { + DutyState::NotSubscribed => false, + DutyState::Subscribed => true, + DutyState::SubscribedAggregator(_) => true, + } + } +} + +impl TryInto for ValidatorDutyBytes { type Error = String; - fn try_into(self) -> Result { - Ok(ValidatorDuty { + fn try_into(self) -> Result { + let duty = ValidatorDuty { validator_pubkey: (&self.validator_pubkey) .try_into() .map_err(|e| format!("Invalid pubkey bytes from server: {:?}", e))?, + validator_index: self.validator_index, attestation_slot: self.attestation_slot, attestation_committee_index: self.attestation_committee_index, attestation_committee_position: self.attestation_committee_position, block_proposal_slots: self.block_proposal_slots, + aggregator_modulo: self.aggregator_modulo, + }; + Ok(DutyAndState { + duty, + state: DutyState::NotSubscribed, }) } } @@ -82,7 +123,7 @@ impl DutiesStore { .filter(|(_validator_pubkey, validator_map)| { validator_map .get(&epoch) - .map(|duties| !duties.block_proposal_slots.is_empty()) + .map(|duties| !duties.duty.block_proposal_slots.is_empty()) .unwrap_or_else(|| false) }) .count() @@ -96,7 +137,7 @@ impl DutiesStore { .filter(|(_validator_pubkey, validator_map)| { validator_map .get(&epoch) - .map(|duties| duties.attestation_slot.is_some()) + .map(|duties| duties.duty.attestation_slot.is_some()) .unwrap_or_else(|| false) }) .count() @@ -112,8 +153,8 @@ impl DutiesStore { let epoch = slot.epoch(slots_per_epoch); validator_map.get(&epoch).and_then(|duties| { - if duties.block_proposal_slots.contains(&slot) { - Some(duties.validator_pubkey.clone()) + if duties.duty.block_proposal_slots.contains(&slot) { + Some(duties.duty.validator_pubkey.clone()) } else { None } @@ -122,7 +163,49 @@ impl DutiesStore { .collect() } - fn attesters(&self, slot: Slot, slots_per_epoch: u64) -> Vec { + /// Gets a list of validator duties for an epoch that have not yet been subscribed + /// to the beacon node. + // Note: Potentially we should modify the data structure to store the unsubscribed epoch duties for validator clients with a large number of validators. This currently adds an O(N) search each slot. + fn unsubscribed_epoch_duties(&self, epoch: &Epoch) -> Vec { + self.store + .read() + .iter() + .filter_map(|(_validator_pubkey, validator_map)| { + validator_map.get(epoch).and_then(|duty_and_state| { + if !duty_and_state.is_subscribed() { + Some(duty_and_state) + } else { + None + } + }) + }) + .map(|duties| duties.duty.clone()) + .collect() + } + + /// Marks a duty as being subscribed to the beacon node. This is called by the attestation + /// service once it has been sent. + fn set_duty_state( + &self, + validator: &PublicKey, + slot: Slot, + state: DutyState, + slots_per_epoch: u64, + ) { + let epoch = slot.epoch(slots_per_epoch); + + let mut store = self.store.write(); + if let Some(map) = store.get_mut(validator) { + if let Some(duty) = map.get_mut(&epoch) { + if duty.duty.attestation_slot == Some(slot) { + // set the duty state + duty.state = state; + } + } + } + } + + fn attesters(&self, slot: Slot, slots_per_epoch: u64) -> Vec { self.store .read() .iter() @@ -132,7 +215,7 @@ impl DutiesStore { let epoch = slot.epoch(slots_per_epoch); validator_map.get(&epoch).and_then(|duties| { - if duties.attestation_slot == Some(slot) { + if duties.duty.attestation_slot == Some(slot) { Some(duties) } else { None @@ -143,16 +226,16 @@ impl DutiesStore { .collect() } - fn insert(&self, epoch: Epoch, duties: ValidatorDuty, slots_per_epoch: u64) -> InsertOutcome { + fn insert(&self, epoch: Epoch, duties: DutyAndState, slots_per_epoch: u64) -> InsertOutcome { let mut store = self.store.write(); - if !duties_match_epoch(&duties, epoch, slots_per_epoch) { + if !duties_match_epoch(&duties.duty, epoch, slots_per_epoch) { return InsertOutcome::Invalid; } - if let Some(validator_map) = store.get_mut(&duties.validator_pubkey) { + if let Some(validator_map) = store.get_mut(&duties.duty.validator_pubkey) { if let Some(known_duties) = validator_map.get_mut(&epoch) { - if *known_duties == duties { + if known_duties.duty == duties.duty { InsertOutcome::Identical } else { *known_duties = duties; @@ -164,7 +247,7 @@ impl DutiesStore { InsertOutcome::NewEpoch } } else { - let validator_pubkey = duties.validator_pubkey.clone(); + let validator_pubkey = duties.duty.validator_pubkey.clone(); let mut validator_map = HashMap::new(); validator_map.insert(epoch, duties); @@ -315,10 +398,29 @@ impl DutiesService { } /// Returns all `ValidatorDuty` for the given `slot`. - pub fn attesters(&self, slot: Slot) -> Vec { + pub fn attesters(&self, slot: Slot) -> Vec { self.store.attesters(slot, E::slots_per_epoch()) } + /// Returns all `ValidatorDuty` that have not been registered with the beacon node. + pub fn unsubscribed_epoch_duties(&self, epoch: &Epoch) -> Vec { + self.store.unsubscribed_epoch_duties(epoch) + } + + /// Marks the duty as being subscribed to the beacon node. + /// + /// If the duty is to be marked as an aggregator duty, a selection proof is also provided. + pub fn subscribe_duty(&self, duty: &ValidatorDuty, aggregator_proof: Option) { + let state = match aggregator_proof { + Some(proof) => DutyState::SubscribedAggregator(proof), + None => DutyState::Subscribed, + }; + if let Some(slot) = duty.attestation_slot { + self.store + .set_duty_state(&duty.validator_pubkey, slot, state, E::slots_per_epoch()) + } + } + /// Start the service that periodically polls the beacon node for validator duties. pub fn start_update_service(&self, spec: &ChainSpec) -> Result { let log = self.context.log.clone(); @@ -477,7 +579,7 @@ impl DutiesService { let mut invalid = 0; all_duties.into_iter().try_for_each::<_, Result<_, String>>(|remote_duties| { - let duties: ValidatorDuty = remote_duties.try_into()?; + let duties: DutyAndState = remote_duties.try_into()?; match service_2 .store @@ -487,9 +589,9 @@ impl DutiesService { debug!( log, "First duty assignment for validator"; - "proposal_slots" => format!("{:?}", &duties.block_proposal_slots), - "attestation_slot" => format!("{:?}", &duties.attestation_slot), - "validator" => format!("{:?}", &duties.validator_pubkey) + "proposal_slots" => format!("{:?}", &duties.duty.block_proposal_slots), + "attestation_slot" => format!("{:?}", &duties.duty.attestation_slot), + "validator" => format!("{:?}", &duties.duty.validator_pubkey) ); new_validator += 1 } diff --git a/validator_client/src/validator_store.rs b/validator_client/src/validator_store.rs index 8700b5c1e..ce9c44f8c 100644 --- a/validator_client/src/validator_store.rs +++ b/validator_client/src/validator_store.rs @@ -12,8 +12,8 @@ use std::path::PathBuf; use std::sync::Arc; use tempdir::TempDir; use types::{ - Attestation, BeaconBlock, ChainSpec, Domain, Epoch, EthSpec, Fork, PublicKey, Signature, - SignedBeaconBlock, SignedRoot, + AggregateAndProof, Attestation, BeaconBlock, ChainSpec, Domain, Epoch, EthSpec, Fork, + PublicKey, Signature, SignedAggregateAndProof, SignedBeaconBlock, SignedRoot, Slot, }; #[derive(Clone)] @@ -198,4 +198,38 @@ impl ValidatorStore { Some(()) }) } + + /// Signs a slot for a given validator. + /// + /// This is used to subscribe a validator to a beacon node and is used to determine if the + /// validator is to aggregate attestations for this slot. + pub fn sign_slot(&self, validator_pubkey: &PublicKey, slot: Slot) -> Option { + let validators = self.validators.read(); + let voting_keypair = validators.get(validator_pubkey)?.voting_keypair.as_ref()?; + + let domain = self.spec.get_domain( + slot.epoch(E::slots_per_epoch()), + Domain::SelectionProof, + &self.fork()?, + ); + + let message = slot.signing_root(domain); + + Some(Signature::new(message.as_bytes(), &voting_keypair.sk)) + } + + /// Signs an `AggregateAndProof` for a given validator. + /// + /// The resulting `SignedAggregateAndProof` is sent on the aggregation channel and cannot be + /// modified by actors other than the signing validator. + pub fn sign_aggregate_and_proof( + &self, + validator_pubkey: &PublicKey, + aggregate_and_proof: AggregateAndProof, + ) -> Option> { + let validators = self.validators.read(); + let voting_keypair = validators.get(validator_pubkey)?.voting_keypair.as_ref()?; + + Some(aggregate_and_proof.into_signed(&voting_keypair.sk, &self.fork()?)) + } }