mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-06 20:13:59 -05:00
Spec freeze updates (#2312)
* Optimize Shuffled Indices Cache (#2728) * Refactor Deposit Contract Test Setup (#2731) * add new package * fix all tests * lint * change hash function (#2732) * Remove Deprecated Validator Protobuf (#2727) * Remove deprecated validator protos * Fix to comments * Fix most of skipped tests (#2735) * Cache Active Validator Indices, Count, and Balances (#2737) * Optimize Base Reward Calculation (#2753) * benchmark process epoch * revert prof.out * Add some optimizations * beware where we use ActiveValidatorIndices... * revert extra file * gaz * quick commit to get feedback * revert extra file * started fixing tests * fixed broken TestProcessCrosslink_NoUpdate * gaz * cache randao seed * fixed all the tests * fmt and lint * spacing * Added todo * lint * revert binary file * started regression test * basic tests done * using a fifo for active indices cache * using a fifo for active count cache * using a fifo for total balance cache * using a fifo for active balance cache * using a fifo for start shard cache * using a fifo for seed cache * gaz * clean up * fixing tests * fixed all the core tests * fixed all the tests!!! * lint * comment * rm'ed commented code * cache size to 1000 should be good enough * optimized base reward * revert binary file * Added comments to calculate adjusted quotient outside * removed deprecated configs (#2755) * Optimize Process Eth1 Data Vote (#2754) * Cleanup and Docs update (#2756) * Add graffiti and update generate seed (#2759) * Benchmark Process Block with Attestations (#2758) * Tidying up Godoc for Core Package (#2762) * Clean up Old RPC Endpoints (#2763) * Update RPC end point for Proposer (#2767) * add RequestBlock * run mockgen * implemented RequestBlock * updated proto definitions * updated tests * updated validator attest tests * done * comment * todo issue * removed unused proto * Update attesting indices v0.6 (#2449) * sort participants slice * add bitfield functions and tests * added BitfieldBit test * add AttestationParticipantsNew * revert AttestationParticipants to its previous change * add tests * remove verifybitfieldnew * fix tests and remove multiple tests * remove duplicate test * change magic number into ceildiv8 * Implement Justification and finalization Processing (#2448) * Add convert to indexed (#2519) * sort participants slice * add bitfield functions and tests * added BitfieldBit test * add AttestationParticipantsNew * revert AttestationParticipants to its previous change * add tests * remove verifybitfieldnew * fix tests and remove multiple tests * remove duplicate test * start work * convert attestation to indexed attestations * fix test for convert index * remove calling getter * add more tests * remove underscore * changes name to signature (#2535) * update registry updates func (#2521) * update registry updates func * added tests and moved to epoch processing * fixed naming issues * Update Committee Helpers to v0.6.0 (#2398) * Update Committee Helper Part 2 (#2592) * Implement Process Slashings for 0.6 (#2523) * Update Proposer/Attester Slashings and Slashing Helpers (#2603) * Implement Final Updates 0.6 (#2562) * ValidatorStatus Estimating Activation RPC Server (#2469) * fix spacing * working on position in queue * fmt * spacing * feedback * tests * rename * Only Perform Initial Sync With a Single Peer (#2471) * fix spacing * use send instead of broadcast in initial sync * Fix Estimation of Deposit Inclusion Slot in ValidatorActivationStatus (#2472) * fix spacing * fix time estimates * correct slot estimation * naming * Update beacon-chain/rpc/validator_server.go Co-Authored-By: rauljordan <raul@prysmaticlabs.com> * SSZ web api for decoding input data (#2473) * first pass ssz server for decoding deposit input data * fix decoding * revert viz change on helper * add image target * use /api prefix, add deployment for cluster * fix lint * standardize slot numbers (#2475) * Add CORS for ssz api (#2476) * first pass ssz server for decoding deposit input data * fix decoding * revert viz change on helper * add image target * use /api prefix, add deployment for cluster * fix lint * needed CORS * Allow Client to Retrieve Multiple Validator Statuses (#2474) * multiple validator statuses * gazelle * context * fixing bugs * remove old way of checking * fix logging * make activation queue more accurate * fix rpc test * add test * fix remaining tests * lint * comment * review comments * Update Prysm README (#2477) * README updated * readme updates * no err throw (#2479) * Fix Status Nil Pointer Error (#2480) * no err throw * nil errors * 3.175 (#2482) * Better Error Message if Failing to Exit Initial Sync (#2483) * no err throw * nil errors * better error on init sync * Only Log Active Balances (#2485) * only log active balance * dont need () * change logging (#2487) * fix chainstart waiting on rpc server (#2488) * shift ticker to after activation (#2489) * Add drain script (#2418) * Add drain script * Fix script to drain contracts from newest to oldest * Add README * remove comments * Only after block 400k, look up by deposit event * issue warn log on disconnecting peer instead of error (#2491) * Display Only Active Validator Data (#2490) * Fix Validator Status Field in RPC Server (#2492) * fix status of key * status test fix * fmt * Estimate the Time Till Follow Distance Is Completed (#2486) * use estimation instead * fix test * fixing another test * fix tests and preston's comments * remove unused var * fix condition * Revert "fix condition" This reverts commitdee0e3112c. * dont return error * add production config for testnet release (#2493) * Lookup Validator Index in State in Status Check (#2494) * state lookup * refactor duplicate code * refactor with mapping * fix broken tests * finish refactor * merged master * updated EpochCommitteeCount and fixed tests * implemented ShardDelta * test for ShardDelta * implemented EpochStartShard * added epoch out of bound test * test for accurate start shard * lint * implemented process_final_updates * move to the top of the file * add comment back * gaz * Test for process final updates * fixed tests * fixed all the tests * Update Reward Helper v0.6 (#2470) * added BaseReward * added rewards helper * added test for BaseReward * extra space * move exported function above * update to new spec (#2614) * Update Block Processing Voluntary Exits (#2609) * Update processEth1Data for v0.6 (#2516) * Clean up Helper Functions Part 1 (#2612) * Finalize helper functions for 0.6 (#2632) * Process Beacon Chain Transfers v0.6 (#2642) * add transfers * beacon transfer operations complete * full cov * transfer testing * finished tests * Update beacon-chain/core/blocks/block_operations_test.go Co-Authored-By: terence tsao <terence@prysmaticlabs.com> * Update beacon-chain/core/blocks/block_operations.go Co-Authored-By: terence tsao <terence@prysmaticlabs.com> * Implement Process Crosslink From 0.6 (#2460) * Process Block Eth1 Data v0.6 (#2645) * Get attestation data slot v0.6 (#2593) * attestation.go is ready, tests not * ready for review * fixing linter issues * modified Crosslink and AttestationData proto fields to spec 2.0,marked deprecated fields * gazelle * fixed tests * fixed error * error msg * Process Block Deposits v0.6 (#2647) * imports fixes * deposits tests pass * wrapped up gazelle * spacing * Implement Crosslink Delta Rewards for 0.6 (#2517) * update process crosslink and update existing tests * added a test case to cover no crosslink changes * more test * preston's feedback * spellings * ValidatorStatus Estimating Activation RPC Server (#2469) * fix spacing * working on position in queue * fmt * spacing * feedback * tests * rename * Only Perform Initial Sync With a Single Peer (#2471) * fix spacing * use send instead of broadcast in initial sync * Fix Estimation of Deposit Inclusion Slot in ValidatorActivationStatus (#2472) * fix spacing * fix time estimates * correct slot estimation * naming * Update beacon-chain/rpc/validator_server.go Co-Authored-By: rauljordan <raul@prysmaticlabs.com> * SSZ web api for decoding input data (#2473) * first pass ssz server for decoding deposit input data * fix decoding * revert viz change on helper * add image target * use /api prefix, add deployment for cluster * fix lint * standardize slot numbers (#2475) * Add CORS for ssz api (#2476) * first pass ssz server for decoding deposit input data * fix decoding * revert viz change on helper * add image target * use /api prefix, add deployment for cluster * fix lint * needed CORS * Allow Client to Retrieve Multiple Validator Statuses (#2474) * multiple validator statuses * gazelle * context * fixing bugs * remove old way of checking * fix logging * make activation queue more accurate * fix rpc test * add test * fix remaining tests * lint * comment * review comments * Update Prysm README (#2477) * README updated * readme updates * no err throw (#2479) * Fix Status Nil Pointer Error (#2480) * no err throw * nil errors * 3.175 (#2482) * Better Error Message if Failing to Exit Initial Sync (#2483) * no err throw * nil errors * better error on init sync * Only Log Active Balances (#2485) * only log active balance * dont need () * change logging (#2487) * fix chainstart waiting on rpc server (#2488) * shift ticker to after activation (#2489) * Add drain script (#2418) * Add drain script * Fix script to drain contracts from newest to oldest * Add README * remove comments * Only after block 400k, look up by deposit event * issue warn log on disconnecting peer instead of error (#2491) * Display Only Active Validator Data (#2490) * Fix Validator Status Field in RPC Server (#2492) * fix status of key * status test fix * fmt * Estimate the Time Till Follow Distance Is Completed (#2486) * use estimation instead * fix test * fixing another test * fix tests and preston's comments * remove unused var * fix condition * Revert "fix condition" This reverts commitdee0e3112c. * dont return error * add production config for testnet release (#2493) * Lookup Validator Index in State in Status Check (#2494) * state lookup * refactor duplicate code * refactor with mapping * fix broken tests * finish refactor * merged master * Starting, I need get_epoch_start_shard * updated EpochCommitteeCount and fixed tests * implemented ShardDelta * test for ShardDelta * implemented EpochStartShard * added epoch out of bound test * test for accurate start shard * lint * need to use changes from latest crosslinks * added BaseReward and totalActiveBalance * added test for base reward * merged master * all tests passing * start testing * done * add ProcessBlockHeader v0.6 (#2534) * add ProcessBlockHeader * function has all its dependancies in place * arange the basic ok test * gazzele and skip test update * skip wrong sig test * fmt imports and change requests * goimports fmt * map for struct fields to be location independent * reorder protobuf fields * added tests * gazzle fix * few change requests fixes * revert changes in types.proto * revert changes in types * fix tests * fix lint * fmt imports * fix gazelle * fix var naming * pb update * var naming * tarance change request fixes * fix test * Add Process Registry for Epoch Processing (#2668) * update update-process-registry * added back the old tests * fmt * gaz * Follow up on process block header v0.6 (#2666) * Putting Crosslink Delta Back (#2654) * update process crosslink and update existing tests * added a test case to cover no crosslink changes * more test * preston's feedback * spellings * ValidatorStatus Estimating Activation RPC Server (#2469) * fix spacing * working on position in queue * fmt * spacing * feedback * tests * rename * Only Perform Initial Sync With a Single Peer (#2471) * fix spacing * use send instead of broadcast in initial sync * Fix Estimation of Deposit Inclusion Slot in ValidatorActivationStatus (#2472) * fix spacing * fix time estimates * correct slot estimation * naming * Update beacon-chain/rpc/validator_server.go Co-Authored-By: rauljordan <raul@prysmaticlabs.com> * SSZ web api for decoding input data (#2473) * first pass ssz server for decoding deposit input data * fix decoding * revert viz change on helper * add image target * use /api prefix, add deployment for cluster * fix lint * standardize slot numbers (#2475) * Add CORS for ssz api (#2476) * first pass ssz server for decoding deposit input data * fix decoding * revert viz change on helper * add image target * use /api prefix, add deployment for cluster * fix lint * needed CORS * Allow Client to Retrieve Multiple Validator Statuses (#2474) * multiple validator statuses * gazelle * context * fixing bugs * remove old way of checking * fix logging * make activation queue more accurate * fix rpc test * add test * fix remaining tests * lint * comment * review comments * Update Prysm README (#2477) * README updated * readme updates * no err throw (#2479) * Fix Status Nil Pointer Error (#2480) * no err throw * nil errors * 3.175 (#2482) * Better Error Message if Failing to Exit Initial Sync (#2483) * no err throw * nil errors * better error on init sync * Only Log Active Balances (#2485) * only log active balance * dont need () * change logging (#2487) * fix chainstart waiting on rpc server (#2488) * shift ticker to after activation (#2489) * Add drain script (#2418) * Add drain script * Fix script to drain contracts from newest to oldest * Add README * remove comments * Only after block 400k, look up by deposit event * issue warn log on disconnecting peer instead of error (#2491) * Display Only Active Validator Data (#2490) * Fix Validator Status Field in RPC Server (#2492) * fix status of key * status test fix * fmt * Estimate the Time Till Follow Distance Is Completed (#2486) * use estimation instead * fix test * fixing another test * fix tests and preston's comments * remove unused var * fix condition * Revert "fix condition" This reverts commitdee0e3112c. * dont return error * add production config for testnet release (#2493) * Lookup Validator Index in State in Status Check (#2494) * state lookup * refactor duplicate code * refactor with mapping * fix broken tests * finish refactor * merged master * Starting, I need get_epoch_start_shard * updated EpochCommitteeCount and fixed tests * implemented ShardDelta * test for ShardDelta * implemented EpochStartShard * added epoch out of bound test * test for accurate start shard * lint * need to use changes from latest crosslinks * added BaseReward and totalActiveBalance * added test for base reward * merged master * all tests passing * start testing * done * fixed tests * addressed shay's feedback * Implement Attestation Delta for v0.6 (#2646) * update process crosslink and update existing tests * added a test case to cover no crosslink changes * more test * preston's feedback * spellings * ValidatorStatus Estimating Activation RPC Server (#2469) * fix spacing * working on position in queue * fmt * spacing * feedback * tests * rename * Only Perform Initial Sync With a Single Peer (#2471) * fix spacing * use send instead of broadcast in initial sync * Fix Estimation of Deposit Inclusion Slot in ValidatorActivationStatus (#2472) * fix spacing * fix time estimates * correct slot estimation * naming * Update beacon-chain/rpc/validator_server.go Co-Authored-By: rauljordan <raul@prysmaticlabs.com> * SSZ web api for decoding input data (#2473) * first pass ssz server for decoding deposit input data * fix decoding * revert viz change on helper * add image target * use /api prefix, add deployment for cluster * fix lint * standardize slot numbers (#2475) * Add CORS for ssz api (#2476) * first pass ssz server for decoding deposit input data * fix decoding * revert viz change on helper * add image target * use /api prefix, add deployment for cluster * fix lint * needed CORS * Allow Client to Retrieve Multiple Validator Statuses (#2474) * multiple validator statuses * gazelle * context * fixing bugs * remove old way of checking * fix logging * make activation queue more accurate * fix rpc test * add test * fix remaining tests * lint * comment * review comments * Update Prysm README (#2477) * README updated * readme updates * no err throw (#2479) * Fix Status Nil Pointer Error (#2480) * no err throw * nil errors * 3.175 (#2482) * Better Error Message if Failing to Exit Initial Sync (#2483) * no err throw * nil errors * better error on init sync * Only Log Active Balances (#2485) * only log active balance * dont need () * change logging (#2487) * fix chainstart waiting on rpc server (#2488) * shift ticker to after activation (#2489) * Add drain script (#2418) * Add drain script * Fix script to drain contracts from newest to oldest * Add README * remove comments * Only after block 400k, look up by deposit event * issue warn log on disconnecting peer instead of error (#2491) * Display Only Active Validator Data (#2490) * Fix Validator Status Field in RPC Server (#2492) * fix status of key * status test fix * fmt * Estimate the Time Till Follow Distance Is Completed (#2486) * use estimation instead * fix test * fixing another test * fix tests and preston's comments * remove unused var * fix condition * Revert "fix condition" This reverts commitdee0e3112c. * dont return error * add production config for testnet release (#2493) * Lookup Validator Index in State in Status Check (#2494) * state lookup * refactor duplicate code * refactor with mapping * fix broken tests * finish refactor * merged master * Starting, I need get_epoch_start_shard * updated EpochCommitteeCount and fixed tests * implemented ShardDelta * test for ShardDelta * implemented EpochStartShard * added epoch out of bound test * test for accurate start shard * lint * need to use changes from latest crosslinks * added BaseReward and totalActiveBalance * added test for base reward * implemented process_attestation_delta * comments * comments * merged master * all tests passing * start testing * done * merged master * fixed tests * tests, more to come * tests done * lint * spaces over tabs * addressed shay's feedback * merged master * Implement process_rewards_and_penalties for 0.6 (#2665) * update process crosslink and update existing tests * added a test case to cover no crosslink changes * more test * preston's feedback * spellings * ValidatorStatus Estimating Activation RPC Server (#2469) * fix spacing * working on position in queue * fmt * spacing * feedback * tests * rename * Only Perform Initial Sync With a Single Peer (#2471) * fix spacing * use send instead of broadcast in initial sync * Fix Estimation of Deposit Inclusion Slot in ValidatorActivationStatus (#2472) * fix spacing * fix time estimates * correct slot estimation * naming * Update beacon-chain/rpc/validator_server.go Co-Authored-By: rauljordan <raul@prysmaticlabs.com> * SSZ web api for decoding input data (#2473) * first pass ssz server for decoding deposit input data * fix decoding * revert viz change on helper * add image target * use /api prefix, add deployment for cluster * fix lint * standardize slot numbers (#2475) * Add CORS for ssz api (#2476) * first pass ssz server for decoding deposit input data * fix decoding * revert viz change on helper * add image target * use /api prefix, add deployment for cluster * fix lint * needed CORS * Allow Client to Retrieve Multiple Validator Statuses (#2474) * multiple validator statuses * gazelle * context * fixing bugs * remove old way of checking * fix logging * make activation queue more accurate * fix rpc test * add test * fix remaining tests * lint * comment * review comments * Update Prysm README (#2477) * README updated * readme updates * no err throw (#2479) * Fix Status Nil Pointer Error (#2480) * no err throw * nil errors * 3.175 (#2482) * Better Error Message if Failing to Exit Initial Sync (#2483) * no err throw * nil errors * better error on init sync * Only Log Active Balances (#2485) * only log active balance * dont need () * change logging (#2487) * fix chainstart waiting on rpc server (#2488) * shift ticker to after activation (#2489) * Add drain script (#2418) * Add drain script * Fix script to drain contracts from newest to oldest * Add README * remove comments * Only after block 400k, look up by deposit event * issue warn log on disconnecting peer instead of error (#2491) * Display Only Active Validator Data (#2490) * Fix Validator Status Field in RPC Server (#2492) * fix status of key * status test fix * fmt * Estimate the Time Till Follow Distance Is Completed (#2486) * use estimation instead * fix test * fixing another test * fix tests and preston's comments * remove unused var * fix condition * Revert "fix condition" This reverts commitdee0e3112c. * dont return error * add production config for testnet release (#2493) * Lookup Validator Index in State in Status Check (#2494) * state lookup * refactor duplicate code * refactor with mapping * fix broken tests * finish refactor * merged master * Starting, I need get_epoch_start_shard * updated EpochCommitteeCount and fixed tests * implemented ShardDelta * test for ShardDelta * implemented EpochStartShard * added epoch out of bound test * test for accurate start shard * lint * need to use changes from latest crosslinks * added BaseReward and totalActiveBalance * added test for base reward * implemented process_attestation_delta * comments * comments * merged master * all tests passing * start testing * done * merged master * fixed tests * tests, more to come * tests done * lint * spaces over tabs * addressed shay's feedback * starting but need to merge a few things... * tests * fmt * Update Slot Processing and State Transition v0.6 (#2664) * edit state transition to add slot processing logic, reorder logic * fix build * lint * tests passing * spacing * tests pass * imports * passing tests * Implement Process Epoch for 0.6 (#2675) * can't find process j f functons * implemented process_epoch * tests done * lint * nishant's feedback * stupid goland replace * goimports * Update CommitteeAssignment (#2693) * cleaned up skipped tests for core processing (#2697) * Process Block Attestations v0.6 (#2650) * attestation.go is ready, tests not * ready for review * fixing linter issues * modified Crosslink and AttestationData proto fields to spec 2.0,marked deprecated fields * gazelle * fixed tests * fixed error * add att processing: * process atts * error msg * finish process attestations logic * spacing * ssz move * inclusion delay failure passing * more attestation tests * more att tests passing * more tests * ffg data mismatching test * ffg tests complete * gofmt * fix testing to match attestation updates * ssz * lint * Fixed Skipped Tests for RPC Server (#2712) * Remove Obsolete Deposit Proto Objects (#2673) * remove deposit data * remove deposit input * fix references * remove deposit helpers * fix all refs * gaz * rgene proto * fix all tests * remove deposit data deprecated field * fix remaining references * fix all tests * fix lint * regen proto * fix test * Remove Deprecated Protobuf State Fields (#2713) * Remove Deprecated Protobuf Crosslink/Slashing/Block Fields (#2714) * Remove Deprecated Beacon Block Proto Fields (#2717) * Remove Deprecated Attestation Proto Fields (#2723) * Cache Shuffled Validator Indices (#2682) * YAML shuffle tests for v0.6 (#2667) * new shuffle tests * added comment for exported function * fix format and print * added config files handling * gazelle fix * shuffle test debugging * added shuffle list and benchmark * hash function addition from nishant code * gazelle fix * remove unused function * few minor changes * add test to test protos optimization * test a bigger list * remove commented code * small changes * fix spec test and test indices to pass * remove empty line * abstraction of repeated code and comment arrangement * terence change requests * fix new test * add small comment for better readability * change from unshuflle to shuffle * comment * better comment * fix all tests * Remove Latest Block (#2721) * lint * remove latest block * lint * add proto * fix build * Fix Deposit Trie (#2686) * remove deposit data * remove deposit input * fix references * remove deposit helpers * fix all refs * gaz * rgene proto * fix all tests * remove deposit data deprecated field * fix remaining references * fix all tests * fix lint * new tests with contract * gaz * more tests * fixed bugs * new test * finally fixed it * gaz * fix test * Remove Committee Cache (#2729) * Benchmark Compute Committee (#2698) * Fixed Skipped Attestation Tests (#2730) * Optimize Shuffled Indices Cache (#2728) * Refactor Deposit Contract Test Setup (#2731) * add new package * fix all tests * lint * change hash function (#2732) * Remove Deprecated Validator Protobuf (#2727) * Remove deprecated validator protos * Fix to comments * Fix most of skipped tests (#2735) * Optimize Base Reward Calculation (#2753) * benchmark process epoch * revert prof.out * Add some optimizations * beware where we use ActiveValidatorIndices... * revert extra file * gaz * quick commit to get feedback * revert extra file * started fixing tests * fixed broken TestProcessCrosslink_NoUpdate * gaz * cache randao seed * fixed all the tests * fmt and lint * spacing * Added todo * lint * revert binary file * started regression test * basic tests done * using a fifo for active indices cache * using a fifo for active count cache * using a fifo for total balance cache * using a fifo for active balance cache * using a fifo for start shard cache * using a fifo for seed cache * gaz * clean up * fixing tests * fixed all the core tests * fixed all the tests!!! * lint * comment * rm'ed commented code * cache size to 1000 should be good enough * optimized base reward * revert binary file * Added comments to calculate adjusted quotient outside * removed deprecated configs (#2755) * Optimize Process Eth1 Data Vote (#2754) * Cleanup and Docs update (#2756) * Add graffiti and update generate seed (#2759) * Benchmark Process Block with Attestations (#2758) * Tidying up Godoc for Core Package (#2762) * Clean up Old RPC Endpoints (#2763) * Update RPC end point for Proposer (#2767) * add RequestBlock * run mockgen * implemented RequestBlock * updated proto definitions * updated tests * updated validator attest tests * done * comment * todo issue * removed unused proto * Cache Active Validator Indices, Count, and Balances (#2737) * Update Deposit Contract (#2648) * lint * add new contract * change version * remove log * generating abi and binary files * fix tests * update to current version * new changes * add new hash function * save hashed nodes * add more things * new method * add update to trie * new stuff * gaz * more stuff * finally fixed build * remove deposit data * Revert "remove deposit data" This reverts commit9085409e91. * more changes * lint and gaz * lint * Update Shard Helpers for 0.6 (#2497) * ValidatorStatus Estimating Activation RPC Server (#2469) * fix spacing * working on position in queue * fmt * spacing * feedback * tests * rename * Only Perform Initial Sync With a Single Peer (#2471) * fix spacing * use send instead of broadcast in initial sync * Fix Estimation of Deposit Inclusion Slot in ValidatorActivationStatus (#2472) * fix spacing * fix time estimates * correct slot estimation * naming * Update beacon-chain/rpc/validator_server.go Co-Authored-By: rauljordan <raul@prysmaticlabs.com> * SSZ web api for decoding input data (#2473) * first pass ssz server for decoding deposit input data * fix decoding * revert viz change on helper * add image target * use /api prefix, add deployment for cluster * fix lint * standardize slot numbers (#2475) * Add CORS for ssz api (#2476) * first pass ssz server for decoding deposit input data * fix decoding * revert viz change on helper * add image target * use /api prefix, add deployment for cluster * fix lint * needed CORS * Allow Client to Retrieve Multiple Validator Statuses (#2474) * multiple validator statuses * gazelle * context * fixing bugs * remove old way of checking * fix logging * make activation queue more accurate * fix rpc test * add test * fix remaining tests * lint * comment * review comments * Update Prysm README (#2477) * README updated * readme updates * no err throw (#2479) * Fix Status Nil Pointer Error (#2480) * no err throw * nil errors * 3.175 (#2482) * Better Error Message if Failing to Exit Initial Sync (#2483) * no err throw * nil errors * better error on init sync * Only Log Active Balances (#2485) * only log active balance * dont need () * change logging (#2487) * fix chainstart waiting on rpc server (#2488) * shift ticker to after activation (#2489) * Add drain script (#2418) * Add drain script * Fix script to drain contracts from newest to oldest * Add README * remove comments * Only after block 400k, look up by deposit event * issue warn log on disconnecting peer instead of error (#2491) * Display Only Active Validator Data (#2490) * Fix Validator Status Field in RPC Server (#2492) * fix status of key * status test fix * fmt * Estimate the Time Till Follow Distance Is Completed (#2486) * use estimation instead * fix test * fixing another test * fix tests and preston's comments * remove unused var * fix condition * Revert "fix condition" This reverts commitdee0e3112c. * dont return error * add production config for testnet release (#2493) * Lookup Validator Index in State in Status Check (#2494) * state lookup * refactor duplicate code * refactor with mapping * fix broken tests * finish refactor * merged master * updated EpochCommitteeCount and fixed tests * implemented ShardDelta * test for ShardDelta * implemented EpochStartShard * added epoch out of bound test * test for accurate start shard * lint * Update Genesis State Function to v0.6 (#2465) * add pseudocode * make changes * fix all tests * fix tests * lint * regen protos and mocks * regenerated protos * started fixing core * all core tests passing! * removed shared/forkutils * started fixing blockchain package * lint * updating rpc package * add back deleted stuff * add back deleted stuff that was deleted accidentally * add back protos and mocks * fix errors * fix genesis issue * fix genesis issue for slot ticker * fix all genesis errors * fix build files * temp change for go-ssz * fix test * Revert "temp change for go-ssz" This reverts commit3411cb9d6d. * update to latest go-ssz * unstaged changes * Update Attester Server RPC Calls (#2773) * Update config and function parameters to v0.7 (#2791) * Minor Updates to 0.7 (#2795) * Refactor Deposit Flow and Cleanup Tests (#2788) * More WIP on cleaning deposit flow * Fix tests * Cleanup and imports * run gazelle * Move deposit to block_operations * gazelle * Update beacon-chain/core/blocks/block_operations.go Co-Authored-By: terence tsao <terence@prysmaticlabs.com> * Fix docs * Remove unneeded calculations * Fix tests * Fix tests finally (?) * Optimize Committee Assignment RPC (#2787) * Update BlockRoot to BlockHash (#2816) * Fix Final Missing Items in Block Processing v0.6 (#2710) * override config successfully * passes processing * add signing root helper * blockchain tests pass * tests blocked by signing root * lint * fix references * fix protos * proper use of signing root * only few failing tests now * fix final test * tests passing * lint and imports * rem unused * Update beacon-chain/core/blocks/block_operations.go Co-Authored-By: terence tsao <terence@prysmaticlabs.com> * lint * Update beacon-chain/attestation/service_test.go Co-Authored-By: terence tsao <terence@prysmaticlabs.com> * Update beacon-chain/db/block_test.go Co-Authored-By: terence tsao <terence@prysmaticlabs.com> * rename to hash tree root * rename decode to unmarshal * fix * use latest ssz * all tests passing * lint * fmt * Add Config YAML for Spec Tests (#2818) * Align Protobuf Type Names (#2825) * gofmt * Revert "Align Protobuf Type Names (#2825)" (#2827) This reverts commit882d067144. * Update Domain Related Functions (#2832) * Add Functions for Compressed and Uncompressed HashG2 With Domain (#2833) * add tests * gaz * lint * Revert "Add Functions for Compressed and Uncompressed HashG2 With Domain (#2833)" (#2835) This reverts commit7fb2ebf3f1. * Add ConvertToPb to package testutil (#2838) * Block Processing Bug Fixes (#2836) * Update types PB with Size Tags (#2840) * Epoch processing spec tests (#2814) * Remove Deposit Index (#2851) * Shuffle tests revisited (#2829) * first commit * remove old files, add log * remove duplicate yaml testing code * reduce visability * nishant feedback changes * skip TestFromYaml_Pass * added tags to bazel build * gazelle fix * remove unused vars * adda back config * remove config handling * remove unused var * gazelle fix * SSZ compatibility test for protobufs (#2839) * update workspace spec sha * remove yamls from branch * BLS spec tests (#2826) (#2856) * bls spec tests * add more bls tests * use ioutil instead of bazel runfiles * dont read bytes * skip tests that overflow uint64 * manually fix input data * add tests * lint and gaz * add all new changes * some refactoring, cleanup, remove new API methods that only exist for tests * gaz * Remove yamls, skip test * Slot processing spec test (#2813) * eth1data rpc endpoint (#2733) * eth1data rpc endpoint * first version * comment added * gazelle fix * new function to go once over the deposit array * fix tests * export DepositContainer * terence feedback * move structure decleration * binary search * fix block into Block * preston feedback * keep slice sorted to remove overhead in retrival * merge changes * feedback * update to the latest go-ssz * revert change * chnages to fit new ssz * revert merge reversion * go fmt goimprts duplicate string * exception for lint unused doesParentExist * feedback changes * latesteth1data to eth1data * goimports and stop exposing Eth1Data * revert unneeded change * remove exposure of DepositContainer * feedback and fixes * fix workspace duplicate dependancy * greatest number of deposits at current height * add count votes function * change method name * revert back to latesteth1data * latesteth1data * preston feedback * seperate function add tests fix bug * stop exposing voteCountMap * eth1data comment fix * preston feedback * fix tests * new proto files * workspace to default version of ssz * new ssz * chnage test size * marshalled marshaled * Attesting Indices Fix (#2862) * add change * fix one test * fix all tests * add test * clear cache * removed old chaintest, simulated backend and state generator (#2863) * Block Processing Sanity Spec Tests (#2817) * update PrevEpoch * add new changes * shift to blocks package * add more changes * new changes * updated pb with size tags * add new changes * fix errors * uncomment code * more changes * add new changes * rename and lint * gaz * more changes * proccess slot SigningRoot instead of HashTreeRoot * ensure yaml generated structs work * block sanity all passing * minimal and mainnet all pass * remove commented code * fix one test * fix all tests * fix again * no state comparison * matching spec * change target viz * comments gazelle * clear caches before test cases * latest attempts * clean up test format * remove debugging log, remove yaml * unskip attestation * remove skip, check post state, diff state diffs * handle err * add bug fixes * fixed one more bug * fixed churn limit bug * change hashProto to HashTreeRoot * all tests pass :) * fix all tests * gaz * add regression tests * fix test bug * Mutation testing fixes for beacon-chain/core/helpers/attestation.go (#2868) * mutation testing for attestation.go * new line * lint * revert fmt.Errorf deletion * gofmt * Add some fixes for mutation testing on blocks.go (#2869) * Fix sizes * gaz * Spec freeze release candidate spectests * Align Protobuf Type Names (#2872) * Removes some deprecated fields from protobuf (#2877) * search and replace checkpoints * fix tests, except spec tests * Update Configs for Freeze (#2876) * update configs * updated minimal configs * almost there * all tests passing except for spec tests * better comment for MinGenesisTime * done, ready for review * rm seconds per day * feedback * Mutation testing fixes for beacon-chain/core/helpers/committee.go (#2870) * Add some fixes for mutation testing on blocks.go * working on mutation testing fo committee.go * gofmt * goimports * update readme target * update latest sha for spec tests * fix build * Update State Transition Function (#2867) * Change Base Reward Factor (#2888) * Update Freeze Spec Simplification Section - part 1 (#2893) * finished changes to attesting_indices * removed index_count <= 2**40 requirement * lint * reverted index_count <= 2**40 check * added short cut len(a) > len(b) * Update justification bits (#2894) * updated all the helper pseudocodes (#2895) * Make Constants Explicit and Minor Cleanups (#2898) * Rename outdated configs, make constants explicitly delcared * Remove activate_validator, not needed * Remove GenesisSlot and GenesisEpoch * Remove unused import * Move Block Operation Length Checks to ProcessOperations (#2900) * Move block operation length checks to ProcessOperations * Write tests for each length check in ProcessOperations * Remove unneeded test * Move checks to a new function * Move duplicate check back into ProcessOperations * reorder proto fields (#2902) * Slashing Penalty Calculation Change (#2889) * lint * change config val * add max helper * changes to slashing and process slashing, add a min function for integers * gaz * fix failing tests * fix test * fixed all tests * Change Yaml tag * lint * remove gc hack * fix test * gaz * preston's comments * change failing field * fix and regen proto * lint * Implement Compact Committee Root (#2897) * add tags * add function * add new code * add function * add all new changes * lint * add tests * fix tests * fix more tests * fix all outstanding tests * gaz * Update beacon-chain/core/helpers/committee.go Co-Authored-By: terence tsao <terence@prysmaticlabs.com> * comment * Remove deprecated fields from attestation data (#2892) * fix broken tests * remove comment * fixes * Update Deposit Contract (#2903) * update to new contract * fix references * fix tests * fix some more tests * fix local deposit trie * gaz * shays review * more changes * update WORKSPACE to use 0.8 spec tests * Perform Mutesting in Helpers Package (#2912) * Perform mutesting on validator * Mutesting in helpers package * Mutested eth1data * s/volundary/voluntary (#2914) * Update BLS Domain (#2916) * change from integer to byte slice * add test * fix func for bytes4 * Fix Spec tests (#2907) * fix panics * handle failed transitions * remove log * fix to protos * new changes * remove i * change ssz commit * new changes * update epoch tests * fix epoch testing * fix shuffle tests * fix test * Perform Mutesting in Epoch and State Packages (#2913) * done with updates (#2890) * Add Max Size Tag for Protobuf Fields (#2908) * No more space between ssz-size numbers * Regen pb.go * Fixed a few incorrect proto fields (#2926) * Update Validator Workflow (#2906) * Justification spec tests (#2896) * update go-ssz * Fix SSZ Compatibility Test (#2924) * figuring out how to seqeeze in multiple fields in a tag for pb * Added max tags and regenerated pb.go * updated to new standard * New bitfield types in proto (#2915) * Cast bytes to correct bitfield, failing tests now though * Add forked gogo/protobuf until https://github.com/gogo/protobuf/pull/582 * remove newline * use proper override for gogo-protobuf * fix a few tags * forgot to include custody bits and Slashable not used * Update yaml struct to use pb * Update workspace to use latest ssz * All tests fail * Use the latest go-ssz commit * All pass except for state (too long to taste) * Update test.proto * Added rest of the tests * use 1 justification bits * fix tag test, apply @rauljordan's suggestion * add IsEmpty and use ssz struct * delete unused file * Update zero hash to sha256().digest() (#2932) * update zero hash * change zero hash to conform with spec * goimports * add test for zero hash * Revert "Update zero hash to sha256().digest() (#2932)" (#2933) This reverts commitb926ae0667. * Fix compress validator (#2936) * fix compress validator * update go-ssz * build without the bytes test * try minimal * Block operations spec tests (#2828) * update PrevEpoch * debugging proposer slashing tests * fmt * add deposit tests * Added skeleton for attestation minimal test * remove bazel runfiles thing * add deposits * proposer slashing test is done * comment * complete test, some failing cases * sig verify on * refactor slightly to support mainnet and minimal * included mainnet stuff * Add block header tests * volunary exit done * transfer done * new changes * fix all tests * update domain functions * fmt * fixed lint * fixed all the tests * fixed a transfer bug * finished attester slashing tests and fixed a few bugs * started fixing... * cleaned up exit and proposr slashing tests * attester slashing passing * refactored deposit tests * remove yamls, update ssz * Added todo for invalid sig * gazelle * deposits test done! * transfer tests done and pass! * fix attesting indices bug * temporarily disabled signature verification * cleaned up most of the block ops, except for att * update committee AttestingIndices * oops, i dont know how or why i changed this file * fixed all the rpc tests * 6 more failing packages * test max transfer in state package * replace hashproto with treehash in package blockchain * gazelle * fix test * fix test again * fixed transition test, 2 more left * expect an error in attestation tests * Handle panic when no votes in aggregate attestation * clear cache * Add differ, add logging, tests pass yay * remove todo, add tag * fixed TestReceiveBlock_RemovesPendingDeposits * TestAttestationMinimal/success_since_max_epochs_per_crosslink fails now... * handle panics * Transfer tests were disabled in https://github.com/ethereum/eth2.0-specs/pull/1238 * more fixes after merge, updating block_operations.yaml.go to match yaml * figuring out how to seqeeze in multiple fields in a tag for pb * Added max tags and regenerated pb.go * updated to new standard * New bitfield types in proto (#2915) * Cast bytes to correct bitfield, failing tests now though * Add forked gogo/protobuf until https://github.com/gogo/protobuf/pull/582 * remove newline * fix references and test panic * change to proto objects from custom types * fix panics in tests * use proper override for gogo-protobuf * fix a few tags * fix tests * forgot to include custody bits and Slashable not used * fix tests * sort again * Update yaml struct to use pb * Update workspace to use latest ssz * All tests fail * Use the latest go-ssz commit * All pass except for state (too long to taste) * Update test.proto * Added rest of the tests * use 1 justification bits * minor fixes * wrong proto.Equal * fix tag test, apply @rauljordan's suggestion * add IsEmpty and use ssz struct * inverted logic * update zero hash * change zero hash to conform with spec * goimports * add test for zero hash * Revert "Update zero hash to sha256().digest() (#2932)" This reverts commitb926ae0667. * update ssz, fix import, shard big test * checkpoint * fix compress validator * update go-ssz * missing import * missing import * tests now pass * been a good day * update test size * fix lint * imports and remove unused const * update bazel jobs flag * update bazel jobs flag * satisfy deprecation warning * Add ssz regression tests for investigation of test failures in PR #2828 (#2935) * Adding regression tests for investigation * add another example * goimports * add quick comment about test case 0 * Epoch Process Slashings Spec Tests (#2930) * updated justification bits, tests passing OK * regen pb.go, clarify bit operations * justification and finalization tests; failing * Add wrapper, so we call the correct method * checkpoint * Update tar ref * TestSlashingsMinimal/small_penalty still failing * Use bigint instead of () and float * Revert a bad merge from workspace * Fmt * add note about https://github.com/ethereum/eth2.0-specs/issues/1284 * improve tests * gaz * Perform Mutesting In core/state Package (#2923) * Perform mutesting on validator * Mutesting in helpers package * Mutested eth1data * Perform mutesting in epoch and state packages * Fix voluntary exits test * Fix typo * Fix comments * Fix formatting * Fix error message * Handle missing errors * Handle all errors * Perform Mutesting In State Package * Fix block roots size * Remove comment * Fix error * add backend service * Add ssz compatibility tests for signing root (#2931) * Added tests for signing root * imports * fix lint on travis * fix bes flag * Final updates spec tests (#2901) * set up tests * need to reorder pbs * figuring out how to seqeeze in multiple fields in a tag for pb * Added max tags and regenerated pb.go * updated to new standard * New bitfield types in proto (#2915) * Cast bytes to correct bitfield, failing tests now though * Add forked gogo/protobuf until https://github.com/gogo/protobuf/pull/582 * remove newline * use proper override for gogo-protobuf * fix a few tags * forgot to include custody bits and Slashable not used * playing with tags idea, can revert this commit later * fixes after merge * reset caches before test * all epoch tests pass * gazelle * Genesis trigger (#2905) * genesis change * integrate changes * bodyroot * remove unused code * HasChainStarted * added isValidGenesisState to ProcessLog * state fix * fix gazelle * uint64 timestamp * SetupInitialDeposits adds proof * remove unneeded parts of test * deposithash * merkleproof from spec utils * Revert "merkleproof from spec utils" This reverts commit1b0a124352. * fix test failures * chain started and hashtree root in tests * simple eth2genesistime * eth2 genesis time * fix zero time * add comment * remove eth1data and feedback * fix build issues * main changes: add fields and methods to track active validator count * gaz * fix test * fix more tests * improve test utils * shift spec method to state package, improve test setup * fixed log processing tests * remove log * gaz * fix invalid metric * use better tag names, not latest * Remove Block Signing Root (#2945) * replace with hash tree root * Revert "replace with hash tree root" This reverts commit77d8f16a16. * replace with signing root instead * remove one more ref * Create Test Runner for Genesis State Spec Tests (#2940) * genesis change * integrate changes * bodyroot * remove unused code * HasChainStarted * added isValidGenesisState to ProcessLog * state fix * fix gazelle * uint64 timestamp * SetupInitialDeposits adds proof * remove unneeded parts of test * deposithash * merkleproof from spec utils * Revert "merkleproof from spec utils" This reverts commit1b0a124352. * fix test failures * chain started and hashtree root in tests * simple eth2genesistime * eth2 genesis time * fix zero time * add comment * remove eth1data and feedback * fix build issues * main changes: add fields and methods to track active validator count * gaz * fix test * fix more tests * improve test utils * Start genesis spec tests * shift spec method to state package, improve test setup * Add Genesis validity spec test * Bazel * fixed log processing tests * remove log * gaz * fix invalid metric * use json tags * fix up latest changes * Fix most of test errors * Attempts to see whats wrong with genesis validity * Fix merge * skip minimal * fix state test * new commit * fix nishant comment * gaz * Static check on branch spec-v0.6 (#2946) * Ran staticcheck and fixed the important complains * commit * commit * Create Test Runner for Genesis State Spec Tests (#2940) * genesis change * integrate changes * bodyroot * remove unused code * HasChainStarted * added isValidGenesisState to ProcessLog * state fix * fix gazelle * uint64 timestamp * SetupInitialDeposits adds proof * remove unneeded parts of test * deposithash * merkleproof from spec utils * Revert "merkleproof from spec utils" This reverts commit1b0a124352. * fix test failures * chain started and hashtree root in tests * simple eth2genesistime * eth2 genesis time * fix zero time * add comment * remove eth1data and feedback * fix build issues * main changes: add fields and methods to track active validator count * gaz * fix test * fix more tests * improve test utils * Start genesis spec tests * shift spec method to state package, improve test setup * Add Genesis validity spec test * Bazel * fixed log processing tests * remove log * gaz * fix invalid metric * use json tags * fix up latest changes * Fix most of test errors * Attempts to see whats wrong with genesis validity * Fix merge * skip minimal * fix state test * new commit * fix nishant comment * gaz * Add Back Eth1Data After Bad Merge (#2953) * eth1data rpc endpoint * first version * comment added * gazelle fix * new function to go once over the deposit array * fix tests * export DepositContainer * terence feedback * move structure decleration * binary search * fix block into Block * preston feedback * keep slice sorted to remove overhead in retrival * merge changes * feedback * update to the latest go-ssz * revert change * chnages to fit new ssz * revert merge reversion * go fmt goimprts duplicate string * exception for lint unused doesParentExist * feedback changes * latesteth1data to eth1data * goimports and stop exposing Eth1Data * revert unneeded change * remove exposure of DepositContainer * feedback and fixes * fix workspace duplicate dependancy * greatest number of deposits at current height * add count votes function * change method name * revert back to latesteth1data * latesteth1data * preston feedback * seperate function add tests fix bug * stop exposing voteCountMap * eth1data comment fix * preston feedback * fix tests * new proto files * workspace to default version of ssz * new ssz * chnage test size * marshalled marshaled * everything passing again * add skip reason * cleanup deposit contract slightly * remove unused chainstart param (#2957) * fix breakages from #2957 (#2958) * fix breakages from #2957 * oops * Fix deposit input data (#2956) * fix deposit input data * fix deposit input data * gaz and build fix * Add Tests for Genesis Deposits Caching (#2952) * remove old method and replace with an improved one * add new files * gaz * add test * added all these tests * gaz * Apply suggestions from code review Co-Authored-By: terence tsao <terence@prysmaticlabs.com> * fix merkle proof error * fix config * Minor fixes for runtime (#2960) * Minor fixes for runtime * use comments * goimports * revert beacon-chain/core/state/state.go and fix comment for lint * fix test too * Minor runtime fixes (#2961) * Add support for bundling binaries and fix ARM64 builds (#2970) * Add support for bundling binaries and fix ARM64 builds * Fix exports * ignore manual targets wrt vis check * fix graknlabs * update spec tests (#2979) * hotfix until https://github.com/graknlabs/bazel-distribution/pull/169 * Overflow slashing calculation fix (#2977) * Runtime Fixes (#2736) * first batch of fixes * add log * more fixes * another bug fixed * update deposit contract and other fixes * remove logs * new changes * fixes * fix build * remove config * more fixes * add more changes * add back todo * make compute state root work * remove commented out and fix condition * fix commented code * fix config * gaz * remove flag * remove init * new fixes * fix test * one more fix * fix all tests * change back config * fix one more bug * remove logging bool * Only build test targets when running bazel test //... * Align prysm to spec v0.8.1 (#2978) * Bazel problem * Update zero hash representation to be clear (cosmetic) * Update minor cosmetic fixes * Fixed lookahead off by 1 * Update randao.go * update ssz * test failures fixed * test fixes * fix up workspace * lint * fixed errs * Updated pubkey loggings (#2983) * Fix proposer assignment (#2984) * add jvm limits * add jvm limits * Removed logging from state transition functions (#2980) * Match spec on proposer index division (#2985) * Match spec on proposer index division * gaz * fixes * Fix Default Eth1Data (#2982) * fix bug * Update beacon-chain/core/state/transition.go Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com> * more fixes * reg test * Set ejection balance to 1.6 (#2987) * improve block processing log (#2990) * Fix HistoricalRootsLimit (#2989) * fix historical lenght * fix genesis state initialization and test * fix genesis state initialization and test * fix genesis state initialization and test * fix genesis state initialization and test * hack config until https://github.com/prysmaticlabs/prysm/issues/2993 * More Runtime Fixes (#2986) * local changes * add val sig * attester fix * one more fix * fixed all tests * rem validator issue * fix finality issue (#2994) * Fix validator prev balance calculation (#2992) * attester fix * one more fix * fixed all tests * Fix validator prev balances calculation * go fmt * 48 bytes * Fix Querier to handle Deposit Logs Race (#2999) * fix sync issue * fix build * add regression test * add var for magic number * Fix eth1data and deposits (#2996) * Work in progress, eth1data works, deposits are included at the appropriate time, and activation happens at the correct time * revert blockInfo being public * git tests to build, not yet pass though * add tests * some commentary * fix comment * goimports * fmt and remove unused method * Update rules go (#2975) * update rules_go * Fix some cross compile builds stuff * add missing deps * update to 0.19.1 * Update Protobufs to Match Ethereum APIs (#2998) * add beacon block and attestation files * add all types * include all new proto type definitions * add add all proto definitions * fix all comments to say 48 bytes * include latest changes * readd common * no swag * add build file * deps issue * right package names * address feedback, maintain parity between upstream ethereumapis * delete pb * bad gens * Update "Testing Prysm" readme section (#3000) Resolves invalid url link to golangci-lint. * Update badge to version 0.8.1 * elaborate on test skip * revert shared/p2p/options.go * make travis happy with goimports * Update beacon-chain/core/blocks/block.go Co-Authored-By: Preston Van Loon <preston@prysmaticlabs.com>
This commit is contained in:
committed by
Raul Jordan
parent
d8e24af4c3
commit
e744d1a07e
3
.bazelrc
3
.bazelrc
@@ -1,5 +1,8 @@
|
||||
# Print warnings for tests with inappropriate test size or timeout.
|
||||
test --test_verbose_timeout_warnings
|
||||
|
||||
# Only build test targets when running bazel test //...
|
||||
test --build_tests_only
|
||||
|
||||
# Fix for rules_docker. See: https://github.com/bazelbuild/rules_docker/issues/842
|
||||
build --host_force_python=PY2
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
# across machines, developers, and workspaces.
|
||||
#
|
||||
# This config is loaded from https://github.com/bazelbuild/bazel-toolchains/blob/master/bazelrc/latest.bazelrc
|
||||
build:remote-cache --remote_cache=remotebuildexecution.googleapis.com
|
||||
build:remote-cache --tls_enabled=true
|
||||
build:remote-cache --remote_cache=grpcs://remotebuildexecution.googleapis.com
|
||||
build:remote-cache --remote_timeout=3600
|
||||
build:remote-cache --auth_enabled=true
|
||||
build:remote-cache --spawn_strategy=standalone
|
||||
@@ -11,15 +10,26 @@ build:remote-cache --strategy=Javac=standalone
|
||||
build:remote-cache --strategy=Closure=standalone
|
||||
build:remote-cache --strategy=Genrule=standalone
|
||||
|
||||
# Build results backend.
|
||||
build:remote-cache --bes_results_url="https://source.cloud.google.com/results/invocations/"
|
||||
build:remote-cache --bes_backend=buildeventservice.googleapis.com
|
||||
build:remote-cache --bes_timeout=60s
|
||||
build:remote-cache --project_id=prysmaticlabs
|
||||
build:remote-cache --bes_upload_mode=fully_async
|
||||
|
||||
# Prysm specific remote-cache properties.
|
||||
build:remote-cache --disk_cache=
|
||||
build:remote-cache --jobs=50
|
||||
build:remote-cache --host_platform_remote_properties_override='properties:{name:\"cache-silo-key\" value:\"prysm\"}'
|
||||
build:remote-cache --remote_instance_name=projects/prysmaticlabs/instances/default_instance
|
||||
|
||||
build:remote-cache --experimental_remote_download_outputs=minimal
|
||||
build:remote-cache --experimental_inmemory_jdeps_files
|
||||
build:remote-cache --experimental_inmemory_dotd_files
|
||||
|
||||
# Import workspace options.
|
||||
import %workspace%/.bazelrc
|
||||
|
||||
startup --host_jvm_args=-Xmx1000m --host_jvm_args=-Xms1000m
|
||||
build --experimental_strict_action_env
|
||||
build --disk_cache=/tmp/bazelbuilds
|
||||
build --experimental_multi_threaded_digest
|
||||
@@ -31,5 +41,8 @@ build --curses=yes --color=yes
|
||||
build --keep_going
|
||||
build --test_output=errors
|
||||
build --flaky_test_attempts=5
|
||||
build --jobs=50
|
||||
build --stamp
|
||||
test --local_test_jobs=2
|
||||
# Disabled race detection due to unstable test results under constrained environment build kite
|
||||
# build --features=race
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"extends": "solium:recommended",
|
||||
"plugins": [
|
||||
"security"
|
||||
],
|
||||
"rules": {
|
||||
"quotes": [
|
||||
"error",
|
||||
"double"
|
||||
],
|
||||
"security/no-inline-assembly": ["warning"],
|
||||
|
||||
"indentation": [
|
||||
"error",
|
||||
4
|
||||
]
|
||||
}
|
||||
}
|
||||
37
BUILD.bazel
37
BUILD.bazel
@@ -3,10 +3,14 @@ load("@com_github_atlassian_bazel_tools//gometalinter:def.bzl", "gometalinter")
|
||||
load("@com_github_atlassian_bazel_tools//goimports:def.bzl", "goimports")
|
||||
load("@io_kubernetes_build//defs:run_in_workspace.bzl", "workspace_binary")
|
||||
load("@io_bazel_rules_go//go:def.bzl", "nogo")
|
||||
load("@graknlabs_bazel_distribution//common:rules.bzl", "assemble_targz", "assemble_versioned")
|
||||
load("//tools:binary_targets.bzl", "binary_targets", "determine_targets")
|
||||
|
||||
prefix = "github.com/prysmaticlabs/prysm"
|
||||
|
||||
exports_files(["genesis.json"])
|
||||
exports_files([
|
||||
"LICENSE.md",
|
||||
])
|
||||
|
||||
# gazelle:prefix github.com/prysmaticlabs/prysm
|
||||
gazelle(
|
||||
@@ -108,3 +112,34 @@ nogo(
|
||||
"@org_golang_x_tools//go/analysis/passes/asmdecl:go_tool_library",
|
||||
],
|
||||
)
|
||||
|
||||
assemble_versioned(
|
||||
name = "assemble-versioned-all",
|
||||
tags = ["manual"],
|
||||
targets = [
|
||||
":assemble-{}-{}-targz".format(
|
||||
pair[0],
|
||||
pair[1],
|
||||
)
|
||||
for pair in binary_targets
|
||||
],
|
||||
version_file = "//:VERSION",
|
||||
)
|
||||
|
||||
common_files = {
|
||||
"//:LICENSE.md": "LICENSE.md",
|
||||
"//:README.md": "README.md",
|
||||
}
|
||||
|
||||
[assemble_targz(
|
||||
name = "assemble-{}-{}-targz".format(
|
||||
pair[0],
|
||||
pair[1],
|
||||
),
|
||||
additional_files = determine_targets(pair, common_files),
|
||||
output_filename = "prysm-{}-{}".format(
|
||||
pair[0],
|
||||
pair[1],
|
||||
),
|
||||
tags = ["manual"],
|
||||
) for pair in binary_targets]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Prysm: Ethereum 'Serenity' 2.0 Go Implementation
|
||||
|
||||
[](https://buildkite.com/prysmatic-labs/prysm)
|
||||
[](https://github.com/ethereum/eth2.0-specs/commit/452ecf8e27c7852c7854597f2b1bb4a62b80c7ec)
|
||||
[](https://discord.gg/KSA7rPr)
|
||||
[](https://gitter.im/prysmaticlabs/geth-sharding?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||
@@ -132,7 +133,7 @@ bazel run //validator
|
||||
bazel test //...
|
||||
```
|
||||
|
||||
**To run our linter**, make sure you have [golangci-lint](https://https://github.com/golangci/golangci-lint) installed and then issue the command:
|
||||
**To run our linter**, make sure you have [golangci-lint](https://github.com/golangci/golangci-lint) installed and then issue the command:
|
||||
```
|
||||
golangci-lint run
|
||||
```
|
||||
|
||||
156
WORKSPACE
156
WORKSPACE
@@ -1,4 +1,5 @@
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||
|
||||
http_archive(
|
||||
name = "bazel_skylib",
|
||||
@@ -9,8 +10,11 @@ http_archive(
|
||||
|
||||
http_archive(
|
||||
name = "io_bazel_rules_go",
|
||||
sha256 = "f04d2373bcaf8aa09bccb08a98a57e721306c8f6043a2a0ee610fd6853dcde3d",
|
||||
url = "https://github.com/bazelbuild/rules_go/releases/download/0.18.6/rules_go-0.18.6.tar.gz",
|
||||
sha256 = "8df59f11fb697743cbb3f26cfb8750395f30471e9eabde0d174c3aebc7a1cd39",
|
||||
urls = [
|
||||
"https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/0.19.1/rules_go-0.19.1.tar.gz",
|
||||
"https://github.com/bazelbuild/rules_go/releases/download/0.19.1/rules_go-0.19.1.tar.gz",
|
||||
],
|
||||
)
|
||||
|
||||
http_archive(
|
||||
@@ -46,6 +50,28 @@ http_archive(
|
||||
url = "https://github.com/bazelbuild/rules_k8s/archive/e68d5d765c2c670943a0baeb04ad8d9cb3661e54.tar.gz",
|
||||
)
|
||||
|
||||
git_repository(
|
||||
name = "graknlabs_bazel_distribution",
|
||||
commit = "fe1e3a8253158c9a766ad76c502ee7a4aa4e39a5",
|
||||
# Update this after https://github.com/graknlabs/bazel-distribution/pull/169 is merged.
|
||||
remote = "https://github.com/prestonvanloon/bazel-distribution",
|
||||
)
|
||||
|
||||
# Override default import in rules_go with special patch until
|
||||
# https://github.com/gogo/protobuf/pull/582 is merged.
|
||||
git_repository(
|
||||
name = "com_github_gogo_protobuf",
|
||||
commit = "ba06b47c162d49f2af050fb4c75bcbc86a159d5c", # v1.2.1, as of 2019-03-03
|
||||
patch_args = ["-p1"],
|
||||
patches = [
|
||||
"@io_bazel_rules_go//third_party:com_github_gogo_protobuf-gazelle.patch",
|
||||
"//third_party:com_github_gogo_protobuf-equal.patch",
|
||||
],
|
||||
remote = "https://github.com/gogo/protobuf",
|
||||
shallow_since = "1550471403 +0200",
|
||||
# gazelle args: -go_prefix github.com/gogo/protobuf -proto legacy
|
||||
)
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_docker//repositories:repositories.bzl",
|
||||
container_repositories = "repositories",
|
||||
@@ -53,16 +79,6 @@ load(
|
||||
|
||||
container_repositories()
|
||||
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "node_repositories", "yarn_install")
|
||||
|
||||
node_repositories()
|
||||
|
||||
yarn_install(
|
||||
name = "npm",
|
||||
package_json = "//:package.json",
|
||||
yarn_lock = "//:yarn.lock",
|
||||
)
|
||||
|
||||
# This requires rules_docker to be fully instantiated before it is pulled in.
|
||||
load("@io_bazel_rules_k8s//k8s:k8s.bzl", "k8s_defaults", "k8s_repositories")
|
||||
|
||||
@@ -140,8 +156,8 @@ filegroup(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
""",
|
||||
sha256 = "56847989737e816ab7d23f3bb2422347dfa81271bae81a94de512c01461fab25",
|
||||
url = "https://github.com/prysmaticlabs/eth2.0-spec-tests/releases/download/v0.7.1/base64_encoded_archive.tar.gz",
|
||||
sha256 = "a531804ac35d2398d37cfa755a686280d8cb3a9649e993e3cf89640f06191d5e",
|
||||
url = "https://github.com/prysmaticlabs/eth2.0-spec-tests/releases/download/v0.8.1/base64_encoded_archive.tar.gz",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
@@ -154,28 +170,28 @@ load("@com_github_bazelbuild_buildtools//buildifier:deps.bzl", "buildifier_depen
|
||||
|
||||
buildifier_dependencies()
|
||||
|
||||
http_archive(
|
||||
name = "com_github_prysmaticlabs_go_ssz",
|
||||
sha256 = "f6fd5d623a988337810b956ddaf612dce771d9d0f9256934c8f4b1379f1cb2f6",
|
||||
strip_prefix = "go-ssz-2e84733edbac32aca6d47feafc4441e43b10047f",
|
||||
url = "https://github.com/prysmaticlabs/go-ssz/archive/2e84733edbac32aca6d47feafc4441e43b10047f.tar.gz",
|
||||
)
|
||||
|
||||
load("@com_github_prysmaticlabs_go_ssz//:deps.bzl", "go_ssz_dependencies")
|
||||
|
||||
go_ssz_dependencies()
|
||||
|
||||
go_repository(
|
||||
name = "com_github_golang_mock",
|
||||
commit = "51421b967af1f557f93a59e0057aaf15ca02e29c", # v1.2.0
|
||||
importpath = "github.com/golang/mock",
|
||||
)
|
||||
|
||||
git_repository(
|
||||
name = "com_google_protobuf",
|
||||
commit = "09745575a923640154bcf307fba8aedff47f240a",
|
||||
remote = "https://github.com/protocolbuffers/protobuf",
|
||||
shallow_since = "1558721209 -0700",
|
||||
)
|
||||
|
||||
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
|
||||
|
||||
protobuf_deps()
|
||||
|
||||
# External dependencies
|
||||
|
||||
go_repository(
|
||||
name = "com_github_ethereum_go_ethereum",
|
||||
commit = "099afb3fd89784f9e3e594b7c2ed11335ca02a9b",
|
||||
commit = "981f27aaf9bdce45391d0cd8bb522df514e0b566",
|
||||
importpath = "github.com/ethereum/go-ethereum",
|
||||
# Note: go-ethereum is not bazel-friendly with regards to cgo. We have a
|
||||
# a fork that has resolved these issues by disabling HID/USB support and
|
||||
@@ -186,6 +202,12 @@ go_repository(
|
||||
vcs = "git",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_prysmaticlabs_go_ssz",
|
||||
commit = "ecf08adca3c19f69aea911fcde9b5e71d6bbfe28",
|
||||
importpath = "github.com/prysmaticlabs/go-ssz",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_urfave_cli",
|
||||
commit = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1", # v1.20.0
|
||||
@@ -502,7 +524,7 @@ go_repository(
|
||||
|
||||
go_repository(
|
||||
name = "org_golang_x_sys",
|
||||
commit = "a34e9553db1e492c9a76e60db2296ae7e5fbb772",
|
||||
commit = "fae7ac547cb717d141c433a2a173315e216b64c4",
|
||||
importpath = "golang.org/x/sys",
|
||||
)
|
||||
|
||||
@@ -538,7 +560,7 @@ go_repository(
|
||||
|
||||
go_repository(
|
||||
name = "org_golang_x_crypto",
|
||||
commit = "8dd112bcdc25174059e45e07517d9fc663123347",
|
||||
commit = "4def268fd1a49955bfb3dda92fe3db4f924f2285",
|
||||
importpath = "golang.org/x/crypto",
|
||||
)
|
||||
|
||||
@@ -807,6 +829,7 @@ go_repository(
|
||||
|
||||
go_repository(
|
||||
name = "io_k8s_client_go",
|
||||
build_extra_args = ["-exclude=vendor"],
|
||||
commit = "8abb21031259350aad0799bb42ba213ee8bb3399",
|
||||
importpath = "k8s.io/client-go",
|
||||
)
|
||||
@@ -1103,3 +1126,80 @@ go_repository(
|
||||
commit = "4afad1f6206cb9222914f2ec6ab9d0b414705c54", # v0.0.3
|
||||
importpath = "github.com/libp2p/go-eventbus",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "in_gopkg_d4l3k_messagediff_v1",
|
||||
commit = "29f32d820d112dbd66e58492a6ffb7cc3106312b",
|
||||
importpath = "gopkg.in/d4l3k/messagediff.v1",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_prysmaticlabs_go_bitfield",
|
||||
commit = "ec88cc4d1d143cad98308da54b73d0cdb04254eb",
|
||||
importpath = "github.com/prysmaticlabs/go-bitfield",
|
||||
)
|
||||
|
||||
load("@com_github_prysmaticlabs_go_ssz//:deps.bzl", "go_ssz_dependencies")
|
||||
|
||||
go_ssz_dependencies()
|
||||
|
||||
go_repository(
|
||||
name = "com_github_burntsushi_toml",
|
||||
commit = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005",
|
||||
importpath = "github.com/BurntSushi/toml",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "org_golang_google_grpc",
|
||||
build_file_proto_mode = "disable",
|
||||
commit = "24b2fb8959201be9ce659bc87b0d590a34c67eae",
|
||||
importpath = "google.golang.org/grpc",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "org_golang_x_net",
|
||||
commit = "da137c7871d730100384dbcf36e6f8fa493aef5b",
|
||||
importpath = "golang.org/x/net",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "org_golang_x_text",
|
||||
commit = "342b2e1fbaa52c93f31447ad2c6abc048c63e475",
|
||||
importpath = "golang.org/x/text",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_golang_glog",
|
||||
commit = "23def4e6c14b4da8ac2ed8007337bc5eb5007998",
|
||||
importpath = "github.com/golang/glog",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "org_golang_x_time",
|
||||
commit = "9d24e82272b4f38b78bc8cff74fa936d31ccd8ef",
|
||||
importpath = "golang.org/x/time",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_gregjones_httpcache",
|
||||
commit = "901d90724c7919163f472a9812253fb26761123d",
|
||||
importpath = "github.com/gregjones/httpcache",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_peterbourgon_diskv",
|
||||
commit = "0be1b92a6df0e4f5cb0a5d15fb7f643d0ad93ce6",
|
||||
importpath = "github.com/peterbourgon/diskv",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_googleapis_gnostic",
|
||||
commit = "25d8b0b6698593f520d9d8dc5a88e6b16ca9ecc0",
|
||||
importpath = "github.com/googleapis/gnostic",
|
||||
)
|
||||
|
||||
go_repository(
|
||||
name = "com_github_google_btree",
|
||||
commit = "20236160a414454a9c64b6c8829381c6f4bddcaa",
|
||||
importpath = "github.com/google/btree",
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
|
||||
load("@io_bazel_rules_docker//go:image.bzl", "go_image")
|
||||
load("@io_bazel_rules_docker//container:container.bzl", "container_push")
|
||||
load("//tools:binary_targets.bzl", "binary_targets")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
@@ -64,7 +65,7 @@ container_push(
|
||||
image = ":image",
|
||||
registry = "gcr.io",
|
||||
repository = "prysmaticlabs/prysm/beacon-chain",
|
||||
tag = "latest",
|
||||
tag = "{DOCKER_TAG}",
|
||||
tags = ["manual"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
@@ -82,3 +83,15 @@ go_test(
|
||||
embed = [":go_default_library"],
|
||||
deps = ["@com_github_urfave_cli//:go_default_library"],
|
||||
)
|
||||
|
||||
[go_binary(
|
||||
name = "beacon-chain-{}-{}".format(
|
||||
pair[0],
|
||||
pair[1],
|
||||
),
|
||||
embed = [":go_default_library"],
|
||||
goarch = pair[1],
|
||||
goos = pair[0],
|
||||
tags = ["manual"],
|
||||
visibility = ["//visibility:public"],
|
||||
) for pair in binary_targets]
|
||||
|
||||
@@ -9,15 +9,11 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/attestation",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/state:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bitutil:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/event:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/messagehandler:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
@@ -33,13 +29,13 @@ go_test(
|
||||
srcs = ["service_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/internal:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
],
|
||||
|
||||
@@ -4,26 +4,20 @@ package attestation
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bitutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/event"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
handler "github.com/prysmaticlabs/prysm/shared/messagehandler"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "attestation")
|
||||
var committeeCache = cache.NewCommitteesCache()
|
||||
|
||||
// TargetHandler provides an interface for fetching latest attestation targets
|
||||
// and updating attestations in batches.
|
||||
@@ -87,7 +81,7 @@ func (a *Service) Stop() error {
|
||||
}
|
||||
|
||||
// Status always returns nil.
|
||||
// TODO(1201): Add service health checks.
|
||||
// TODO(#1201): Add service health checks.
|
||||
func (a *Service) Status() error {
|
||||
return nil
|
||||
}
|
||||
@@ -106,10 +100,10 @@ func (a *Service) IncomingAttestationFeed() *event.Feed {
|
||||
// BeaconBlock` be the target block in the attestation
|
||||
// `get_latest_attestation(store, validator_index)`.
|
||||
func (a *Service) LatestAttestationTarget(beaconState *pb.BeaconState, index uint64) (*pb.AttestationTarget, error) {
|
||||
if index >= uint64(len(beaconState.ValidatorRegistry)) {
|
||||
if index >= uint64(len(beaconState.Validators)) {
|
||||
return nil, fmt.Errorf("invalid validator index %d", index)
|
||||
}
|
||||
validator := beaconState.ValidatorRegistry[index]
|
||||
validator := beaconState.Validators[index]
|
||||
|
||||
pubKey := bytesutil.ToBytes48(validator.Pubkey)
|
||||
a.store.RLock()
|
||||
@@ -122,7 +116,7 @@ func (a *Service) LatestAttestationTarget(beaconState *pb.BeaconState, index uin
|
||||
if attestation == nil {
|
||||
return nil, nil
|
||||
}
|
||||
targetRoot := bytesutil.ToBytes32(attestation.Data.BeaconBlockRootHash32)
|
||||
targetRoot := bytesutil.ToBytes32(attestation.Data.BeaconBlockRoot)
|
||||
if !a.beaconDB.HasBlock(targetRoot) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -162,11 +156,14 @@ func (a *Service) handleAttestation(ctx context.Context, msg proto.Message) erro
|
||||
// This sets the pool limit, once the old pool is cleared out. It does by using the number of active
|
||||
// validators per slot as an estimate. The active indices here are not used in the actual processing
|
||||
// of attestations.
|
||||
activeIndices := helpers.ActiveValidatorIndices(state.ValidatorRegistry, helpers.CurrentEpoch(state))
|
||||
attPerSlot := len(activeIndices) / int(params.BeaconConfig().SlotsPerEpoch)
|
||||
count, err := helpers.ActiveValidatorCount(state, helpers.CurrentEpoch(state))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attPerSlot := count / params.BeaconConfig().SlotsPerEpoch
|
||||
// we only set the limit at 70% of the calculated amount to be safe so that relevant attestations
|
||||
// arent carried over to the next batch.
|
||||
a.poolLimit = attPerSlot * 7 / 10
|
||||
a.poolLimit = int(attPerSlot) * 7 / 10
|
||||
if a.poolLimit == 0 {
|
||||
a.poolLimit++
|
||||
}
|
||||
@@ -190,15 +187,7 @@ func (a *Service) UpdateLatestAttestation(ctx context.Context, attestation *pb.A
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
head, err := a.beaconDB.ChainHead()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
headRoot, err := hashutil.HashBeaconBlock(head)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return a.updateAttestation(ctx, headRoot, beaconState, attestation)
|
||||
return a.updateAttestation(beaconState, attestation)
|
||||
}
|
||||
|
||||
// BatchUpdateLatestAttestation updates multiple attestations and adds them into the attestation store
|
||||
@@ -214,19 +203,9 @@ func (a *Service) BatchUpdateLatestAttestation(ctx context.Context, attestations
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
head, err := a.beaconDB.ChainHead()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
headRoot, err := hashutil.HashBeaconBlock(head)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
attestations = a.sortAttestations(attestations)
|
||||
|
||||
for _, attestation := range attestations {
|
||||
if err := a.updateAttestation(ctx, headRoot, beaconState, attestation); err != nil {
|
||||
if err := a.updateAttestation(beaconState, attestation); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -242,91 +221,53 @@ func (a *Service) InsertAttestationIntoStore(pubkey [48]byte, att *pb.Attestatio
|
||||
a.store.m[pubkey] = att
|
||||
}
|
||||
|
||||
func (a *Service) updateAttestation(ctx context.Context, headRoot [32]byte, beaconState *pb.BeaconState,
|
||||
attestation *pb.Attestation) error {
|
||||
func (a *Service) updateAttestation(beaconState *pb.BeaconState, attestation *pb.Attestation) error {
|
||||
totalAttestationSeen.Inc()
|
||||
|
||||
slot := attestation.Data.Slot
|
||||
var committee []uint64
|
||||
var cachedCommittees *cache.CommitteesInSlot
|
||||
var err error
|
||||
|
||||
for beaconState.Slot < slot {
|
||||
beaconState, err = state.ExecuteStateTransition(
|
||||
ctx, beaconState, nil /* block */, headRoot, state.DefaultConfig(),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not execute head transition: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
cachedCommittees, err = committeeCache.CommitteesInfoBySlot(slot)
|
||||
committee, err := helpers.CrosslinkCommittee(beaconState, helpers.CurrentEpoch(beaconState), attestation.Data.Crosslink.Shard)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cachedCommittees == nil {
|
||||
crosslinkCommittees, err := helpers.CrosslinkCommitteesAtSlot(beaconState, slot, false /* registryChange */)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cachedCommittees = helpers.ToCommitteeCache(slot, crosslinkCommittees)
|
||||
if err := committeeCache.AddCommittees(cachedCommittees); err != nil {
|
||||
return err
|
||||
}
|
||||
slot, err := helpers.AttestationDataSlot(beaconState, attestation.Data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get attestation slot: %v", err)
|
||||
}
|
||||
|
||||
// Find committee for shard.
|
||||
for _, v := range cachedCommittees.Committees {
|
||||
if v.Shard == attestation.Data.Shard {
|
||||
committee = v.Committee
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"attestationSlot": attestation.Data.Slot - params.BeaconConfig().GenesisSlot,
|
||||
"attestationShard": attestation.Data.Shard,
|
||||
"committeesShard": cachedCommittees.Committees[0].Shard,
|
||||
"committeesList": cachedCommittees.Committees[0].Committee,
|
||||
"lengthOfCommittees": len(cachedCommittees.Committees),
|
||||
"attestationSlot": slot,
|
||||
"attestationShard": attestation.Data.Crosslink.Shard,
|
||||
"committeesList": committee,
|
||||
"lengthOfCommittees": len(committee),
|
||||
}).Debug("Updating latest attestation")
|
||||
|
||||
// The participation bitfield from attestation is represented in bytes,
|
||||
// here we multiply by 8 to get an accurate validator count in bits.
|
||||
bitfield := attestation.AggregationBitfield
|
||||
totalBits := len(bitfield) * 8
|
||||
|
||||
// Check each bit of participation bitfield to find out which
|
||||
// attester has submitted new attestation.
|
||||
// This is has O(n) run time and could be optimized down the line.
|
||||
for i := 0; i < totalBits; i++ {
|
||||
bitSet, err := bitutil.CheckBit(bitfield, i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bitSet {
|
||||
for i := uint64(0); i < attestation.AggregationBits.Len(); i++ {
|
||||
if !attestation.AggregationBits.BitAt(i) {
|
||||
continue
|
||||
}
|
||||
|
||||
if i >= len(committee) {
|
||||
log.Debugf("bitfield points to an invalid index in the committee: bitfield %08b", bitfield)
|
||||
if i >= uint64(len(committee)) {
|
||||
// This should never happen.
|
||||
log.Warnf("bitfield points to an invalid index in the committee: bitfield %08b", attestation.AggregationBits)
|
||||
return nil
|
||||
}
|
||||
|
||||
if int(committee[i]) >= len(beaconState.ValidatorRegistry) {
|
||||
log.Debugf("index doesn't exist in validator registry: index %d", committee[i])
|
||||
if int(committee[i]) >= len(beaconState.Validators) {
|
||||
// This should never happen.
|
||||
log.Warnf("index doesn't exist in validator registry: index %d", committee[i])
|
||||
return nil
|
||||
}
|
||||
|
||||
// If the attestation came from this attester. We use the slot committee to find the
|
||||
// validator's actual index.
|
||||
pubkey := bytesutil.ToBytes48(beaconState.ValidatorRegistry[committee[i]].Pubkey)
|
||||
newAttestationSlot := attestation.Data.Slot
|
||||
pubkey := bytesutil.ToBytes48(beaconState.Validators[committee[i]].Pubkey)
|
||||
newAttestationSlot := slot
|
||||
currentAttestationSlot := uint64(0)
|
||||
a.store.Lock()
|
||||
defer a.store.Unlock()
|
||||
if _, exists := a.store.m[pubkey]; exists {
|
||||
currentAttestationSlot = a.store.m[pubkey].Data.Slot
|
||||
currentAttestationSlot = slot
|
||||
}
|
||||
// If the attestation is newer than this attester's one in pool.
|
||||
if newAttestationSlot > currentAttestationSlot {
|
||||
@@ -334,12 +275,12 @@ func (a *Service) updateAttestation(ctx context.Context, headRoot [32]byte, beac
|
||||
|
||||
log.WithFields(
|
||||
logrus.Fields{
|
||||
"attestationSlot": attestation.Data.Slot - params.BeaconConfig().GenesisSlot,
|
||||
"justifiedEpoch": attestation.Data.JustifiedEpoch - params.BeaconConfig().GenesisEpoch,
|
||||
"attestationSlot": slot,
|
||||
"sourceEpoch": attestation.Data.Source.Epoch,
|
||||
},
|
||||
).Debug("Attestation store updated")
|
||||
|
||||
blockRoot := bytesutil.ToBytes32(attestation.Data.BeaconBlockRootHash32)
|
||||
blockRoot := bytesutil.ToBytes32(attestation.Data.BeaconBlockRoot)
|
||||
votedBlock, err := a.beaconDB.Block(blockRoot)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -349,12 +290,3 @@ func (a *Service) updateAttestation(ctx context.Context, headRoot [32]byte, beac
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// sortAttestations sorts attestations by their slot number in ascending order.
|
||||
func (a *Service) sortAttestations(attestations []*pb.Attestation) []*pb.Attestation {
|
||||
sort.SliceStable(attestations, func(i, j int) bool {
|
||||
return attestations[i].Data.Slot < attestations[j].Data.Slot
|
||||
})
|
||||
|
||||
return attestations
|
||||
}
|
||||
|
||||
@@ -4,15 +4,14 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/internal"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -34,63 +33,67 @@ func TestUpdateLatestAttestation_UpdatesLatest(t *testing.T) {
|
||||
for i := 0; i < 64; i++ {
|
||||
validators = append(validators, &pb.Validator{
|
||||
Pubkey: []byte{byte(i)},
|
||||
ActivationEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
ExitEpoch: params.BeaconConfig().GenesisEpoch + 10,
|
||||
ActivationEpoch: 0,
|
||||
ExitEpoch: 10,
|
||||
})
|
||||
}
|
||||
|
||||
beaconState := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
ValidatorRegistry: validators,
|
||||
Slot: 1,
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
ActiveIndexRoots: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
}
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
Slot: 1,
|
||||
}
|
||||
if err := beaconDB.SaveBlock(block); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.LatestBlock = block
|
||||
if err := beaconDB.UpdateChainHead(ctx, block, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
service := NewAttestationService(context.Background(), &Config{BeaconDB: beaconDB})
|
||||
|
||||
attestation := &pb.Attestation{
|
||||
AggregationBitfield: []byte{0x80},
|
||||
AggregationBits: bitfield.Bitlist{0x03},
|
||||
Data: &pb.AttestationData{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
Shard: 1,
|
||||
Crosslink: &pb.Crosslink{
|
||||
Shard: 1,
|
||||
},
|
||||
Target: &pb.Checkpoint{},
|
||||
Source: &pb.Checkpoint{},
|
||||
},
|
||||
}
|
||||
|
||||
if err := service.UpdateLatestAttestation(ctx, attestation); err != nil {
|
||||
t.Fatalf("could not update latest attestation: %v", err)
|
||||
}
|
||||
pubkey := bytesutil.ToBytes48([]byte{byte(3)})
|
||||
if service.store.m[pubkey].Data.Slot !=
|
||||
attestation.Data.Slot {
|
||||
t.Errorf("Incorrect slot stored, wanted: %d, got: %d",
|
||||
attestation.Data.Slot, service.store.m[pubkey].Data.Slot)
|
||||
pubkey := bytesutil.ToBytes48(beaconState.Validators[10].Pubkey)
|
||||
if service.store.m[pubkey].Data.Crosslink.Shard !=
|
||||
attestation.Data.Crosslink.Shard {
|
||||
t.Errorf("Incorrect shard stored, wanted: %d, got: %d",
|
||||
attestation.Data.Crosslink.Shard, service.store.m[pubkey].Data.Crosslink.Shard)
|
||||
}
|
||||
|
||||
beaconState = &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 36,
|
||||
ValidatorRegistry: validators,
|
||||
Slot: 36,
|
||||
Validators: validators,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
ActiveIndexRoots: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
}
|
||||
beaconState.LatestBlock = block
|
||||
if err := beaconDB.UpdateChainHead(ctx, block, beaconState); err != nil {
|
||||
t.Fatalf("could not save state: %v", err)
|
||||
}
|
||||
|
||||
attestation.Data.Slot = params.BeaconConfig().GenesisSlot + 36
|
||||
attestation.Data.Shard = 36
|
||||
attestation.Data.Crosslink.Shard = 36
|
||||
if err := service.UpdateLatestAttestation(ctx, attestation); err != nil {
|
||||
t.Fatalf("could not update latest attestation: %v", err)
|
||||
}
|
||||
if service.store.m[pubkey].Data.Slot !=
|
||||
attestation.Data.Slot {
|
||||
t.Errorf("Incorrect slot stored, wanted: %d, got: %d",
|
||||
attestation.Data.Slot, service.store.m[pubkey].Data.Slot)
|
||||
if service.store.m[pubkey].Data.Crosslink.Shard !=
|
||||
attestation.Data.Crosslink.Shard {
|
||||
t.Errorf("Incorrect shard stored, wanted: %d, got: %d",
|
||||
attestation.Data.Crosslink.Shard, service.store.m[pubkey].Data.Crosslink.Shard)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,31 +106,31 @@ func TestAttestationPool_UpdatesAttestationPool(t *testing.T) {
|
||||
for i := 0; i < 64; i++ {
|
||||
validators = append(validators, &pb.Validator{
|
||||
Pubkey: []byte{byte(i)},
|
||||
ActivationEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
ExitEpoch: params.BeaconConfig().GenesisEpoch + 10,
|
||||
ActivationEpoch: 0,
|
||||
ExitEpoch: 10,
|
||||
})
|
||||
}
|
||||
beaconState := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
ValidatorRegistry: validators,
|
||||
Slot: 1,
|
||||
Validators: validators,
|
||||
}
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
Slot: 1,
|
||||
}
|
||||
if err := beaconDB.SaveBlock(block); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.LatestBlock = block
|
||||
if err := beaconDB.UpdateChainHead(ctx, block, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
service := NewAttestationService(context.Background(), &Config{BeaconDB: beaconDB})
|
||||
attestation := &pb.Attestation{
|
||||
AggregationBitfield: []byte{0x80},
|
||||
AggregationBits: bitfield.Bitlist{0x80, 0x01},
|
||||
Data: &pb.AttestationData{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
Shard: 1,
|
||||
Crosslink: &pb.Crosslink{
|
||||
Shard: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -142,8 +145,7 @@ func TestLatestAttestationTarget_CantGetAttestation(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
if err := beaconDB.SaveState(ctx, &pb.BeaconState{
|
||||
ValidatorRegistry: []*pb.Validator{{}},
|
||||
LatestBlock: &pb.BeaconBlock{Slot: params.BeaconConfig().GenesisSlot},
|
||||
Validators: []*pb.Validator{{}},
|
||||
}); err != nil {
|
||||
t.Fatalf("could not save state: %v", err)
|
||||
}
|
||||
@@ -167,8 +169,7 @@ func TestLatestAttestationTarget_ReturnsLatestAttestedBlock(t *testing.T) {
|
||||
|
||||
pubKey := []byte{'A'}
|
||||
if err := beaconDB.SaveState(ctx, &pb.BeaconState{
|
||||
ValidatorRegistry: []*pb.Validator{{Pubkey: pubKey}},
|
||||
LatestBlock: &pb.BeaconBlock{Slot: params.BeaconConfig().GenesisSlot},
|
||||
Validators: []*pb.Validator{{Pubkey: pubKey}},
|
||||
}); err != nil {
|
||||
t.Fatalf("could not save state: %v", err)
|
||||
}
|
||||
@@ -177,7 +178,7 @@ func TestLatestAttestationTarget_ReturnsLatestAttestedBlock(t *testing.T) {
|
||||
if err := beaconDB.SaveBlock(block); err != nil {
|
||||
t.Fatalf("could not save block: %v", err)
|
||||
}
|
||||
blockRoot, err := hashutil.HashBeaconBlock(block)
|
||||
blockRoot, err := ssz.SigningRoot(block)
|
||||
if err != nil {
|
||||
log.Fatalf("could not hash block: %v", err)
|
||||
}
|
||||
@@ -193,7 +194,7 @@ func TestLatestAttestationTarget_ReturnsLatestAttestedBlock(t *testing.T) {
|
||||
|
||||
attestation := &pb.Attestation{
|
||||
Data: &pb.AttestationData{
|
||||
BeaconBlockRootHash32: blockRoot[:],
|
||||
BeaconBlockRoot: blockRoot[:],
|
||||
}}
|
||||
pubKey48 := bytesutil.ToBytes48(pubKey)
|
||||
service.store.m[pubKey48] = attestation
|
||||
@@ -213,159 +214,6 @@ func TestLatestAttestationTarget_ReturnsLatestAttestedBlock(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateLatestAttestation_CacheEnabledAndMiss(t *testing.T) {
|
||||
|
||||
beaconDB := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, beaconDB)
|
||||
ctx := context.Background()
|
||||
|
||||
var validators []*pb.Validator
|
||||
for i := 0; i < 64; i++ {
|
||||
validators = append(validators, &pb.Validator{
|
||||
Pubkey: []byte{byte(i)},
|
||||
ActivationEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
ExitEpoch: params.BeaconConfig().GenesisEpoch + 10,
|
||||
})
|
||||
}
|
||||
|
||||
beaconState := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
ValidatorRegistry: validators,
|
||||
}
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
}
|
||||
if err := beaconDB.SaveBlock(block); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.LatestBlock = block
|
||||
if err := beaconDB.UpdateChainHead(ctx, block, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
service := NewAttestationService(context.Background(), &Config{BeaconDB: beaconDB})
|
||||
|
||||
attestation := &pb.Attestation{
|
||||
AggregationBitfield: []byte{0x80},
|
||||
Data: &pb.AttestationData{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
Shard: 1,
|
||||
},
|
||||
}
|
||||
|
||||
if err := service.UpdateLatestAttestation(ctx, attestation); err != nil {
|
||||
t.Fatalf("could not update latest attestation: %v", err)
|
||||
}
|
||||
pubkey := bytesutil.ToBytes48([]byte{byte(3)})
|
||||
if service.store.m[pubkey].Data.Slot !=
|
||||
attestation.Data.Slot {
|
||||
t.Errorf("Incorrect slot stored, wanted: %d, got: %d",
|
||||
attestation.Data.Slot, service.store.m[pubkey].Data.Slot)
|
||||
}
|
||||
|
||||
attestation.Data.Slot = params.BeaconConfig().GenesisSlot + 36
|
||||
attestation.Data.Shard = 36
|
||||
|
||||
beaconState = &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 36,
|
||||
ValidatorRegistry: validators,
|
||||
}
|
||||
beaconState.LatestBlock = block
|
||||
if err := beaconDB.UpdateChainHead(ctx, block, beaconState); err != nil {
|
||||
t.Fatalf("could not save state: %v", err)
|
||||
}
|
||||
|
||||
if err := service.UpdateLatestAttestation(ctx, attestation); err != nil {
|
||||
t.Fatalf("could not update latest attestation: %v", err)
|
||||
}
|
||||
if service.store.m[pubkey].Data.Slot !=
|
||||
attestation.Data.Slot {
|
||||
t.Errorf("Incorrect slot stored, wanted: %d, got: %d",
|
||||
attestation.Data.Slot, service.store.m[pubkey].Data.Slot)
|
||||
}
|
||||
|
||||
// Verify the committee for attestation's data slot was cached.
|
||||
fetchedCommittees, err := committeeCache.CommitteesInfoBySlot(attestation.Data.Slot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wantedCommittee := []uint64{38}
|
||||
if !reflect.DeepEqual(wantedCommittee, fetchedCommittees.Committees[0].Committee) {
|
||||
t.Errorf(
|
||||
"Result indices was an unexpected value. Wanted %d, got %d",
|
||||
wantedCommittee,
|
||||
fetchedCommittees.Committees[0].Committee,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateLatestAttestation_CacheEnabledAndHit(t *testing.T) {
|
||||
|
||||
var validators []*pb.Validator
|
||||
for i := 0; i < 64; i++ {
|
||||
validators = append(validators, &pb.Validator{
|
||||
Pubkey: []byte{byte(i)},
|
||||
ActivationEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
ExitEpoch: params.BeaconConfig().GenesisEpoch + 10,
|
||||
})
|
||||
}
|
||||
|
||||
beaconDB := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, beaconDB)
|
||||
ctx := context.Background()
|
||||
|
||||
beaconState := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 2,
|
||||
ValidatorRegistry: validators,
|
||||
}
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 2,
|
||||
}
|
||||
if err := beaconDB.SaveBlock(block); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.LatestBlock = block
|
||||
if err := beaconDB.UpdateChainHead(ctx, block, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
service := NewAttestationService(context.Background(), &Config{BeaconDB: beaconDB})
|
||||
|
||||
slot := params.BeaconConfig().GenesisSlot + 2
|
||||
shard := uint64(3)
|
||||
index := uint64(4)
|
||||
attestation := &pb.Attestation{
|
||||
AggregationBitfield: []byte{0x80},
|
||||
Data: &pb.AttestationData{
|
||||
Slot: slot,
|
||||
Shard: shard,
|
||||
},
|
||||
}
|
||||
|
||||
csInSlot := &cache.CommitteesInSlot{
|
||||
Slot: slot,
|
||||
Committees: []*cache.CommitteeInfo{
|
||||
{Shard: shard, Committee: []uint64{index, 999}},
|
||||
}}
|
||||
|
||||
if err := committeeCache.AddCommittees(csInSlot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := service.UpdateLatestAttestation(ctx, attestation); err != nil {
|
||||
t.Fatalf("could not update latest attestation: %v", err)
|
||||
}
|
||||
pubkey := bytesutil.ToBytes48([]byte{byte(index)})
|
||||
if err := service.UpdateLatestAttestation(ctx, attestation); err != nil {
|
||||
t.Fatalf("could not update latest attestation: %v", err)
|
||||
}
|
||||
|
||||
if service.store.m[pubkey].Data.Slot !=
|
||||
attestation.Data.Slot {
|
||||
t.Errorf("Incorrect slot stored, wanted: %d, got: %d",
|
||||
attestation.Data.Slot, service.store.m[pubkey].Data.Slot)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateLatestAttestation_InvalidIndex(t *testing.T) {
|
||||
beaconDB := internal.SetupDB(t)
|
||||
hook := logTest.NewGlobal()
|
||||
@@ -376,31 +224,35 @@ func TestUpdateLatestAttestation_InvalidIndex(t *testing.T) {
|
||||
for i := 0; i < 64; i++ {
|
||||
validators = append(validators, &pb.Validator{
|
||||
Pubkey: []byte{byte(i)},
|
||||
ActivationEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
ExitEpoch: params.BeaconConfig().GenesisEpoch + 10,
|
||||
ActivationEpoch: 0,
|
||||
ExitEpoch: 10,
|
||||
})
|
||||
}
|
||||
|
||||
beaconState := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
ValidatorRegistry: validators,
|
||||
Slot: 1,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
ActiveIndexRoots: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
Validators: validators,
|
||||
}
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
Slot: 1,
|
||||
}
|
||||
if err := beaconDB.SaveBlock(block); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.LatestBlock = block
|
||||
if err := beaconDB.UpdateChainHead(ctx, block, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
service := NewAttestationService(context.Background(), &Config{BeaconDB: beaconDB})
|
||||
attestation := &pb.Attestation{
|
||||
AggregationBitfield: []byte{0xC0},
|
||||
AggregationBits: bitfield.Bitlist{0xC0, 0x01},
|
||||
Data: &pb.AttestationData{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
Shard: 1,
|
||||
Crosslink: &pb.Crosslink{
|
||||
Shard: 1,
|
||||
},
|
||||
Target: &pb.Checkpoint{},
|
||||
Source: &pb.Checkpoint{},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -419,25 +271,30 @@ func TestBatchUpdate_FromSync(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
var validators []*pb.Validator
|
||||
var latestRandaoMixes [][]byte
|
||||
var latestActiveIndexRoots [][]byte
|
||||
for i := 0; i < 64; i++ {
|
||||
validators = append(validators, &pb.Validator{
|
||||
Pubkey: []byte{byte(i)},
|
||||
ActivationEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
ExitEpoch: params.BeaconConfig().GenesisEpoch + 10,
|
||||
ActivationEpoch: 0,
|
||||
ExitEpoch: 10,
|
||||
})
|
||||
latestRandaoMixes = append(latestRandaoMixes, []byte{'A'})
|
||||
latestActiveIndexRoots = append(latestActiveIndexRoots, []byte{'B'})
|
||||
}
|
||||
|
||||
beaconState := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
ValidatorRegistry: validators,
|
||||
Slot: 1,
|
||||
Validators: validators,
|
||||
RandaoMixes: latestRandaoMixes,
|
||||
ActiveIndexRoots: latestActiveIndexRoots,
|
||||
}
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
Slot: 1,
|
||||
}
|
||||
if err := beaconDB.SaveBlock(block); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.LatestBlock = block
|
||||
if err := beaconDB.UpdateChainHead(ctx, block, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -445,10 +302,13 @@ func TestBatchUpdate_FromSync(t *testing.T) {
|
||||
service.poolLimit = 9
|
||||
for i := 0; i < 10; i++ {
|
||||
attestation := &pb.Attestation{
|
||||
AggregationBitfield: []byte{0x80},
|
||||
AggregationBits: bitfield.Bitlist{0x80},
|
||||
Data: &pb.AttestationData{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
Shard: 1,
|
||||
Target: &pb.Checkpoint{Epoch: 2},
|
||||
Source: &pb.Checkpoint{},
|
||||
Crosslink: &pb.Crosslink{
|
||||
Shard: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := service.handleAttestation(ctx, attestation); err != nil {
|
||||
@@ -469,22 +329,23 @@ func TestUpdateLatestAttestation_BatchUpdate(t *testing.T) {
|
||||
for i := 0; i < 64; i++ {
|
||||
validators = append(validators, &pb.Validator{
|
||||
Pubkey: []byte{byte(i)},
|
||||
ActivationEpoch: params.BeaconConfig().GenesisEpoch,
|
||||
ExitEpoch: params.BeaconConfig().GenesisEpoch + 10,
|
||||
ActivationEpoch: 0,
|
||||
ExitEpoch: 10,
|
||||
})
|
||||
}
|
||||
|
||||
beaconState := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
ValidatorRegistry: validators,
|
||||
Slot: 1,
|
||||
RandaoMixes: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
ActiveIndexRoots: make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector),
|
||||
Validators: validators,
|
||||
}
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
Slot: 1,
|
||||
}
|
||||
if err := beaconDB.SaveBlock(block); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.LatestBlock = block
|
||||
if err := beaconDB.UpdateChainHead(ctx, block, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -492,10 +353,13 @@ func TestUpdateLatestAttestation_BatchUpdate(t *testing.T) {
|
||||
attestations := make([]*pb.Attestation, 0)
|
||||
for i := 0; i < 10; i++ {
|
||||
attestations = append(attestations, &pb.Attestation{
|
||||
AggregationBitfield: []byte{0x80},
|
||||
AggregationBits: bitfield.Bitlist{0x80, 0x01},
|
||||
Data: &pb.AttestationData{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 1,
|
||||
Shard: 1,
|
||||
Crosslink: &pb.Crosslink{
|
||||
Shard: 1,
|
||||
},
|
||||
Target: &pb.Checkpoint{},
|
||||
Source: &pb.Checkpoint{},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -37,7 +36,6 @@ func reportVoteMetrics(index uint64, block *pb.BeaconBlock) {
|
||||
return
|
||||
}
|
||||
|
||||
s := params.BeaconConfig().GenesisSlot
|
||||
validatorLastVoteGauge.WithLabelValues(
|
||||
"v" + strconv.Itoa(int(index))).Set(float64(block.Slot - s))
|
||||
"v" + strconv.Itoa(int(index))).Set(float64(block.Slot))
|
||||
}
|
||||
|
||||
@@ -23,12 +23,11 @@ go_library(
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/event:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/p2p:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
],
|
||||
@@ -36,7 +35,7 @@ go_library(
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
size = "medium",
|
||||
srcs = [
|
||||
"block_processing_test.go",
|
||||
"fork_choice_reorg_test.go",
|
||||
@@ -59,7 +58,6 @@ go_test(
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/event:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/forkutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/p2p:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
@@ -69,6 +67,7 @@ go_test(
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
],
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
@@ -14,8 +15,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/event"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
@@ -33,7 +32,7 @@ type BlockReceiver interface {
|
||||
// to beacon blocks and generating a new beacon state from the Ethereum 2.0 core primitives.
|
||||
type BlockProcessor interface {
|
||||
VerifyBlockValidity(ctx context.Context, block *pb.BeaconBlock, beaconState *pb.BeaconState) error
|
||||
ApplyBlockStateTransition(ctx context.Context, block *pb.BeaconBlock, beaconState *pb.BeaconState) (*pb.BeaconState, error)
|
||||
AdvanceState(ctx context.Context, beaconState *pb.BeaconState, block *pb.BeaconBlock) (*pb.BeaconState, error)
|
||||
CleanupBlockOperations(ctx context.Context, block *pb.BeaconBlock) error
|
||||
}
|
||||
|
||||
@@ -58,7 +57,7 @@ func (c *ChainService) ReceiveBlock(ctx context.Context, block *pb.BeaconBlock)
|
||||
defer c.receiveBlockLock.Unlock()
|
||||
ctx, span := trace.StartSpan(ctx, "beacon-chain.blockchain.ReceiveBlock")
|
||||
defer span.End()
|
||||
parentRoot := bytesutil.ToBytes32(block.ParentRootHash32)
|
||||
parentRoot := bytesutil.ToBytes32(block.ParentRoot)
|
||||
parent, err := c.beaconDB.Block(parentRoot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get parent block: %v", err)
|
||||
@@ -70,9 +69,8 @@ func (c *ChainService) ReceiveBlock(ctx context.Context, block *pb.BeaconBlock)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not retrieve beacon state: %v", err)
|
||||
}
|
||||
saveLatestBlock := beaconState.LatestBlock
|
||||
|
||||
blockRoot, err := hashutil.HashBeaconBlock(block)
|
||||
blockRoot, err := ssz.SigningRoot(block)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not hash beacon block")
|
||||
}
|
||||
@@ -85,15 +83,14 @@ func (c *ChainService) ReceiveBlock(ctx context.Context, block *pb.BeaconBlock)
|
||||
if err := c.SaveAndBroadcastBlock(ctx, block); err != nil {
|
||||
return beaconState, fmt.Errorf(
|
||||
"could not save and broadcast beacon block with slot %d: %v",
|
||||
block.Slot-params.BeaconConfig().GenesisSlot, err,
|
||||
block.Slot, err,
|
||||
)
|
||||
}
|
||||
|
||||
log.WithField("slotNumber", block.Slot-params.BeaconConfig().GenesisSlot).Info(
|
||||
"Executing state transition")
|
||||
log.WithField("slot", block.Slot).Info("Executing state transition")
|
||||
|
||||
// We then apply the block state transition accordingly to obtain the resulting beacon state.
|
||||
beaconState, err = c.ApplyBlockStateTransition(ctx, block, beaconState)
|
||||
beaconState, err = c.AdvanceState(ctx, beaconState, block)
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case *BlockFailedProcessingErr:
|
||||
@@ -109,21 +106,18 @@ func (c *ChainService) ReceiveBlock(ctx context.Context, block *pb.BeaconBlock)
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
"slotNumber": block.Slot - params.BeaconConfig().GenesisSlot,
|
||||
"currentEpoch": helpers.SlotToEpoch(block.Slot) - params.BeaconConfig().GenesisEpoch,
|
||||
"slot": block.Slot,
|
||||
"epoch": helpers.SlotToEpoch(block.Slot),
|
||||
}).Info("State transition complete")
|
||||
|
||||
// Check state root
|
||||
if featureconfig.FeatureConfig().EnableCheckBlockStateRoot {
|
||||
// Calc state hash with previous block
|
||||
beaconState.LatestBlock = saveLatestBlock
|
||||
stateRoot, err := hashutil.HashProto(beaconState)
|
||||
stateRoot, err := ssz.HashTreeRoot(beaconState)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not hash beacon state: %v", err)
|
||||
}
|
||||
beaconState.LatestBlock = block
|
||||
if !bytes.Equal(block.StateRootHash32, stateRoot[:]) {
|
||||
return nil, fmt.Errorf("beacon state root is not equal to block state root: %#x != %#x", stateRoot, block.StateRootHash32)
|
||||
if !bytes.Equal(block.StateRoot, stateRoot[:]) {
|
||||
return nil, fmt.Errorf("beacon state root is not equal to block state root: %#x != %#x", stateRoot, block.StateRoot)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,53 +127,12 @@ func (c *ChainService) ReceiveBlock(ctx context.Context, block *pb.BeaconBlock)
|
||||
return beaconState, fmt.Errorf("could not process block deposits, attestations, and other operations: %v", err)
|
||||
}
|
||||
|
||||
log.WithField("slot", block.Slot-params.BeaconConfig().GenesisSlot).Info("Finished processing beacon block")
|
||||
return beaconState, nil
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"slot": block.Slot,
|
||||
"attestations": len(block.Body.Attestations),
|
||||
"deposits": len(block.Body.Deposits),
|
||||
}).Info("Finished processing beacon block")
|
||||
|
||||
// ApplyBlockStateTransition runs the Ethereum 2.0 state transition function
|
||||
// to produce a new beacon state and also accounts for skip slots occurring.
|
||||
//
|
||||
// def apply_block_state_transition(block):
|
||||
// # process skipped slots
|
||||
// while (state.slot < block.slot - 1):
|
||||
// state = slot_state_transition(state, block=None)
|
||||
//
|
||||
// # process slot with block
|
||||
// state = slot_state_transition(state, block)
|
||||
//
|
||||
// # check state root
|
||||
// if block.state_root == hash(state):
|
||||
// return state, error
|
||||
// else:
|
||||
// return nil, error # or throw or whatever
|
||||
//
|
||||
func (c *ChainService) ApplyBlockStateTransition(
|
||||
ctx context.Context, block *pb.BeaconBlock, beaconState *pb.BeaconState,
|
||||
) (*pb.BeaconState, error) {
|
||||
// Retrieve the last processed beacon block's hash root.
|
||||
headRoot, err := c.ChainHeadRoot()
|
||||
if err != nil {
|
||||
return beaconState, fmt.Errorf("could not retrieve chain head root: %v", err)
|
||||
}
|
||||
|
||||
// Check for skipped slots.
|
||||
numSkippedSlots := 0
|
||||
for beaconState.Slot < block.Slot-1 {
|
||||
beaconState, err = c.runStateTransition(ctx, headRoot, nil, beaconState)
|
||||
if err != nil {
|
||||
return beaconState, err
|
||||
}
|
||||
numSkippedSlots++
|
||||
}
|
||||
if numSkippedSlots > 0 {
|
||||
log.Warnf("Processed %d skipped slots", numSkippedSlots)
|
||||
}
|
||||
|
||||
beaconState, err = c.runStateTransition(ctx, headRoot, block, beaconState)
|
||||
if err != nil {
|
||||
return beaconState, err
|
||||
}
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
@@ -194,9 +147,9 @@ func (c *ChainService) VerifyBlockValidity(
|
||||
block *pb.BeaconBlock,
|
||||
beaconState *pb.BeaconState,
|
||||
) error {
|
||||
if block.Slot == params.BeaconConfig().GenesisSlot {
|
||||
if block.Slot == 0 {
|
||||
return fmt.Errorf("cannot process a genesis block: received block with slot %d",
|
||||
block.Slot-params.BeaconConfig().GenesisSlot)
|
||||
block.Slot)
|
||||
}
|
||||
powBlockFetcher := c.web3Service.Client().BlockByHash
|
||||
if err := b.IsValidBlock(ctx, beaconState, block,
|
||||
@@ -210,7 +163,7 @@ func (c *ChainService) VerifyBlockValidity(
|
||||
// peers via p2p. Blocks which have already been saved are not processed again via p2p, which is why
|
||||
// the order of operations is important in this function to prevent infinite p2p loops.
|
||||
func (c *ChainService) SaveAndBroadcastBlock(ctx context.Context, block *pb.BeaconBlock) error {
|
||||
blockRoot, err := hashutil.HashBeaconBlock(block)
|
||||
blockRoot, err := ssz.SigningRoot(block)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not tree hash incoming block: %v", err)
|
||||
}
|
||||
@@ -220,7 +173,7 @@ func (c *ChainService) SaveAndBroadcastBlock(ctx context.Context, block *pb.Beac
|
||||
if err := c.beaconDB.SaveAttestationTarget(ctx, &pb.AttestationTarget{
|
||||
Slot: block.Slot,
|
||||
BlockRoot: blockRoot[:],
|
||||
ParentRoot: block.ParentRootHash32,
|
||||
ParentRoot: block.ParentRoot,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("failed to save attestation target: %v", err)
|
||||
}
|
||||
@@ -253,43 +206,42 @@ func (c *ChainService) CleanupBlockOperations(ctx context.Context, block *pb.Bea
|
||||
return nil
|
||||
}
|
||||
|
||||
// runStateTransition executes the Ethereum 2.0 core state transition for the beacon chain and
|
||||
// AdvanceState executes the Ethereum 2.0 core state transition for the beacon chain and
|
||||
// updates important checkpoints and local persistent data during epoch transitions. It serves as a wrapper
|
||||
// around the more low-level, core state transition function primitive.
|
||||
func (c *ChainService) runStateTransition(
|
||||
func (c *ChainService) AdvanceState(
|
||||
ctx context.Context,
|
||||
headRoot [32]byte,
|
||||
block *pb.BeaconBlock,
|
||||
beaconState *pb.BeaconState,
|
||||
block *pb.BeaconBlock,
|
||||
) (*pb.BeaconState, error) {
|
||||
finalizedEpoch := beaconState.FinalizedEpoch
|
||||
finalizedEpoch := beaconState.FinalizedCheckpoint.Epoch
|
||||
newState, err := state.ExecuteStateTransition(
|
||||
ctx,
|
||||
beaconState,
|
||||
block,
|
||||
headRoot,
|
||||
&state.TransitionConfig{
|
||||
VerifySignatures: false, // We disable signature verification for now.
|
||||
Logging: true, // We enable logging in this state transition call.
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return beaconState, &BlockFailedProcessingErr{err}
|
||||
}
|
||||
// Prune the block cache on every new finalized epoch.
|
||||
if newState.FinalizedEpoch > finalizedEpoch {
|
||||
// Prune the block cache and helper caches on every new finalized epoch.
|
||||
if newState.FinalizedCheckpoint.Epoch > finalizedEpoch {
|
||||
helpers.ClearAllCaches()
|
||||
c.beaconDB.ClearBlockCache()
|
||||
}
|
||||
|
||||
log.WithField(
|
||||
"slotsSinceGenesis", newState.Slot-params.BeaconConfig().GenesisSlot,
|
||||
"slotsSinceGenesis", newState.Slot,
|
||||
).Info("Slot transition successfully processed")
|
||||
|
||||
if block != nil {
|
||||
log.WithField(
|
||||
"slotsSinceGenesis", newState.Slot-params.BeaconConfig().GenesisSlot,
|
||||
"slotsSinceGenesis", newState.Slot,
|
||||
).Info("Block transition successfully processed")
|
||||
|
||||
blockRoot, err := hashutil.HashBeaconBlock(block)
|
||||
blockRoot, err := ssz.SigningRoot(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -312,9 +264,7 @@ func (c *ChainService) runStateTransition(
|
||||
if err := c.updateFFGCheckPts(ctx, newState); err != nil {
|
||||
return newState, fmt.Errorf("could not update FFG checkpts: %v", err)
|
||||
}
|
||||
log.WithField(
|
||||
"SlotsSinceGenesis", newState.Slot-params.BeaconConfig().GenesisSlot,
|
||||
).Info("Epoch transition successfully processed")
|
||||
logEpochData(newState)
|
||||
}
|
||||
return newState, nil
|
||||
}
|
||||
@@ -329,11 +279,11 @@ func (c *ChainService) saveValidatorIdx(state *pb.BeaconState) error {
|
||||
for _, idx := range activatedValidators {
|
||||
// If for some reason the activated validator indices is not in state,
|
||||
// we skip them and save them to process for next epoch.
|
||||
if int(idx) >= len(state.ValidatorRegistry) {
|
||||
if int(idx) >= len(state.Validators) {
|
||||
idxNotInState = append(idxNotInState, idx)
|
||||
continue
|
||||
}
|
||||
pubKey := state.ValidatorRegistry[idx].Pubkey
|
||||
pubKey := state.Validators[idx].Pubkey
|
||||
if err := c.beaconDB.SaveValidatorIndex(pubKey, int(idx)); err != nil {
|
||||
return fmt.Errorf("could not save validator index: %v", err)
|
||||
}
|
||||
@@ -351,7 +301,7 @@ func (c *ChainService) saveValidatorIdx(state *pb.BeaconState) error {
|
||||
func (c *ChainService) deleteValidatorIdx(state *pb.BeaconState) error {
|
||||
exitedValidators := validators.ExitedValFromEpoch(helpers.CurrentEpoch(state) + 1)
|
||||
for _, idx := range exitedValidators {
|
||||
pubKey := state.ValidatorRegistry[idx].Pubkey
|
||||
pubKey := state.Validators[idx].Pubkey
|
||||
if err := c.beaconDB.DeleteValidatorIndex(pubKey); err != nil {
|
||||
return fmt.Errorf("could not delete validator index: %v", err)
|
||||
}
|
||||
@@ -359,3 +309,29 @@ func (c *ChainService) deleteValidatorIdx(state *pb.BeaconState) error {
|
||||
validators.DeleteExitedVal(helpers.CurrentEpoch(state))
|
||||
return nil
|
||||
}
|
||||
|
||||
// logs epoch related data in each epoch transition
|
||||
func logEpochData(beaconState *pb.BeaconState) {
|
||||
|
||||
log.WithField("currentEpochAttestations", len(beaconState.CurrentEpochAttestations)).Info("Number of current epoch attestations")
|
||||
log.WithField("prevEpochAttestations", len(beaconState.PreviousEpochAttestations)).Info("Number of previous epoch attestations")
|
||||
log.WithField(
|
||||
"previousJustifiedEpoch", beaconState.PreviousJustifiedCheckpoint.Epoch,
|
||||
).Info("Previous justified epoch")
|
||||
log.WithField(
|
||||
"justifiedEpoch", beaconState.CurrentJustifiedCheckpoint.Epoch,
|
||||
).Info("Justified epoch")
|
||||
log.WithField(
|
||||
"finalizedEpoch", beaconState.FinalizedCheckpoint.Epoch,
|
||||
).Info("Finalized epoch")
|
||||
log.WithField(
|
||||
"Deposit Index", beaconState.Eth1DepositIndex,
|
||||
).Info("ETH1 Deposit Index")
|
||||
log.WithField(
|
||||
"numValidators", len(beaconState.Validators),
|
||||
).Info("Validator registry length")
|
||||
|
||||
log.WithField(
|
||||
"SlotsSinceGenesis", beaconState.Slot,
|
||||
).Info("Epoch transition successfully processed")
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/attestation"
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
v "github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/internal"
|
||||
@@ -27,8 +29,15 @@ import (
|
||||
// Ensure ChainService implements interfaces.
|
||||
var _ = BlockProcessor(&ChainService{})
|
||||
|
||||
func init() {
|
||||
// TODO(2993): remove this after ssz is optimized for mainnet.
|
||||
c := params.BeaconConfig()
|
||||
c.HistoricalRootsLimit = 8192
|
||||
params.OverrideBeaconConfig(c)
|
||||
}
|
||||
|
||||
func initBlockStateRoot(t *testing.T, block *pb.BeaconBlock, chainService *ChainService) {
|
||||
parentRoot := bytesutil.ToBytes32(block.ParentRootHash32)
|
||||
parentRoot := bytesutil.ToBytes32(block.ParentRoot)
|
||||
parent, err := chainService.beaconDB.Block(parentRoot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -37,19 +46,18 @@ func initBlockStateRoot(t *testing.T, block *pb.BeaconBlock, chainService *Chain
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to retrieve state %v", err)
|
||||
}
|
||||
saveLatestBlock := beaconState.LatestBlock
|
||||
|
||||
computedState, err := chainService.ApplyBlockStateTransition(context.Background(), block, beaconState)
|
||||
computedState, err := chainService.AdvanceState(context.Background(), beaconState, block)
|
||||
if err != nil {
|
||||
t.Fatalf("could not apply block state transition: %v", err)
|
||||
}
|
||||
|
||||
computedState.LatestBlock = saveLatestBlock
|
||||
stateRoot, err := hashutil.HashProto(computedState)
|
||||
stateRoot, err := ssz.HashTreeRoot(computedState)
|
||||
if err != nil {
|
||||
t.Fatalf("could not tree hash state: %v", err)
|
||||
}
|
||||
block.StateRootHash32 = stateRoot[:]
|
||||
|
||||
block.StateRoot = stateRoot[:]
|
||||
t.Logf("state root after block: %#x", stateRoot)
|
||||
}
|
||||
|
||||
@@ -58,8 +66,8 @@ func TestReceiveBlock_FaultyPOWChain(t *testing.T) {
|
||||
defer internal.TeardownDB(t, db)
|
||||
chainService := setupBeaconChain(t, db, nil)
|
||||
unixTime := uint64(time.Now().Unix())
|
||||
deposits, _ := setupInitialDeposits(t, 100)
|
||||
if err := db.InitializeState(context.Background(), unixTime, deposits, &pb.Eth1Data{}); err != nil {
|
||||
deposits, _ := testutil.SetupInitialDeposits(t, 100, false)
|
||||
if err := db.InitializeState(context.Background(), unixTime, deposits, nil); err != nil {
|
||||
t.Fatalf("Could not initialize beacon state to disk: %v", err)
|
||||
}
|
||||
|
||||
@@ -71,7 +79,7 @@ func TestReceiveBlock_FaultyPOWChain(t *testing.T) {
|
||||
Slot: 1,
|
||||
}
|
||||
|
||||
parentRoot, err := hashutil.HashBeaconBlock(parentBlock)
|
||||
parentRoot, err := ssz.SigningRoot(parentBlock)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to tree hash block %v", err)
|
||||
}
|
||||
@@ -81,11 +89,13 @@ func TestReceiveBlock_FaultyPOWChain(t *testing.T) {
|
||||
}
|
||||
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: 2,
|
||||
ParentRootHash32: parentRoot[:],
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositRootHash32: []byte("a"),
|
||||
BlockHash32: []byte("b"),
|
||||
Slot: 2,
|
||||
ParentRoot: parentRoot[:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositRoot: []byte("a"),
|
||||
BlockHash: []byte("b"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -98,35 +108,41 @@ func TestReceiveBlock_FaultyPOWChain(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestReceiveBlock_ProcessCorrectly(t *testing.T) {
|
||||
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
|
||||
EnableCheckBlockStateRoot: false,
|
||||
})
|
||||
hook := logTest.NewGlobal()
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
ctx := context.Background()
|
||||
|
||||
chainService := setupBeaconChain(t, db, nil)
|
||||
deposits, privKeys := setupInitialDeposits(t, 100)
|
||||
eth1Data := &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{},
|
||||
BlockHash32: []byte{},
|
||||
}
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, eth1Data)
|
||||
deposits, privKeys := testutil.SetupInitialDeposits(t, 100, true)
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't generate genesis state: %v", err)
|
||||
}
|
||||
stateRoot, err := hashutil.HashProto(beaconState)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not tree hash state: %v", err)
|
||||
}
|
||||
beaconState.StateRoots = make([][]byte, params.BeaconConfig().HistoricalRootsLimit)
|
||||
genesis := b.NewGenesisBlock([]byte{})
|
||||
bodyRoot, err := ssz.HashTreeRoot(genesis.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
|
||||
Slot: genesis.Slot,
|
||||
ParentRoot: genesis.ParentRoot,
|
||||
BodyRoot: bodyRoot[:],
|
||||
}
|
||||
beaconState.Eth1DepositIndex = 100
|
||||
if err := chainService.beaconDB.SaveBlock(genesis); err != nil {
|
||||
t.Fatalf("Could not save block to db: %v", err)
|
||||
}
|
||||
parentHash, err := hashutil.HashBeaconBlock(genesis)
|
||||
parentRoot, err := ssz.SigningRoot(genesis)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to get tree hash root of canonical head: %v", err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := db.SaveHistoricalState(ctx, beaconState, parentHash); err != nil {
|
||||
if err := db.SaveHistoricalState(ctx, beaconState, parentRoot); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -135,24 +151,26 @@ func TestReceiveBlock_ProcessCorrectly(t *testing.T) {
|
||||
}
|
||||
|
||||
beaconState.Slot++
|
||||
randaoReveal := createRandaoReveal(t, beaconState, privKeys)
|
||||
epoch := helpers.CurrentEpoch(beaconState)
|
||||
randaoReveal, err := helpers.CreateRandaoReveal(beaconState, epoch, privKeys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: beaconState.Slot,
|
||||
StateRootHash32: stateRoot[:],
|
||||
ParentRootHash32: parentHash[:],
|
||||
RandaoReveal: randaoReveal,
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositRootHash32: []byte("a"),
|
||||
BlockHash32: []byte("b"),
|
||||
},
|
||||
Slot: beaconState.Slot,
|
||||
ParentRoot: parentRoot[:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositCount: uint64(len(deposits)),
|
||||
DepositRoot: []byte("a"),
|
||||
BlockHash: []byte("b"),
|
||||
},
|
||||
RandaoReveal: randaoReveal,
|
||||
Attestations: nil,
|
||||
},
|
||||
}
|
||||
|
||||
initBlockStateRoot(t, block, chainService)
|
||||
|
||||
if err := chainService.beaconDB.SaveJustifiedBlock(block); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -165,31 +183,36 @@ func TestReceiveBlock_ProcessCorrectly(t *testing.T) {
|
||||
if _, err := chainService.ReceiveBlock(context.Background(), block); err != nil {
|
||||
t.Errorf("Block failed processing: %v", err)
|
||||
}
|
||||
|
||||
testutil.AssertLogsContain(t, hook, "Finished processing beacon block")
|
||||
}
|
||||
|
||||
func TestReceiveBlock_UsesParentBlockState(t *testing.T) {
|
||||
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
|
||||
EnableCheckBlockStateRoot: false,
|
||||
})
|
||||
hook := logTest.NewGlobal()
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
ctx := context.Background()
|
||||
|
||||
chainService := setupBeaconChain(t, db, nil)
|
||||
deposits, _ := setupInitialDeposits(t, 100)
|
||||
eth1Data := &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{},
|
||||
BlockHash32: []byte{},
|
||||
}
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, eth1Data)
|
||||
deposits, _ := testutil.SetupInitialDeposits(t, 100, false)
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't generate genesis state: %v", err)
|
||||
}
|
||||
|
||||
stateRoot, err := hashutil.HashProto(beaconState)
|
||||
beaconState.StateRoots = make([][]byte, params.BeaconConfig().HistoricalRootsLimit)
|
||||
genesis := b.NewGenesisBlock([]byte{})
|
||||
bodyRoot, err := ssz.HashTreeRoot(genesis.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not tree hash state: %v", err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
|
||||
Slot: genesis.Slot,
|
||||
ParentRoot: genesis.ParentRoot,
|
||||
BodyRoot: bodyRoot[:],
|
||||
}
|
||||
beaconState.Eth1DepositIndex = 100
|
||||
|
||||
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
|
||||
if err := chainService.beaconDB.UpdateChainHead(ctx, genesisBlock, beaconState); err != nil {
|
||||
@@ -198,21 +221,24 @@ func TestReceiveBlock_UsesParentBlockState(t *testing.T) {
|
||||
if err := chainService.beaconDB.SaveHistoricalState(ctx, beaconState, parentHash); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
parentRoot, err := ssz.SigningRoot(beaconState.LatestBlockHeader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// We ensure the block uses the right state parent if its ancestor is not block.Slot-1.
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: beaconState.Slot + 4,
|
||||
StateRootHash32: stateRoot[:],
|
||||
ParentRootHash32: parentHash[:],
|
||||
RandaoReveal: []byte{},
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositRootHash32: []byte("a"),
|
||||
BlockHash32: []byte("b"),
|
||||
},
|
||||
Slot: beaconState.Slot + 4,
|
||||
StateRoot: []byte{},
|
||||
ParentRoot: parentRoot[:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositRoot: []byte("a"),
|
||||
BlockHash: []byte("b"),
|
||||
},
|
||||
RandaoReveal: []byte{},
|
||||
Attestations: nil,
|
||||
},
|
||||
}
|
||||
initBlockStateRoot(t, block, chainService)
|
||||
if err := chainService.beaconDB.SaveBlock(block); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -230,19 +256,25 @@ func TestReceiveBlock_DeletesBadBlock(t *testing.T) {
|
||||
defer internal.TeardownDB(t, db)
|
||||
ctx := context.Background()
|
||||
|
||||
chainService := setupBeaconChain(t, db, nil)
|
||||
deposits, _ := setupInitialDeposits(t, 100)
|
||||
eth1Data := &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{},
|
||||
BlockHash32: []byte{},
|
||||
}
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, eth1Data)
|
||||
attsService := attestation.NewAttestationService(
|
||||
context.Background(),
|
||||
&attestation.Config{BeaconDB: db})
|
||||
chainService := setupBeaconChain(t, db, attsService)
|
||||
deposits, _ := testutil.SetupInitialDeposits(t, 100, false)
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't generate genesis state: %v", err)
|
||||
}
|
||||
stateRoot, err := hashutil.HashProto(beaconState)
|
||||
beaconState.StateRoots = make([][]byte, params.BeaconConfig().HistoricalRootsLimit)
|
||||
genesis := b.NewGenesisBlock([]byte{})
|
||||
bodyRoot, err := ssz.HashTreeRoot(genesis.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not tree hash state: %v", err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
|
||||
Slot: genesis.Slot,
|
||||
ParentRoot: genesis.ParentRoot,
|
||||
BodyRoot: bodyRoot[:],
|
||||
}
|
||||
|
||||
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
|
||||
@@ -255,27 +287,29 @@ func TestReceiveBlock_DeletesBadBlock(t *testing.T) {
|
||||
|
||||
beaconState.Slot++
|
||||
|
||||
parentRoot, err := ssz.SigningRoot(beaconState.LatestBlockHeader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: beaconState.Slot,
|
||||
StateRootHash32: stateRoot[:],
|
||||
ParentRootHash32: parentHash[:],
|
||||
RandaoReveal: []byte{},
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositRootHash32: []byte("a"),
|
||||
BlockHash32: []byte("b"),
|
||||
},
|
||||
Slot: beaconState.Slot,
|
||||
StateRoot: []byte{},
|
||||
ParentRoot: parentRoot[:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Attestations: []*pb.Attestation{
|
||||
{
|
||||
Data: &pb.AttestationData{
|
||||
JustifiedEpoch: params.BeaconConfig().GenesisSlot * 100,
|
||||
},
|
||||
},
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositRoot: []byte("a"),
|
||||
BlockHash: []byte("b"),
|
||||
},
|
||||
RandaoReveal: []byte{},
|
||||
Attestations: []*pb.Attestation{{
|
||||
Data: &pb.AttestationData{
|
||||
Target: &pb.Checkpoint{Epoch: 5},
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
blockRoot, err := hashutil.HashBeaconBlock(block)
|
||||
blockRoot, err := ssz.SigningRoot(block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -285,7 +319,7 @@ func TestReceiveBlock_DeletesBadBlock(t *testing.T) {
|
||||
case *BlockFailedProcessingErr:
|
||||
t.Log("Block failed processing as expected")
|
||||
default:
|
||||
t.Errorf("Unexpected block processing error: %v", err)
|
||||
t.Errorf("Expected block processing to fail, received: %v", err)
|
||||
}
|
||||
|
||||
savedBlock, err := db.Block(blockRoot)
|
||||
@@ -314,16 +348,23 @@ func TestReceiveBlock_CheckBlockStateRoot_GoodState(t *testing.T) {
|
||||
context.Background(),
|
||||
&attestation.Config{BeaconDB: db})
|
||||
chainService := setupBeaconChain(t, db, attsService)
|
||||
deposits, privKeys := setupInitialDeposits(t, 100)
|
||||
eth1Data := &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{},
|
||||
BlockHash32: []byte{},
|
||||
}
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, eth1Data)
|
||||
deposits, privKeys := testutil.SetupInitialDeposits(t, 100, true)
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't generate genesis state: %v", err)
|
||||
}
|
||||
|
||||
beaconState.Eth1DepositIndex = 100
|
||||
genesis := b.NewGenesisBlock([]byte{})
|
||||
bodyRoot, err := ssz.HashTreeRoot(genesis.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.StateRoots = make([][]byte, params.BeaconConfig().HistoricalRootsLimit)
|
||||
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
|
||||
Slot: genesis.Slot,
|
||||
ParentRoot: genesis.ParentRoot,
|
||||
BodyRoot: bodyRoot[:],
|
||||
}
|
||||
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
|
||||
if err := chainService.beaconDB.SaveHistoricalState(ctx, beaconState, parentHash); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -334,11 +375,23 @@ func TestReceiveBlock_CheckBlockStateRoot_GoodState(t *testing.T) {
|
||||
}
|
||||
|
||||
beaconState.Slot++
|
||||
parentRoot, err := ssz.SigningRoot(genesisBlock)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
epoch := helpers.CurrentEpoch(beaconState)
|
||||
randaoReveal, err := helpers.CreateRandaoReveal(beaconState, epoch, privKeys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
goodStateBlock := &pb.BeaconBlock{
|
||||
Slot: beaconState.Slot,
|
||||
ParentRootHash32: parentHash[:],
|
||||
RandaoReveal: createRandaoReveal(t, beaconState, privKeys),
|
||||
Body: &pb.BeaconBlockBody{},
|
||||
Slot: beaconState.Slot,
|
||||
ParentRoot: parentRoot[:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{},
|
||||
RandaoReveal: randaoReveal,
|
||||
},
|
||||
}
|
||||
beaconState.Slot--
|
||||
initBlockStateRoot(t, goodStateBlock, chainService)
|
||||
@@ -357,17 +410,25 @@ func TestReceiveBlock_CheckBlockStateRoot_GoodState(t *testing.T) {
|
||||
func TestReceiveBlock_CheckBlockStateRoot_BadState(t *testing.T) {
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
chainService := setupBeaconChain(t, db, nil)
|
||||
deposits, privKeys := setupInitialDeposits(t, 100)
|
||||
ctx := context.Background()
|
||||
eth1Data := &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{},
|
||||
BlockHash32: []byte{},
|
||||
}
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, eth1Data)
|
||||
chainService := setupBeaconChain(t, db, nil)
|
||||
deposits, privKeys := testutil.SetupInitialDeposits(t, 100, true)
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't generate genesis state: %v", err)
|
||||
}
|
||||
beaconState.Eth1DepositIndex = 100
|
||||
genesis := b.NewGenesisBlock([]byte{})
|
||||
bodyRoot, err := ssz.HashTreeRoot(genesis.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.StateRoots = make([][]byte, params.BeaconConfig().HistoricalRootsLimit)
|
||||
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
|
||||
Slot: genesis.Slot,
|
||||
ParentRoot: genesis.ParentRoot,
|
||||
BodyRoot: bodyRoot[:],
|
||||
}
|
||||
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
|
||||
if err := chainService.beaconDB.SaveHistoricalState(ctx, beaconState, parentHash); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -378,12 +439,24 @@ func TestReceiveBlock_CheckBlockStateRoot_BadState(t *testing.T) {
|
||||
}
|
||||
|
||||
beaconState.Slot++
|
||||
parentRoot, err := ssz.SigningRoot(genesis)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
epoch := helpers.CurrentEpoch(beaconState)
|
||||
randaoReveal, err := helpers.CreateRandaoReveal(beaconState, epoch, privKeys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
invalidStateBlock := &pb.BeaconBlock{
|
||||
Slot: beaconState.Slot,
|
||||
StateRootHash32: []byte{'b', 'a', 'd', ' ', 'h', 'a', 's', 'h'},
|
||||
ParentRootHash32: parentHash[:],
|
||||
RandaoReveal: createRandaoReveal(t, beaconState, privKeys),
|
||||
Body: &pb.BeaconBlockBody{},
|
||||
Slot: beaconState.Slot,
|
||||
StateRoot: []byte{'b', 'a', 'd', ' ', 'h', 'a', 's', 'h'},
|
||||
ParentRoot: parentRoot[:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{},
|
||||
RandaoReveal: randaoReveal,
|
||||
},
|
||||
}
|
||||
beaconState.Slot--
|
||||
|
||||
@@ -406,15 +479,24 @@ func TestReceiveBlock_RemovesPendingDeposits(t *testing.T) {
|
||||
context.Background(),
|
||||
&attestation.Config{BeaconDB: db})
|
||||
chainService := setupBeaconChain(t, db, attsService)
|
||||
deposits, privKeys := setupInitialDeposits(t, 100)
|
||||
eth1Data := &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{},
|
||||
BlockHash32: []byte{},
|
||||
}
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, eth1Data)
|
||||
deposits, privKeys := testutil.SetupInitialDeposits(t, 100, true)
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't generate genesis state: %v", err)
|
||||
}
|
||||
genesis := b.NewGenesisBlock([]byte{})
|
||||
bodyRoot, err := ssz.HashTreeRoot(genesis.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.StateRoots = make([][]byte, params.BeaconConfig().HistoricalRootsLimit)
|
||||
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
|
||||
Slot: genesis.Slot,
|
||||
ParentRoot: genesis.ParentRoot,
|
||||
BodyRoot: bodyRoot[:],
|
||||
}
|
||||
beaconState.Eth1Data.DepositCount = 1
|
||||
beaconState.Eth1DepositIndex = 0
|
||||
if err := chainService.beaconDB.SaveJustifiedState(beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -422,7 +504,7 @@ func TestReceiveBlock_RemovesPendingDeposits(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stateRoot, err := hashutil.HashProto(beaconState)
|
||||
stateRoot, err := ssz.HashTreeRoot(beaconState)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not tree hash state: %v", err)
|
||||
}
|
||||
@@ -432,57 +514,69 @@ func TestReceiveBlock_RemovesPendingDeposits(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
currentSlot := params.BeaconConfig().GenesisSlot
|
||||
randaoReveal := createRandaoReveal(t, beaconState, privKeys)
|
||||
currentSlot := uint64(0)
|
||||
|
||||
epoch := helpers.CurrentEpoch(beaconState)
|
||||
randaoReveal, err := helpers.CreateRandaoReveal(beaconState, epoch, privKeys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pendingDeposits := []*pb.Deposit{
|
||||
createPreChainStartDeposit(t, []byte{'F'}, beaconState.DepositIndex),
|
||||
createPreChainStartDeposit([]byte{'F'}),
|
||||
}
|
||||
pendingDepositsData := make([][]byte, len(pendingDeposits))
|
||||
for i, pd := range pendingDeposits {
|
||||
pendingDepositsData[i] = pd.DepositData
|
||||
h, err := hashutil.DepositHash(pd.Data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pendingDepositsData[i] = h[:]
|
||||
}
|
||||
depositTrie, err := trieutil.GenerateTrieFromItems(pendingDepositsData, int(params.BeaconConfig().DepositContractTreeDepth))
|
||||
if err != nil {
|
||||
t.Fatalf("Could not generate deposit trie: %v", err)
|
||||
}
|
||||
for i := range pendingDeposits {
|
||||
pendingDeposits[i].MerkleTreeIndex = 0
|
||||
proof, err := depositTrie.MerkleProof(int(pendingDeposits[i].MerkleTreeIndex))
|
||||
proof, err := depositTrie.MerkleProof(0)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not generate proof: %v", err)
|
||||
}
|
||||
pendingDeposits[i].MerkleProofHash32S = proof
|
||||
pendingDeposits[i].Proof = proof
|
||||
}
|
||||
depositRoot := depositTrie.Root()
|
||||
beaconState.LatestEth1Data.DepositRootHash32 = depositRoot[:]
|
||||
beaconState.Eth1Data.DepositRoot = depositRoot[:]
|
||||
if err := db.SaveHistoricalState(context.Background(), beaconState, parentHash); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
parentRoot, err := ssz.SigningRoot(genesis)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: currentSlot + 1,
|
||||
StateRootHash32: stateRoot[:],
|
||||
ParentRootHash32: parentHash[:],
|
||||
RandaoReveal: randaoReveal,
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositRootHash32: []byte("a"),
|
||||
BlockHash32: []byte("b"),
|
||||
},
|
||||
Slot: currentSlot + 1,
|
||||
StateRoot: stateRoot[:],
|
||||
ParentRoot: parentRoot[:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Deposits: pendingDeposits,
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositRoot: []byte("a"),
|
||||
BlockHash: []byte("b"),
|
||||
},
|
||||
RandaoReveal: randaoReveal,
|
||||
Deposits: pendingDeposits,
|
||||
},
|
||||
}
|
||||
|
||||
beaconState.LatestBlock = block
|
||||
beaconState.Slot--
|
||||
beaconState.DepositIndex = 0
|
||||
|
||||
beaconState.Eth1DepositIndex = 0
|
||||
if err := chainService.beaconDB.SaveState(ctx, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
initBlockStateRoot(t, block, chainService)
|
||||
|
||||
blockRoot, err := hashutil.HashBeaconBlock(block)
|
||||
blockRoot, err := ssz.SigningRoot(block)
|
||||
if err != nil {
|
||||
log.Fatalf("could not hash block: %v", err)
|
||||
}
|
||||
@@ -495,7 +589,7 @@ func TestReceiveBlock_RemovesPendingDeposits(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, dep := range pendingDeposits {
|
||||
db.InsertPendingDeposit(chainService.ctx, dep, big.NewInt(0))
|
||||
db.InsertPendingDeposit(chainService.ctx, dep, big.NewInt(0), 0, [32]byte{})
|
||||
}
|
||||
|
||||
if len(db.PendingDeposits(chainService.ctx, nil)) != len(pendingDeposits) || len(pendingDeposits) == 0 {
|
||||
@@ -513,11 +607,11 @@ func TestReceiveBlock_RemovesPendingDeposits(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i := 0; i < len(beaconState.ValidatorRegistry); i++ {
|
||||
pubKey := bytesutil.ToBytes48(beaconState.ValidatorRegistry[i].Pubkey)
|
||||
for i := 0; i < len(beaconState.Validators); i++ {
|
||||
pubKey := bytesutil.ToBytes48(beaconState.Validators[i].Pubkey)
|
||||
attsService.InsertAttestationIntoStore(pubKey, &pb.Attestation{
|
||||
Data: &pb.AttestationData{
|
||||
BeaconBlockRootHash32: blockRoot[:],
|
||||
BeaconBlockRoot: blockRoot[:],
|
||||
}},
|
||||
)
|
||||
}
|
||||
@@ -569,56 +663,74 @@ func TestReceiveBlock_OnChainSplit(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
chainService := setupBeaconChain(t, db, nil)
|
||||
deposits, privKeys := setupInitialDeposits(t, 100)
|
||||
eth1Data := &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{},
|
||||
BlockHash32: []byte{},
|
||||
}
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, eth1Data)
|
||||
deposits, privKeys := testutil.SetupInitialDeposits(t, 100, true)
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't generate genesis state: %v", err)
|
||||
}
|
||||
stateRoot, err := hashutil.HashProto(beaconState)
|
||||
beaconState.Eth1DepositIndex = 100
|
||||
genesis := b.NewGenesisBlock([]byte{})
|
||||
bodyRoot, err := ssz.HashTreeRoot(genesis.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.StateRoots = make([][]byte, params.BeaconConfig().HistoricalRootsLimit)
|
||||
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
|
||||
Slot: genesis.Slot,
|
||||
ParentRoot: genesis.ParentRoot,
|
||||
BodyRoot: bodyRoot[:],
|
||||
}
|
||||
stateRoot, err := ssz.HashTreeRoot(beaconState)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not tree hash state: %v", err)
|
||||
}
|
||||
parentHash, genesisBlock := setupGenesisBlock(t, chainService)
|
||||
beaconState.LatestBlock = genesisBlock
|
||||
_, genesisBlock := setupGenesisBlock(t, chainService)
|
||||
if err := db.UpdateChainHead(ctx, genesisBlock, beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.SaveFinalizedState(beaconState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
genesisSlot := params.BeaconConfig().GenesisSlot
|
||||
genesisSlot := uint64(0)
|
||||
|
||||
parentRoot, err := ssz.SigningRoot(genesisBlock)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
epoch := helpers.CurrentEpoch(beaconState)
|
||||
randaoReveal, err := helpers.CreateRandaoReveal(beaconState, epoch, privKeys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Top chain slots (see graph)
|
||||
blockSlots := []uint64{1, 2, 3, 5, 8}
|
||||
for _, slot := range blockSlots {
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: genesisSlot + slot,
|
||||
StateRootHash32: stateRoot[:],
|
||||
ParentRootHash32: parentHash[:],
|
||||
RandaoReveal: createRandaoReveal(t, beaconState, privKeys),
|
||||
Body: &pb.BeaconBlockBody{},
|
||||
Slot: genesisSlot + slot,
|
||||
StateRoot: stateRoot[:],
|
||||
ParentRoot: parentRoot[:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{},
|
||||
RandaoReveal: randaoReveal,
|
||||
},
|
||||
}
|
||||
initBlockStateRoot(t, block, chainService)
|
||||
computedState, err := chainService.ReceiveBlock(ctx, block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stateRoot, err = hashutil.HashProto(computedState)
|
||||
stateRoot, err = ssz.HashTreeRoot(computedState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = db.SaveBlock(block); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
computedState.LatestBlock = block
|
||||
if err = db.UpdateChainHead(ctx, block, computedState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
parentHash, err = hashutil.HashBeaconBlock(block)
|
||||
parentRoot, err = ssz.SigningRoot(block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -630,39 +742,48 @@ func TestReceiveBlock_OnChainSplit(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
parentHash, err = hashutil.HashBeaconBlock(commonAncestor)
|
||||
parentRoot, err = ssz.SigningRoot(commonAncestor)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
beaconState, err = db.HistoricalStateFromSlot(ctx, commonAncestor.Slot, parentHash)
|
||||
beaconState, err = db.HistoricalStateFromSlot(ctx, commonAncestor.Slot, parentRoot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stateRoot, err = hashutil.HashProto(beaconState)
|
||||
stateRoot, err = ssz.HashTreeRoot(beaconState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
epoch = helpers.CurrentEpoch(beaconState)
|
||||
randaoReveal, err = helpers.CreateRandaoReveal(beaconState, epoch, privKeys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Then we receive the block `f` from slot 6
|
||||
blockF := &pb.BeaconBlock{
|
||||
Slot: genesisSlot + 6,
|
||||
ParentRootHash32: parentHash[:],
|
||||
StateRootHash32: stateRoot[:],
|
||||
RandaoReveal: createRandaoReveal(t, beaconState, privKeys),
|
||||
Body: &pb.BeaconBlockBody{},
|
||||
Slot: genesisSlot + 6,
|
||||
ParentRoot: parentRoot[:],
|
||||
StateRoot: stateRoot[:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{},
|
||||
RandaoReveal: randaoReveal,
|
||||
},
|
||||
}
|
||||
rootF, _ := hashutil.HashBeaconBlock(blockF)
|
||||
rootF, _ := ssz.SigningRoot(blockF)
|
||||
if err := db.SaveHistoricalState(ctx, beaconState, rootF); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
initBlockStateRoot(t, blockF, chainService)
|
||||
|
||||
initBlockStateRoot(t, blockF, chainService)
|
||||
computedState, err := chainService.ReceiveBlock(ctx, blockF)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stateRoot, err = hashutil.HashProto(computedState)
|
||||
stateRoot, err = ssz.HashTreeRoot(computedState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -671,18 +792,26 @@ func TestReceiveBlock_OnChainSplit(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
parentHash, err = hashutil.HashBeaconBlock(blockF)
|
||||
parentRoot, err = ssz.SigningRoot(blockF)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
epoch = helpers.CurrentEpoch(beaconState)
|
||||
randaoReveal, err = helpers.CreateRandaoReveal(beaconState, epoch, privKeys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Then we apply block `g` from slot 7
|
||||
blockG := &pb.BeaconBlock{
|
||||
Slot: genesisSlot + 7,
|
||||
ParentRootHash32: parentHash[:],
|
||||
StateRootHash32: stateRoot[:],
|
||||
RandaoReveal: createRandaoReveal(t, computedState, privKeys),
|
||||
Body: &pb.BeaconBlockBody{},
|
||||
Slot: genesisSlot + 7,
|
||||
ParentRoot: parentRoot[:],
|
||||
StateRoot: stateRoot[:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{},
|
||||
RandaoReveal: randaoReveal,
|
||||
},
|
||||
}
|
||||
initBlockStateRoot(t, blockG, chainService)
|
||||
|
||||
@@ -703,63 +832,79 @@ func TestIsBlockReadyForProcessing_ValidBlock(t *testing.T) {
|
||||
|
||||
chainService := setupBeaconChain(t, db, nil)
|
||||
unixTime := uint64(time.Now().Unix())
|
||||
deposits, privKeys := setupInitialDeposits(t, 100)
|
||||
if err := db.InitializeState(context.Background(), unixTime, deposits, &pb.Eth1Data{}); err != nil {
|
||||
deposits, privKeys := testutil.SetupInitialDeposits(t, 100, true)
|
||||
if err := db.InitializeState(context.Background(), unixTime, deposits, nil); err != nil {
|
||||
t.Fatalf("Could not initialize beacon state to disk: %v", err)
|
||||
}
|
||||
beaconState, err := db.HeadState(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't get genesis state: %v", err)
|
||||
}
|
||||
genesis := b.NewGenesisBlock([]byte{})
|
||||
bodyRoot, err := ssz.HashTreeRoot(genesis.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
beaconState.StateRoots = make([][]byte, params.BeaconConfig().HistoricalRootsLimit)
|
||||
beaconState.LatestBlockHeader = &pb.BeaconBlockHeader{
|
||||
Slot: genesis.Slot,
|
||||
ParentRoot: genesis.ParentRoot,
|
||||
BodyRoot: bodyRoot[:],
|
||||
}
|
||||
block := &pb.BeaconBlock{
|
||||
ParentRootHash32: []byte{'a'},
|
||||
ParentRoot: []byte{'a'},
|
||||
}
|
||||
|
||||
if err := chainService.VerifyBlockValidity(ctx, block, beaconState); err == nil {
|
||||
t.Fatal("block processing succeeded despite block having no parent saved")
|
||||
}
|
||||
|
||||
beaconState.Slot = params.BeaconConfig().GenesisSlot + 10
|
||||
beaconState.Slot = 10
|
||||
|
||||
stateRoot, err := hashutil.HashProto(beaconState)
|
||||
stateRoot, err := ssz.HashTreeRoot(beaconState)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not tree hash state: %v", err)
|
||||
}
|
||||
genesis := b.NewGenesisBlock([]byte{})
|
||||
if err := chainService.beaconDB.SaveBlock(genesis); err != nil {
|
||||
t.Fatalf("cannot save block: %v", err)
|
||||
}
|
||||
parentRoot, err := hashutil.HashBeaconBlock(genesis)
|
||||
parentRoot, err := ssz.SigningRoot(genesis)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get root of canonical head: %v", err)
|
||||
}
|
||||
|
||||
beaconState.LatestEth1Data = &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{2},
|
||||
BlockHash32: []byte{3},
|
||||
beaconState.Eth1Data = &pb.Eth1Data{
|
||||
DepositRoot: []byte{2},
|
||||
BlockHash: []byte{3},
|
||||
}
|
||||
beaconState.Slot = params.BeaconConfig().GenesisSlot
|
||||
beaconState.Slot = 0
|
||||
|
||||
currentSlot := params.BeaconConfig().GenesisSlot + 1
|
||||
attestationSlot := params.BeaconConfig().GenesisSlot
|
||||
currentSlot := uint64(1)
|
||||
|
||||
epoch := helpers.CurrentEpoch(beaconState)
|
||||
randaoReveal, err := helpers.CreateRandaoReveal(beaconState, epoch, privKeys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
randaoReveal := createRandaoReveal(t, beaconState, privKeys)
|
||||
block2 := &pb.BeaconBlock{
|
||||
Slot: currentSlot,
|
||||
StateRootHash32: stateRoot[:],
|
||||
ParentRootHash32: parentRoot[:],
|
||||
RandaoReveal: randaoReveal,
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositRootHash32: []byte("a"),
|
||||
BlockHash32: []byte("b"),
|
||||
},
|
||||
Slot: currentSlot,
|
||||
StateRoot: stateRoot[:],
|
||||
ParentRoot: parentRoot[:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositRoot: []byte("a"),
|
||||
BlockHash: []byte("b"),
|
||||
},
|
||||
RandaoReveal: randaoReveal,
|
||||
Attestations: []*pb.Attestation{{
|
||||
AggregationBitfield: []byte{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
AggregationBits: []byte{128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
Data: &pb.AttestationData{
|
||||
Slot: attestationSlot,
|
||||
JustifiedBlockRootHash32: parentRoot[:],
|
||||
Source: &pb.Checkpoint{Root: parentRoot[:]},
|
||||
Crosslink: &pb.Crosslink{
|
||||
Shard: 960,
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
@@ -785,8 +930,8 @@ func TestDeleteValidatorIdx_DeleteWorks(t *testing.T) {
|
||||
})
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: validators,
|
||||
Slot: epoch * params.BeaconConfig().SlotsPerEpoch,
|
||||
Validators: validators,
|
||||
Slot: epoch * params.BeaconConfig().SlotsPerEpoch,
|
||||
}
|
||||
chainService := setupBeaconChain(t, db, nil)
|
||||
if err := chainService.saveValidatorIdx(state); err != nil {
|
||||
@@ -827,8 +972,8 @@ func TestSaveValidatorIdx_SaveRetrieveWorks(t *testing.T) {
|
||||
})
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: validators,
|
||||
Slot: epoch * params.BeaconConfig().SlotsPerEpoch,
|
||||
Validators: validators,
|
||||
Slot: epoch * params.BeaconConfig().SlotsPerEpoch,
|
||||
}
|
||||
chainService := setupBeaconChain(t, db, nil)
|
||||
if err := chainService.saveValidatorIdx(state); err != nil {
|
||||
@@ -854,7 +999,7 @@ func TestSaveValidatorIdx_IdxNotInState(t *testing.T) {
|
||||
defer internal.TeardownDB(t, db)
|
||||
epoch := uint64(100)
|
||||
|
||||
// Tried to insert 5 active indices to DB with only 3 validators in state.
|
||||
// Tried to insert 5 active indices to DB with only 3 validators in state
|
||||
v.InsertActivatedIndices(epoch+1, []uint64{0, 1, 2, 3, 4})
|
||||
var validators []*pb.Validator
|
||||
for i := 0; i < 3; i++ {
|
||||
@@ -865,8 +1010,8 @@ func TestSaveValidatorIdx_IdxNotInState(t *testing.T) {
|
||||
})
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: validators,
|
||||
Slot: epoch * params.BeaconConfig().SlotsPerEpoch,
|
||||
Validators: validators,
|
||||
Slot: epoch * params.BeaconConfig().SlotsPerEpoch,
|
||||
}
|
||||
chainService := setupBeaconChain(t, db, nil)
|
||||
if err := chainService.saveValidatorIdx(state); err != nil {
|
||||
@@ -886,7 +1031,7 @@ func TestSaveValidatorIdx_IdxNotInState(t *testing.T) {
|
||||
t.Errorf("Activated validators mapping for epoch %d still there", epoch)
|
||||
}
|
||||
|
||||
// Verify the skipped validators are included in the next epoch.
|
||||
// Verify the skipped validators are included in the next epoch
|
||||
if !reflect.DeepEqual(v.ActivatedValFromEpoch(epoch+2), []uint64{3, 4}) {
|
||||
t.Error("Did not get wanted validator from activation queue")
|
||||
}
|
||||
|
||||
@@ -8,13 +8,12 @@ import (
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
@@ -43,7 +42,7 @@ type TargetsFetcher interface {
|
||||
// are not older than the ones just processed in state. If it's older, we update
|
||||
// the db with the latest FFG check points, both justification and finalization.
|
||||
func (c *ChainService) updateFFGCheckPts(ctx context.Context, state *pb.BeaconState) error {
|
||||
lastJustifiedSlot := helpers.StartSlot(state.JustifiedEpoch)
|
||||
lastJustifiedSlot := helpers.StartSlot(state.CurrentJustifiedCheckpoint.Epoch)
|
||||
savedJustifiedBlock, err := c.beaconDB.JustifiedBlock()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -60,7 +59,7 @@ func (c *ChainService) updateFFGCheckPts(ctx context.Context, state *pb.BeaconSt
|
||||
// until we can get a block.
|
||||
lastAvailBlkSlot := lastJustifiedSlot
|
||||
for newJustifiedBlock == nil {
|
||||
log.WithField("slot", lastAvailBlkSlot-params.BeaconConfig().GenesisSlot).Debug("Missing block in DB, looking one slot back")
|
||||
log.WithField("slot", lastAvailBlkSlot).Debug("Missing block in DB, looking one slot back")
|
||||
lastAvailBlkSlot--
|
||||
newJustifiedBlock, err = c.beaconDB.CanonicalBlockBySlot(ctx, lastAvailBlkSlot)
|
||||
if err != nil {
|
||||
@@ -68,7 +67,7 @@ func (c *ChainService) updateFFGCheckPts(ctx context.Context, state *pb.BeaconSt
|
||||
}
|
||||
}
|
||||
|
||||
newJustifiedRoot, err := hashutil.HashBeaconBlock(newJustifiedBlock)
|
||||
newJustifiedRoot, err := ssz.SigningRoot(newJustifiedBlock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -85,7 +84,7 @@ func (c *ChainService) updateFFGCheckPts(ctx context.Context, state *pb.BeaconSt
|
||||
}
|
||||
}
|
||||
|
||||
lastFinalizedSlot := helpers.StartSlot(state.FinalizedEpoch)
|
||||
lastFinalizedSlot := helpers.StartSlot(state.FinalizedCheckpoint.Epoch)
|
||||
savedFinalizedBlock, err := c.beaconDB.FinalizedBlock()
|
||||
// If the last processed finalized slot in state is greater than
|
||||
// the slot of finalized block saved in DB.
|
||||
@@ -102,7 +101,7 @@ func (c *ChainService) updateFFGCheckPts(ctx context.Context, state *pb.BeaconSt
|
||||
// until we can get a block.
|
||||
lastAvailBlkSlot := lastFinalizedSlot
|
||||
for newFinalizedBlock == nil {
|
||||
log.WithField("slot", lastAvailBlkSlot-params.BeaconConfig().GenesisSlot).Debug("Missing block in DB, looking one slot back")
|
||||
log.WithField("slot", lastAvailBlkSlot).Debug("Missing block in DB, looking one slot back")
|
||||
lastAvailBlkSlot--
|
||||
newFinalizedBlock, err = c.beaconDB.CanonicalBlockBySlot(ctx, lastAvailBlkSlot)
|
||||
if err != nil {
|
||||
@@ -110,7 +109,7 @@ func (c *ChainService) updateFFGCheckPts(ctx context.Context, state *pb.BeaconSt
|
||||
}
|
||||
}
|
||||
|
||||
newFinalizedRoot, err := hashutil.HashBeaconBlock(newFinalizedBlock)
|
||||
newFinalizedRoot, err := ssz.SigningRoot(newFinalizedBlock)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -160,7 +159,7 @@ func (c *ChainService) ApplyForkChoiceRule(
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not run fork choice: %v", err)
|
||||
}
|
||||
newHeadRoot, err := hashutil.HashBeaconBlock(newHead)
|
||||
newHeadRoot, err := ssz.SigningRoot(newHead)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not hash new head block: %v", err)
|
||||
}
|
||||
@@ -172,7 +171,7 @@ func (c *ChainService) ApplyForkChoiceRule(
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not retrieve chain head: %v", err)
|
||||
}
|
||||
currentHeadRoot, err := hashutil.HashBeaconBlock(currentHead)
|
||||
currentHeadRoot, err := ssz.SigningRoot(currentHead)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not hash current head block: %v", err)
|
||||
}
|
||||
@@ -185,9 +184,9 @@ func (c *ChainService) ApplyForkChoiceRule(
|
||||
newState := postState
|
||||
if !isDescendant && !proto.Equal(currentHead, newHead) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"currentSlot": currentHead.Slot - params.BeaconConfig().GenesisSlot,
|
||||
"currentSlot": currentHead.Slot,
|
||||
"currentRoot": fmt.Sprintf("%#x", bytesutil.Trunc(currentHeadRoot[:])),
|
||||
"newSlot": newHead.Slot - params.BeaconConfig().GenesisSlot,
|
||||
"newSlot": newHead.Slot,
|
||||
"newRoot": fmt.Sprintf("%#x", bytesutil.Trunc(newHeadRoot[:])),
|
||||
}).Warn("Reorg happened")
|
||||
// Only regenerate head state if there was a reorg.
|
||||
@@ -204,7 +203,7 @@ func (c *ChainService) ApplyForkChoiceRule(
|
||||
|
||||
if proto.Equal(currentHead, newHead) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"currentSlot": currentHead.Slot - params.BeaconConfig().GenesisSlot,
|
||||
"currentSlot": currentHead.Slot,
|
||||
"currentRoot": fmt.Sprintf("%#x", bytesutil.Trunc(currentHeadRoot[:])),
|
||||
}).Warn("Head did not change after fork choice, current head has the most votes")
|
||||
}
|
||||
@@ -220,14 +219,14 @@ func (c *ChainService) ApplyForkChoiceRule(
|
||||
if err := c.beaconDB.UpdateChainHead(ctx, newHead, newState); err != nil {
|
||||
return fmt.Errorf("failed to update chain: %v", err)
|
||||
}
|
||||
h, err := hashutil.HashBeaconBlock(newHead)
|
||||
h, err := ssz.SigningRoot(newHead)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not hash head: %v", err)
|
||||
}
|
||||
log.WithFields(logrus.Fields{
|
||||
"headRoot": fmt.Sprintf("%#x", bytesutil.Trunc(h[:])),
|
||||
"headSlot": newHead.Slot - params.BeaconConfig().GenesisSlot,
|
||||
"stateSlot": newState.Slot - params.BeaconConfig().GenesisSlot,
|
||||
"headSlot": newHead.Slot,
|
||||
"stateSlot": newState.Slot,
|
||||
}).Info("Chain head block and state updated")
|
||||
|
||||
return nil
|
||||
@@ -288,11 +287,11 @@ func (c *ChainService) lmdGhost(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to determine vote count for block: %v", err)
|
||||
}
|
||||
maxChildRoot, err := hashutil.HashBeaconBlock(maxChild)
|
||||
maxChildRoot, err := ssz.SigningRoot(maxChild)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
candidateChildRoot, err := hashutil.HashBeaconBlock(children[i])
|
||||
candidateChildRoot, err := ssz.SigningRoot(children[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -318,7 +317,7 @@ func (c *ChainService) lmdGhost(
|
||||
// get_children(store: Store, block: BeaconBlock) -> List[BeaconBlock]
|
||||
// returns the child blocks of the given block.
|
||||
func (c *ChainService) BlockChildren(ctx context.Context, block *pb.BeaconBlock, highestSlot uint64) ([]*pb.BeaconBlock, error) {
|
||||
blockRoot, err := hashutil.HashBeaconBlock(block)
|
||||
blockRoot, err := ssz.SigningRoot(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -334,7 +333,7 @@ func (c *ChainService) BlockChildren(ctx context.Context, block *pb.BeaconBlock,
|
||||
|
||||
filteredChildren := []*pb.BeaconBlock{}
|
||||
for _, kid := range children {
|
||||
parentRoot := bytesutil.ToBytes32(kid.ParentRootHash32)
|
||||
parentRoot := bytesutil.ToBytes32(kid.ParentRoot)
|
||||
if blockRoot == parentRoot {
|
||||
filteredChildren = append(filteredChildren, kid)
|
||||
}
|
||||
@@ -344,15 +343,15 @@ func (c *ChainService) BlockChildren(ctx context.Context, block *pb.BeaconBlock,
|
||||
|
||||
// isDescendant checks if the new head block is a descendant block of the current head.
|
||||
func (c *ChainService) isDescendant(currentHead *pb.BeaconBlock, newHead *pb.BeaconBlock) (bool, error) {
|
||||
currentHeadRoot, err := hashutil.HashBeaconBlock(currentHead)
|
||||
currentHeadRoot, err := ssz.SigningRoot(currentHead)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
for newHead.Slot > currentHead.Slot {
|
||||
if bytesutil.ToBytes32(newHead.ParentRootHash32) == currentHeadRoot {
|
||||
if bytesutil.ToBytes32(newHead.ParentRoot) == currentHeadRoot {
|
||||
return true, nil
|
||||
}
|
||||
newHead, err = c.beaconDB.Block(bytesutil.ToBytes32(newHead.ParentRootHash32))
|
||||
newHead, err = c.beaconDB.Block(bytesutil.ToBytes32(newHead.ParentRoot))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -367,7 +366,11 @@ func (c *ChainService) isDescendant(currentHead *pb.BeaconBlock, newHead *pb.Bea
|
||||
// each attestation target consists of validator index and its attestation target (i.e. the block
|
||||
// which the validator attested to)
|
||||
func (c *ChainService) AttestationTargets(state *pb.BeaconState) (map[uint64]*pb.AttestationTarget, error) {
|
||||
indices := helpers.ActiveValidatorIndices(state.ValidatorRegistry, helpers.CurrentEpoch(state))
|
||||
indices, err := helpers.ActiveValidatorIndices(state, helpers.CurrentEpoch(state))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
attestationTargets := make(map[uint64]*pb.AttestationTarget)
|
||||
for i, index := range indices {
|
||||
target, err := c.attsService.LatestAttestationTarget(state, index)
|
||||
@@ -397,7 +400,7 @@ func VoteCount(block *pb.BeaconBlock, state *pb.BeaconState, targets map[uint64]
|
||||
var ancestorRoot []byte
|
||||
var err error
|
||||
|
||||
blockRoot, err := hashutil.HashBeaconBlock(block)
|
||||
blockRoot, err := ssz.SigningRoot(block)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -417,7 +420,7 @@ func VoteCount(block *pb.BeaconBlock, state *pb.BeaconState, targets map[uint64]
|
||||
}
|
||||
|
||||
if bytes.Equal(blockRoot[:], ancestorRoot) {
|
||||
balances += int(helpers.EffectiveBalance(state, validatorIndex))
|
||||
balances += int(state.Validators[validatorIndex].EffectiveBalance)
|
||||
}
|
||||
}
|
||||
return balances, nil
|
||||
@@ -454,7 +457,7 @@ func BlockAncestor(targetBlock *pb.AttestationTarget, slot uint64, beaconDB *db.
|
||||
newTarget := &pb.AttestationTarget{
|
||||
Slot: parent.Slot,
|
||||
BlockRoot: parentRoot[:],
|
||||
ParentRoot: parent.ParentRootHash32,
|
||||
ParentRoot: parent.ParentRoot,
|
||||
}
|
||||
return BlockAncestor(newTarget, slot, beaconDB)
|
||||
}
|
||||
@@ -485,7 +488,7 @@ func cachedAncestor(target *pb.AttestationTarget, height uint64, beaconDB *db.Be
|
||||
ancestorTarget := &pb.AttestationTarget{
|
||||
Slot: ancestor.Slot,
|
||||
BlockRoot: ancestorRoot,
|
||||
ParentRoot: ancestor.ParentRootHash32,
|
||||
ParentRoot: ancestor.ParentRoot,
|
||||
}
|
||||
if err := blkAncestorCache.AddBlockAncestor(&cache.AncestorInfo{
|
||||
Height: height,
|
||||
|
||||
@@ -5,10 +5,10 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/internal"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
@@ -27,20 +27,22 @@ func (m *mockAttestationHandler) BatchUpdateLatestAttestation(ctx context.Contex
|
||||
}
|
||||
|
||||
func TestApplyForkChoice_ChainSplitReorg(t *testing.T) {
|
||||
// TODO(#2307): Fix test once v0.6 is merged.
|
||||
t.Skip()
|
||||
hook := logTest.NewGlobal()
|
||||
beaconDB := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, beaconDB)
|
||||
|
||||
ctx := context.Background()
|
||||
deposits, _ := setupInitialDeposits(t, 100)
|
||||
eth1Data := &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{},
|
||||
BlockHash32: []byte{},
|
||||
}
|
||||
justifiedState, err := state.GenesisBeaconState(deposits, 0, eth1Data)
|
||||
deposits, _ := testutil.SetupInitialDeposits(t, 100, false)
|
||||
justifiedState, err := state.GenesisBeaconState(deposits, 0, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Can't generate genesis state: %v", err)
|
||||
}
|
||||
justifiedState.StateRoots = make([][]byte, params.BeaconConfig().HistoricalRootsLimit)
|
||||
justifiedState.LatestBlockHeader = &pb.BeaconBlockHeader{
|
||||
StateRoot: []byte{},
|
||||
}
|
||||
|
||||
chainService := setupBeaconChain(t, beaconDB, nil)
|
||||
|
||||
@@ -54,7 +56,6 @@ func TestApplyForkChoice_ChainSplitReorg(t *testing.T) {
|
||||
if err := chainService.beaconDB.SaveBlock(blocks[0]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
justifiedState.LatestBlock = blocks[0]
|
||||
if err := chainService.beaconDB.SaveJustifiedState(justifiedState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -67,7 +68,7 @@ func TestApplyForkChoice_ChainSplitReorg(t *testing.T) {
|
||||
canonicalBlockIndices := []int{1, 3, 5}
|
||||
postState := proto.Clone(justifiedState).(*pb.BeaconState)
|
||||
for _, canonicalIndex := range canonicalBlockIndices {
|
||||
postState, err = chainService.ApplyBlockStateTransition(ctx, blocks[canonicalIndex], postState)
|
||||
postState, err = chainService.AdvanceState(ctx, postState, blocks[canonicalIndex])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -86,8 +87,8 @@ func TestApplyForkChoice_ChainSplitReorg(t *testing.T) {
|
||||
if chainHead.Slot != justifiedState.Slot+5 {
|
||||
t.Errorf(
|
||||
"Expected chain head with slot %d, received %d",
|
||||
justifiedState.Slot+5-params.BeaconConfig().GenesisSlot,
|
||||
chainHead.Slot-params.BeaconConfig().GenesisSlot,
|
||||
justifiedState.Slot+5,
|
||||
chainHead.Slot,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -96,7 +97,7 @@ func TestApplyForkChoice_ChainSplitReorg(t *testing.T) {
|
||||
forkedBlockIndices := []int{2, 4}
|
||||
forkState := proto.Clone(justifiedState).(*pb.BeaconState)
|
||||
for _, forkIndex := range forkedBlockIndices {
|
||||
forkState, err = chainService.ApplyBlockStateTransition(ctx, blocks[forkIndex], forkState)
|
||||
forkState, err = chainService.AdvanceState(ctx, forkState, blocks[forkIndex])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -113,13 +114,13 @@ func TestApplyForkChoice_ChainSplitReorg(t *testing.T) {
|
||||
voteTargets[0] = &pb.AttestationTarget{
|
||||
Slot: blocks[5].Slot,
|
||||
BlockRoot: roots[5][:],
|
||||
ParentRoot: blocks[5].ParentRootHash32,
|
||||
ParentRoot: blocks[5].ParentRoot,
|
||||
}
|
||||
for i := 1; i < len(deposits); i++ {
|
||||
voteTargets[uint64(i)] = &pb.AttestationTarget{
|
||||
Slot: blocks[4].Slot,
|
||||
BlockRoot: roots[4][:],
|
||||
ParentRoot: blocks[4].ParentRootHash32,
|
||||
ParentRoot: blocks[4].ParentRoot,
|
||||
}
|
||||
}
|
||||
attHandler := &mockAttestationHandler{
|
||||
@@ -159,61 +160,73 @@ func constructForkedChain(t *testing.T, beaconState *pb.BeaconState) ([]*pb.Beac
|
||||
roots := make([][32]byte, 6)
|
||||
var err error
|
||||
blocks[0] = &pb.BeaconBlock{
|
||||
Slot: beaconState.Slot,
|
||||
ParentRootHash32: []byte{'A'},
|
||||
Body: &pb.BeaconBlockBody{},
|
||||
Slot: beaconState.Slot,
|
||||
ParentRoot: []byte{'A'},
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{},
|
||||
},
|
||||
}
|
||||
roots[0], err = hashutil.HashBeaconBlock(blocks[0])
|
||||
roots[0], err = ssz.SigningRoot(blocks[0])
|
||||
if err != nil {
|
||||
t.Fatalf("Could not hash block: %v", err)
|
||||
}
|
||||
|
||||
blocks[1] = &pb.BeaconBlock{
|
||||
Slot: beaconState.Slot + 2,
|
||||
ParentRootHash32: roots[0][:],
|
||||
Body: &pb.BeaconBlockBody{},
|
||||
Slot: beaconState.Slot + 2,
|
||||
ParentRoot: roots[0][:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{},
|
||||
},
|
||||
}
|
||||
roots[1], err = hashutil.HashBeaconBlock(blocks[1])
|
||||
roots[1], err = ssz.SigningRoot(blocks[1])
|
||||
if err != nil {
|
||||
t.Fatalf("Could not hash block: %v", err)
|
||||
}
|
||||
|
||||
blocks[2] = &pb.BeaconBlock{
|
||||
Slot: beaconState.Slot + 1,
|
||||
ParentRootHash32: roots[0][:],
|
||||
Body: &pb.BeaconBlockBody{},
|
||||
Slot: beaconState.Slot + 1,
|
||||
ParentRoot: roots[0][:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{},
|
||||
},
|
||||
}
|
||||
roots[2], err = hashutil.HashBeaconBlock(blocks[2])
|
||||
roots[2], err = ssz.SigningRoot(blocks[2])
|
||||
if err != nil {
|
||||
t.Fatalf("Could not hash block: %v", err)
|
||||
}
|
||||
|
||||
blocks[3] = &pb.BeaconBlock{
|
||||
Slot: beaconState.Slot + 3,
|
||||
ParentRootHash32: roots[1][:],
|
||||
Body: &pb.BeaconBlockBody{},
|
||||
Slot: beaconState.Slot + 3,
|
||||
ParentRoot: roots[1][:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{},
|
||||
},
|
||||
}
|
||||
roots[3], err = hashutil.HashBeaconBlock(blocks[3])
|
||||
roots[3], err = ssz.SigningRoot(blocks[3])
|
||||
if err != nil {
|
||||
t.Fatalf("Could not hash block: %v", err)
|
||||
}
|
||||
|
||||
blocks[4] = &pb.BeaconBlock{
|
||||
Slot: beaconState.Slot + 4,
|
||||
ParentRootHash32: roots[2][:],
|
||||
Body: &pb.BeaconBlockBody{},
|
||||
Slot: beaconState.Slot + 4,
|
||||
ParentRoot: roots[2][:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{},
|
||||
},
|
||||
}
|
||||
roots[4], err = hashutil.HashBeaconBlock(blocks[4])
|
||||
roots[4], err = ssz.SigningRoot(blocks[4])
|
||||
if err != nil {
|
||||
t.Fatalf("Could not hash block: %v", err)
|
||||
}
|
||||
|
||||
blocks[5] = &pb.BeaconBlock{
|
||||
Slot: beaconState.Slot + 5,
|
||||
ParentRootHash32: roots[3][:],
|
||||
Body: &pb.BeaconBlockBody{},
|
||||
Slot: beaconState.Slot + 5,
|
||||
ParentRoot: roots[3][:],
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Eth1Data: &pb.Eth1Data{},
|
||||
},
|
||||
}
|
||||
roots[5], err = hashutil.HashBeaconBlock(blocks[5])
|
||||
roots[5], err = ssz.SigningRoot(blocks[5])
|
||||
if err != nil {
|
||||
t.Fatalf("Could not hash block: %v", err)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/attestation"
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
@@ -18,7 +19,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/event"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/p2p"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
@@ -95,7 +95,7 @@ func (c *ChainService) Start() {
|
||||
if beaconState != nil {
|
||||
log.Info("Beacon chain data already exists, starting service")
|
||||
c.genesisTime = time.Unix(int64(beaconState.GenesisTime), 0)
|
||||
c.finalizedEpoch = beaconState.FinalizedEpoch
|
||||
c.finalizedEpoch = beaconState.FinalizedCheckpoint.Epoch
|
||||
} else {
|
||||
log.Info("Waiting for ChainStart log from the Validator Deposit Contract to start the beacon chain...")
|
||||
if c.web3Service == nil {
|
||||
@@ -114,17 +114,12 @@ func (c *ChainService) Start() {
|
||||
// processChainStartTime initializes a series of deposits from the ChainStart deposits in the eth1
|
||||
// deposit contract, initializes the beacon chain's state, and kicks off the beacon chain.
|
||||
func (c *ChainService) processChainStartTime(genesisTime time.Time, chainStartSub event.Subscription) {
|
||||
initialDepositsData := c.web3Service.ChainStartDeposits()
|
||||
initialDeposits := make([]*pb.Deposit, len(initialDepositsData))
|
||||
for i := range initialDepositsData {
|
||||
initialDeposits[i] = &pb.Deposit{DepositData: initialDepositsData[i]}
|
||||
}
|
||||
|
||||
initialDeposits := c.web3Service.ChainStartDeposits()
|
||||
beaconState, err := c.initializeBeaconChain(genesisTime, initialDeposits, c.web3Service.ChainStartETH1Data())
|
||||
if err != nil {
|
||||
log.Fatalf("Could not initialize beacon chain: %v", err)
|
||||
}
|
||||
c.finalizedEpoch = beaconState.FinalizedEpoch
|
||||
c.finalizedEpoch = beaconState.FinalizedCheckpoint.Epoch
|
||||
c.stateInitializedFeed.Send(genesisTime)
|
||||
chainStartSub.Unsubscribe()
|
||||
}
|
||||
@@ -132,8 +127,7 @@ func (c *ChainService) processChainStartTime(genesisTime time.Time, chainStartSu
|
||||
// initializes the state and genesis block of the beacon chain to persistent storage
|
||||
// based on a genesis timestamp value obtained from the ChainStart event emitted
|
||||
// by the ETH1.0 Deposit Contract and the POWChain service of the node.
|
||||
func (c *ChainService) initializeBeaconChain(genesisTime time.Time, deposits []*pb.Deposit,
|
||||
eth1data *pb.Eth1Data) (*pb.BeaconState, error) {
|
||||
func (c *ChainService) initializeBeaconChain(genesisTime time.Time, deposits []*pb.Deposit, eth1data *pb.Eth1Data) (*pb.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(context.Background(), "beacon-chain.ChainService.initializeBeaconChain")
|
||||
defer span.End()
|
||||
log.Info("ChainStart time reached, starting the beacon chain!")
|
||||
@@ -147,26 +141,23 @@ func (c *ChainService) initializeBeaconChain(genesisTime time.Time, deposits []*
|
||||
return nil, fmt.Errorf("could not attempt fetch beacon state: %v", err)
|
||||
}
|
||||
|
||||
stateRoot, err := hashutil.HashProto(beaconState)
|
||||
stateRoot, err := ssz.HashTreeRoot(beaconState)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not hash beacon state: %v", err)
|
||||
}
|
||||
genBlock := b.NewGenesisBlock(stateRoot[:])
|
||||
genBlockRoot, err := hashutil.HashBeaconBlock(genBlock)
|
||||
genBlockRoot, err := ssz.SigningRoot(genBlock)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not hash beacon block: %v", err)
|
||||
}
|
||||
|
||||
// TODO(#2011): Remove this in state caching.
|
||||
beaconState.LatestBlock = genBlock
|
||||
|
||||
if err := c.beaconDB.SaveBlock(genBlock); err != nil {
|
||||
return nil, fmt.Errorf("could not save genesis block to disk: %v", err)
|
||||
}
|
||||
if err := c.beaconDB.SaveAttestationTarget(ctx, &pb.AttestationTarget{
|
||||
Slot: genBlock.Slot,
|
||||
BlockRoot: genBlockRoot[:],
|
||||
ParentRoot: genBlock.ParentRootHash32,
|
||||
ParentRoot: genBlock.ParentRoot,
|
||||
}); err != nil {
|
||||
return nil, fmt.Errorf("failed to save attestation target: %v", err)
|
||||
}
|
||||
@@ -225,7 +216,7 @@ func (c *ChainService) ChainHeadRoot() ([32]byte, error) {
|
||||
return [32]byte{}, fmt.Errorf("could not retrieve chain head: %v", err)
|
||||
}
|
||||
|
||||
root, err := hashutil.HashBeaconBlock(head)
|
||||
root, err := ssz.SigningRoot(head)
|
||||
if err != nil {
|
||||
return [32]byte{}, fmt.Errorf("could not tree hash parent block: %v", err)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ package blockchain
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
@@ -14,18 +12,15 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
gethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/attestation"
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/internal"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/powchain"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/event"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/forkutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/p2p"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
@@ -156,54 +151,13 @@ func (mb *mockBroadcaster) Broadcast(_ context.Context, _ proto.Message) {
|
||||
|
||||
var _ = p2p.Broadcaster(&mockBroadcaster{})
|
||||
|
||||
func setupInitialDeposits(t *testing.T, numDeposits int) ([]*pb.Deposit, []*bls.SecretKey) {
|
||||
privKeys := make([]*bls.SecretKey, numDeposits)
|
||||
deposits := make([]*pb.Deposit, numDeposits)
|
||||
for i := 0; i < len(deposits); i++ {
|
||||
priv, err := bls.RandKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
depositInput := &pb.DepositInput{
|
||||
Pubkey: priv.PublicKey().Marshal(),
|
||||
}
|
||||
balance := params.BeaconConfig().MaxDepositAmount
|
||||
depositData, err := helpers.EncodeDepositData(depositInput, balance, time.Now().Unix())
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot encode data: %v", err)
|
||||
}
|
||||
deposits[i] = &pb.Deposit{
|
||||
DepositData: depositData,
|
||||
MerkleTreeIndex: uint64(i),
|
||||
}
|
||||
privKeys[i] = priv
|
||||
}
|
||||
return deposits, privKeys
|
||||
}
|
||||
func createPreChainStartDeposit(pk []byte) *pb.Deposit {
|
||||
balance := params.BeaconConfig().MaxEffectiveBalance
|
||||
depositData := &pb.DepositData{Pubkey: pk, Amount: balance, Signature: make([]byte, 96)}
|
||||
|
||||
func createPreChainStartDeposit(t *testing.T, pk []byte, index uint64) *pb.Deposit {
|
||||
depositInput := &pb.DepositInput{Pubkey: pk}
|
||||
balance := params.BeaconConfig().MaxDepositAmount
|
||||
depositData, err := helpers.EncodeDepositData(depositInput, balance, time.Now().Unix())
|
||||
if err != nil {
|
||||
t.Fatalf("Cannot encode data: %v", err)
|
||||
return &pb.Deposit{
|
||||
Data: depositData,
|
||||
}
|
||||
return &pb.Deposit{DepositData: depositData, MerkleTreeIndex: index}
|
||||
}
|
||||
|
||||
func createRandaoReveal(t *testing.T, beaconState *pb.BeaconState, privKeys []*bls.SecretKey) []byte {
|
||||
// We fetch the proposer's index as that is whom the RANDAO will be verified against.
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(beaconState, beaconState.Slot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
epoch := helpers.SlotToEpoch(beaconState.Slot)
|
||||
buf := make([]byte, 32)
|
||||
binary.LittleEndian.PutUint64(buf, epoch)
|
||||
domain := forkutil.DomainVersion(beaconState.Fork, epoch, params.BeaconConfig().DomainRandao)
|
||||
// We make the previous validator's index sign the message instead of the proposer.
|
||||
epochSignature := privKeys[proposerIdx].Sign(buf, domain)
|
||||
return epochSignature.Marshal()
|
||||
}
|
||||
|
||||
func setupGenesisBlock(t *testing.T, cs *ChainService) ([32]byte, *pb.BeaconBlock) {
|
||||
@@ -211,7 +165,7 @@ func setupGenesisBlock(t *testing.T, cs *ChainService) ([32]byte, *pb.BeaconBloc
|
||||
if err := cs.beaconDB.SaveBlock(genesis); err != nil {
|
||||
t.Fatalf("could not save block to db: %v", err)
|
||||
}
|
||||
parentHash, err := hashutil.HashBeaconBlock(genesis)
|
||||
parentHash, err := ssz.SigningRoot(genesis)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to get tree hash root of canonical head: %v", err)
|
||||
}
|
||||
@@ -289,7 +243,7 @@ func TestChainStartStop_Uninitialized(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if beaconState == nil || beaconState.Slot != params.BeaconConfig().GenesisSlot {
|
||||
if beaconState == nil || beaconState.Slot != 0 {
|
||||
t.Error("Expected canonical state feed to send a state with genesis block")
|
||||
}
|
||||
if err := chainService.Stop(); err != nil {
|
||||
@@ -311,8 +265,8 @@ func TestChainStartStop_Initialized(t *testing.T) {
|
||||
chainService := setupBeaconChain(t, db, nil)
|
||||
|
||||
unixTime := uint64(time.Now().Unix())
|
||||
deposits, _ := setupInitialDeposits(t, 100)
|
||||
if err := db.InitializeState(context.Background(), unixTime, deposits, &pb.Eth1Data{}); err != nil {
|
||||
deposits, _ := testutil.SetupInitialDeposits(t, 100, false)
|
||||
if err := db.InitializeState(context.Background(), unixTime, deposits, nil); err != nil {
|
||||
t.Fatalf("Could not initialize beacon state to disk: %v", err)
|
||||
}
|
||||
setupGenesisBlock(t, chainService)
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["state_generator.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/stategenerator",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/state:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_opencensus_go//trace:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = ["state_generator_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/chaintest/backend:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -1,179 +0,0 @@
|
||||
package stategenerator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "stategenerator")
|
||||
|
||||
// GenerateStateFromBlock generates state from the last finalized state to the input slot.
|
||||
// Ex:
|
||||
// 1A - 2B(finalized) - 3C - 4 - 5D - 6 - 7F (letters mean there's a block).
|
||||
// Input: slot 6.
|
||||
// Output: resulting state of state transition function after applying block C and D.
|
||||
// along with skipped slot 4 and 6.
|
||||
func GenerateStateFromBlock(ctx context.Context, db *db.BeaconDB, slot uint64) (*pb.BeaconState, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "beacon-chain.blockchain.stategenerator.GenerateStateFromBlock")
|
||||
defer span.End()
|
||||
fState, err := db.HistoricalStateFromSlot(ctx, slot, [32]byte{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// return finalized state if it's the same as input slot.
|
||||
if fState.Slot == slot {
|
||||
return fState, nil
|
||||
}
|
||||
|
||||
// input slot can't be smaller than last finalized state's slot.
|
||||
if fState.Slot > slot {
|
||||
return nil, fmt.Errorf(
|
||||
"requested slot %d < current slot %d in the finalized beacon state",
|
||||
slot-params.BeaconConfig().GenesisSlot,
|
||||
fState.Slot-params.BeaconConfig().GenesisSlot,
|
||||
)
|
||||
}
|
||||
|
||||
if fState.LatestBlock == nil {
|
||||
return nil, fmt.Errorf("latest head in state is nil %v", err)
|
||||
}
|
||||
|
||||
fRoot, err := hashutil.HashBeaconBlock(fState.LatestBlock)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get block root %v", err)
|
||||
}
|
||||
|
||||
// from input slot, retrieve its corresponding block and call that the most recent block.
|
||||
mostRecentBlocks, err := db.BlocksBySlot(ctx, slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mostRecentBlock := mostRecentBlocks[0]
|
||||
|
||||
// if the most recent block is a skip block, we get its parent block.
|
||||
// ex:
|
||||
// 1A - 2B - 3C - 4 - 5 (letters mean there's a block).
|
||||
// input slot is 5, but slots 4 and 5 are skipped, we get block C from slot 3.
|
||||
lastSlot := slot
|
||||
for mostRecentBlock == nil {
|
||||
lastSlot--
|
||||
blocks, err := db.BlocksBySlot(ctx, lastSlot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mostRecentBlock = blocks[0]
|
||||
}
|
||||
|
||||
// retrieve the block list to recompute state of the input slot.
|
||||
blocks, err := blocksSinceFinalized(ctx, db, mostRecentBlock, fRoot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to look up block ancestors %v", err)
|
||||
}
|
||||
|
||||
log.Infof("Recompute state starting last finalized slot %d and ending slot %d",
|
||||
fState.Slot-params.BeaconConfig().GenesisSlot, slot-params.BeaconConfig().GenesisSlot)
|
||||
postState := fState
|
||||
root := fRoot
|
||||
// this recomputes state up to the last available block.
|
||||
// ex: 1A - 2B (finalized) - 3C - 4 - 5 - 6C - 7 - 8 (C is the last block).
|
||||
// input slot 8, this recomputes state to slot 6.
|
||||
for i := len(blocks); i > 0; i-- {
|
||||
block := blocks[i-1]
|
||||
if block.Slot <= postState.Slot {
|
||||
continue
|
||||
}
|
||||
// running state transitions for skipped slots.
|
||||
for block.Slot != fState.Slot+1 {
|
||||
postState, err = state.ExecuteStateTransition(
|
||||
ctx,
|
||||
postState,
|
||||
nil,
|
||||
root,
|
||||
&state.TransitionConfig{
|
||||
VerifySignatures: false,
|
||||
Logging: false,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not execute state transition %v", err)
|
||||
}
|
||||
}
|
||||
postState, err = state.ExecuteStateTransition(
|
||||
ctx,
|
||||
postState,
|
||||
block,
|
||||
root,
|
||||
&state.TransitionConfig{
|
||||
VerifySignatures: false,
|
||||
Logging: false,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not execute state transition %v", err)
|
||||
}
|
||||
|
||||
root, err = hashutil.HashBeaconBlock(block)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get block root %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// this recomputes state from last block to last slot if there's skipp slots after.
|
||||
// ex: 1A - 2B (finalized) - 3C - 4 - 5 - 6C - 7 - 8 (7 and 8 are skipped slots).
|
||||
// input slot 8, this recomputes state from 6C to 8.
|
||||
for i := postState.Slot; i < slot; i++ {
|
||||
postState, err = state.ExecuteStateTransition(
|
||||
ctx,
|
||||
postState,
|
||||
nil,
|
||||
root,
|
||||
&state.TransitionConfig{
|
||||
VerifySignatures: false,
|
||||
Logging: false,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not execute state transition %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Finished recompute state with slot %d and finalized epoch %d",
|
||||
postState.Slot-params.BeaconConfig().GenesisSlot, postState.FinalizedEpoch-params.BeaconConfig().GenesisEpoch)
|
||||
|
||||
return postState, nil
|
||||
}
|
||||
|
||||
// blocksSinceFinalized will return a list of linked blocks that's
|
||||
// between the input block and the last finalized block in the db.
|
||||
// The input block is also returned in the list.
|
||||
// Ex:
|
||||
// A -> B(finalized) -> C -> D -> E -> D.
|
||||
// Input: E, output: [E, D, C, B].
|
||||
func blocksSinceFinalized(ctx context.Context, db *db.BeaconDB, block *pb.BeaconBlock,
|
||||
finalizedBlockRoot [32]byte) ([]*pb.BeaconBlock, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "beacon-chain.blockchain.stategenerator.blocksSinceFinalized")
|
||||
defer span.End()
|
||||
blockAncestors := make([]*pb.BeaconBlock, 0)
|
||||
blockAncestors = append(blockAncestors, block)
|
||||
parentRoot := bytesutil.ToBytes32(block.ParentRootHash32)
|
||||
// looking up ancestors, until the finalized block.
|
||||
for parentRoot != finalizedBlockRoot {
|
||||
retblock, err := db.Block(parentRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockAncestors = append(blockAncestors, retblock)
|
||||
parentRoot = bytesutil.ToBytes32(retblock.ParentRootHash32)
|
||||
}
|
||||
return blockAncestors, nil
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
package stategenerator_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain/stategenerator"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/chaintest/backend"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func init() {
|
||||
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
|
||||
CacheTreeHash: false,
|
||||
})
|
||||
}
|
||||
func TestGenerateState_OK(t *testing.T) {
|
||||
b, err := backend.NewSimulatedBackend()
|
||||
if err != nil {
|
||||
t.Fatalf("Could not create a new simulated backend %v", err)
|
||||
}
|
||||
privKeys, err := b.SetupBackend(100)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not set up backend %v", err)
|
||||
}
|
||||
beaconDb := b.DB()
|
||||
defer b.Shutdown()
|
||||
defer db.TeardownDB(beaconDb)
|
||||
ctx := context.Background()
|
||||
|
||||
slotLimit := uint64(30)
|
||||
|
||||
// Run the simulated chain for 30 slots, to get a state that we can save as finalized.
|
||||
for i := uint64(0); i < slotLimit; i++ {
|
||||
if err := b.GenerateBlockAndAdvanceChain(&backend.SimulatedObjects{}, privKeys); err != nil {
|
||||
t.Fatalf("Could not generate block and transition state successfully %v for slot %d", err, b.State().Slot+1)
|
||||
}
|
||||
inMemBlocks := b.InMemoryBlocks()
|
||||
if err := beaconDb.SaveBlock(inMemBlocks[len(inMemBlocks)-1]); err != nil {
|
||||
t.Fatalf("Unable to save block %v", err)
|
||||
}
|
||||
if err := beaconDb.UpdateChainHead(ctx, inMemBlocks[len(inMemBlocks)-1], b.State()); err != nil {
|
||||
t.Fatalf("Unable to save block %v", err)
|
||||
}
|
||||
if err := beaconDb.SaveFinalizedBlock(inMemBlocks[len(inMemBlocks)-1]); err != nil {
|
||||
t.Fatalf("Unable to save finalized state: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := beaconDb.SaveFinalizedState(b.State()); err != nil {
|
||||
t.Fatalf("Unable to save finalized state: %v", err)
|
||||
}
|
||||
|
||||
// Run the chain for another 30 slots so that we can have this at the current head.
|
||||
for i := uint64(0); i < slotLimit; i++ {
|
||||
if err := b.GenerateBlockAndAdvanceChain(&backend.SimulatedObjects{}, privKeys); err != nil {
|
||||
t.Fatalf("Could not generate block and transition state successfully %v for slot %d", err, b.State().Slot+1)
|
||||
}
|
||||
inMemBlocks := b.InMemoryBlocks()
|
||||
if err := beaconDb.SaveBlock(inMemBlocks[len(inMemBlocks)-1]); err != nil {
|
||||
t.Fatalf("Unable to save block %v", err)
|
||||
}
|
||||
if err := beaconDb.UpdateChainHead(ctx, inMemBlocks[len(inMemBlocks)-1], b.State()); err != nil {
|
||||
t.Fatalf("Unable to save block %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ran 30 slots to save finalized slot then ran another 30 slots.
|
||||
slotToGenerateTill := params.BeaconConfig().GenesisSlot + slotLimit*2
|
||||
newState, err := stategenerator.GenerateStateFromBlock(context.Background(), beaconDb, slotToGenerateTill)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to generate new state from previous finalized state %v", err)
|
||||
}
|
||||
|
||||
if newState.Slot != b.State().Slot {
|
||||
t.Fatalf("The generated state and the current state do not have the same slot, expected: %d but got %d",
|
||||
b.State().Slot, newState.Slot)
|
||||
}
|
||||
|
||||
if !proto.Equal(newState, b.State()) {
|
||||
t.Error("Generated and saved states are unequal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateState_WithNilBlocksOK(t *testing.T) {
|
||||
b, err := backend.NewSimulatedBackend()
|
||||
if err != nil {
|
||||
t.Fatalf("Could not create a new simulated backend %v", err)
|
||||
}
|
||||
privKeys, err := b.SetupBackend(100)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not set up backend %v", err)
|
||||
}
|
||||
beaconDb := b.DB()
|
||||
defer b.Shutdown()
|
||||
defer db.TeardownDB(beaconDb)
|
||||
ctx := context.Background()
|
||||
|
||||
slotLimit := uint64(30)
|
||||
|
||||
// Run the simulated chain for 30 slots, to get a state that we can save as finalized.
|
||||
for i := uint64(0); i < slotLimit; i++ {
|
||||
if err := b.GenerateBlockAndAdvanceChain(&backend.SimulatedObjects{}, privKeys); err != nil {
|
||||
t.Fatalf("Could not generate block and transition state successfully %v for slot %d", err, b.State().Slot+1)
|
||||
}
|
||||
inMemBlocks := b.InMemoryBlocks()
|
||||
if err := beaconDb.SaveBlock(inMemBlocks[len(inMemBlocks)-1]); err != nil {
|
||||
t.Fatalf("Unable to save block %v", err)
|
||||
}
|
||||
if err := beaconDb.UpdateChainHead(ctx, inMemBlocks[len(inMemBlocks)-1], b.State()); err != nil {
|
||||
t.Fatalf("Unable to save block %v", err)
|
||||
}
|
||||
if err := beaconDb.SaveFinalizedBlock(inMemBlocks[len(inMemBlocks)-1]); err != nil {
|
||||
t.Fatalf("Unable to save finalized state: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := beaconDb.SaveFinalizedState(b.State()); err != nil {
|
||||
t.Fatalf("Unable to save finalized state")
|
||||
}
|
||||
|
||||
slotsWithNil := uint64(10)
|
||||
|
||||
// Run the chain for 10 slots with nil blocks.
|
||||
for i := uint64(0); i < slotsWithNil; i++ {
|
||||
if err := b.GenerateNilBlockAndAdvanceChain(); err != nil {
|
||||
t.Fatalf("Could not generate block and transition state successfully %v for slot %d", err, b.State().Slot+1)
|
||||
}
|
||||
}
|
||||
|
||||
for i := uint64(0); i < slotLimit-slotsWithNil; i++ {
|
||||
if err := b.GenerateBlockAndAdvanceChain(&backend.SimulatedObjects{}, privKeys); err != nil {
|
||||
t.Fatalf("Could not generate block and transition state successfully %v for slot %d", err, b.State().Slot+1)
|
||||
}
|
||||
inMemBlocks := b.InMemoryBlocks()
|
||||
if err := beaconDb.SaveBlock(inMemBlocks[len(inMemBlocks)-1]); err != nil {
|
||||
t.Fatalf("Unable to save block %v", err)
|
||||
}
|
||||
if err := beaconDb.UpdateChainHead(ctx, inMemBlocks[len(inMemBlocks)-1], b.State()); err != nil {
|
||||
t.Fatalf("Unable to save block %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ran 30 slots to save finalized slot then ran another 10 slots w/o blocks and 20 slots w/ blocks.
|
||||
slotToGenerateTill := params.BeaconConfig().GenesisSlot + slotLimit*2
|
||||
newState, err := stategenerator.GenerateStateFromBlock(context.Background(), beaconDb, slotToGenerateTill)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to generate new state from previous finalized state %v", err)
|
||||
}
|
||||
|
||||
if newState.Slot != b.State().Slot {
|
||||
t.Fatalf("The generated state and the current state do not have the same slot, expected: %d but got %d",
|
||||
b.State().Slot, newState.Slot)
|
||||
}
|
||||
|
||||
if !proto.Equal(newState, b.State()) {
|
||||
t.Error("generated and saved states are unequal")
|
||||
}
|
||||
}
|
||||
20
beacon-chain/cache/BUILD.bazel
vendored
20
beacon-chain/cache/BUILD.bazel
vendored
@@ -3,9 +3,17 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"active_balance.go",
|
||||
"active_count.go",
|
||||
"active_indices.go",
|
||||
"attestation_data.go",
|
||||
"block.go",
|
||||
"committee.go",
|
||||
"common.go",
|
||||
"eth1_data.go",
|
||||
"seed.go",
|
||||
"shuffled_indices.go",
|
||||
"start_shard.go",
|
||||
"total_balance.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/cache",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
@@ -23,15 +31,23 @@ go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"active_balance_test.go",
|
||||
"active_count_test.go",
|
||||
"active_indices_test.go",
|
||||
"attestation_data_test.go",
|
||||
"block_test.go",
|
||||
"committee_test.go",
|
||||
"eth1_data_test.go",
|
||||
"seed_test.go",
|
||||
"shuffled_indices_test.go",
|
||||
"start_shard_test.go",
|
||||
"total_balance_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
race = "on",
|
||||
deps = [
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//proto/beacon/rpc/v1:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
98
beacon-chain/cache/active_balance.go
vendored
Normal file
98
beacon-chain/cache/active_balance.go
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotActiveBalanceInfo will be returned when a cache object is not a pointer to
|
||||
// a ActiveBalanceByEpoch struct.
|
||||
ErrNotActiveBalanceInfo = errors.New("object is not a active balance obj")
|
||||
|
||||
// maxActiveBalanceListSize defines the max number of active balance can cache.
|
||||
maxActiveBalanceListSize = 1000
|
||||
|
||||
// Metrics.
|
||||
activeBalanceCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "active_balance_cache_miss",
|
||||
Help: "The number of active balance requests that aren't present in the cache.",
|
||||
})
|
||||
activeBalanceCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "active_balance_cache_hit",
|
||||
Help: "The number of active balance requests that are present in the cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// ActiveBalanceByEpoch defines the active validator balance per epoch.
|
||||
type ActiveBalanceByEpoch struct {
|
||||
Epoch uint64
|
||||
ActiveBalance uint64
|
||||
}
|
||||
|
||||
// ActiveBalanceCache is a struct with 1 queue for looking up active balance by epoch.
|
||||
type ActiveBalanceCache struct {
|
||||
activeBalanceCache *cache.FIFO
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// activeBalanceKeyFn takes the epoch as the key for the active balance of a given epoch.
|
||||
func activeBalanceKeyFn(obj interface{}) (string, error) {
|
||||
tInfo, ok := obj.(*ActiveBalanceByEpoch)
|
||||
if !ok {
|
||||
return "", ErrNotActiveBalanceInfo
|
||||
}
|
||||
|
||||
return strconv.Itoa(int(tInfo.Epoch)), nil
|
||||
}
|
||||
|
||||
// NewActiveBalanceCache creates a new active balance cache for storing/accessing active validator balance.
|
||||
func NewActiveBalanceCache() *ActiveBalanceCache {
|
||||
return &ActiveBalanceCache{
|
||||
activeBalanceCache: cache.NewFIFO(activeBalanceKeyFn),
|
||||
}
|
||||
}
|
||||
|
||||
// ActiveBalanceInEpoch fetches ActiveBalanceByEpoch by epoch. Returns true with a
|
||||
// reference to the ActiveBalanceInEpoch info, if exists. Otherwise returns false, nil.
|
||||
func (c *ActiveBalanceCache) ActiveBalanceInEpoch(epoch uint64) (uint64, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.activeBalanceCache.GetByKey(strconv.Itoa(int(epoch)))
|
||||
if err != nil {
|
||||
return params.BeaconConfig().FarFutureEpoch, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
activeBalanceCacheHit.Inc()
|
||||
} else {
|
||||
activeBalanceCacheMiss.Inc()
|
||||
return params.BeaconConfig().FarFutureEpoch, nil
|
||||
}
|
||||
|
||||
tInfo, ok := obj.(*ActiveBalanceByEpoch)
|
||||
if !ok {
|
||||
return params.BeaconConfig().FarFutureEpoch, ErrNotActiveBalanceInfo
|
||||
}
|
||||
|
||||
return tInfo.ActiveBalance, nil
|
||||
}
|
||||
|
||||
// AddActiveBalance adds ActiveBalanceByEpoch object to the cache. This method also trims the least
|
||||
// recently added ActiveBalanceByEpoch object if the cache size has ready the max cache size limit.
|
||||
func (c *ActiveBalanceCache) AddActiveBalance(activeBalance *ActiveBalanceByEpoch) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if err := c.activeBalanceCache.AddIfNotPresent(activeBalance); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trim(c.activeBalanceCache, maxActiveBalanceListSize)
|
||||
return nil
|
||||
}
|
||||
83
beacon-chain/cache/active_balance_test.go
vendored
Normal file
83
beacon-chain/cache/active_balance_test.go
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestActiveBalanceKeyFn_OK(t *testing.T) {
|
||||
tInfo := &ActiveBalanceByEpoch{
|
||||
Epoch: 45,
|
||||
ActiveBalance: 7456,
|
||||
}
|
||||
|
||||
key, err := activeBalanceKeyFn(tInfo)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if key != strconv.Itoa(int(tInfo.Epoch)) {
|
||||
t.Errorf("Incorrect hash key: %s, expected %s", key, strconv.Itoa(int(tInfo.Epoch)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestActiveBalanceKeyFn_InvalidObj(t *testing.T) {
|
||||
_, err := activeBalanceKeyFn("bad")
|
||||
if err != ErrNotActiveBalanceInfo {
|
||||
t.Errorf("Expected error %v, got %v", ErrNotActiveBalanceInfo, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActiveBalanceCache_ActiveBalanceByEpoch(t *testing.T) {
|
||||
cache := NewActiveBalanceCache()
|
||||
|
||||
tInfo := &ActiveBalanceByEpoch{
|
||||
Epoch: 16511,
|
||||
ActiveBalance: 4456547,
|
||||
}
|
||||
activeBalance, err := cache.ActiveBalanceInEpoch(tInfo.Epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if activeBalance != params.BeaconConfig().FarFutureEpoch {
|
||||
t.Error("Expected active balance not to exist in empty cache")
|
||||
}
|
||||
|
||||
if err := cache.AddActiveBalance(tInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
activeBalance, err = cache.ActiveBalanceInEpoch(tInfo.Epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(activeBalance, tInfo.ActiveBalance) {
|
||||
t.Errorf(
|
||||
"Expected fetched active balance to be %v, got %v",
|
||||
tInfo.ActiveBalance,
|
||||
activeBalance,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActiveBalance_MaxSize(t *testing.T) {
|
||||
cache := NewActiveBalanceCache()
|
||||
|
||||
for i := uint64(0); i < 1001; i++ {
|
||||
tInfo := &ActiveBalanceByEpoch{
|
||||
Epoch: i,
|
||||
}
|
||||
if err := cache.AddActiveBalance(tInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cache.activeBalanceCache.ListKeys()) != maxActiveBalanceListSize {
|
||||
t.Errorf(
|
||||
"Expected hash cache key size to be %d, got %d",
|
||||
maxActiveBalanceListSize,
|
||||
len(cache.activeBalanceCache.ListKeys()),
|
||||
)
|
||||
}
|
||||
}
|
||||
98
beacon-chain/cache/active_count.go
vendored
Normal file
98
beacon-chain/cache/active_count.go
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotActiveCountInfo will be returned when a cache object is not a pointer to
|
||||
// a ActiveCountByEpoch struct.
|
||||
ErrNotActiveCountInfo = errors.New("object is not a active count obj")
|
||||
|
||||
// maxActiveCountListSize defines the max number of active count can cache.
|
||||
maxActiveCountListSize = 1000
|
||||
|
||||
// Metrics.
|
||||
activeCountCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "active_validator_count_cache_miss",
|
||||
Help: "The number of active validator count requests that aren't present in the cache.",
|
||||
})
|
||||
activeCountCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "active_validator_count_cache_hit",
|
||||
Help: "The number of active validator count requests that are present in the cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// ActiveCountByEpoch defines the active validator count per epoch.
|
||||
type ActiveCountByEpoch struct {
|
||||
Epoch uint64
|
||||
ActiveCount uint64
|
||||
}
|
||||
|
||||
// ActiveCountCache is a struct with 1 queue for looking up active count by epoch.
|
||||
type ActiveCountCache struct {
|
||||
activeCountCache *cache.FIFO
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// activeCountKeyFn takes the epoch as the key for the active count of a given epoch.
|
||||
func activeCountKeyFn(obj interface{}) (string, error) {
|
||||
aInfo, ok := obj.(*ActiveCountByEpoch)
|
||||
if !ok {
|
||||
return "", ErrNotActiveCountInfo
|
||||
}
|
||||
|
||||
return strconv.Itoa(int(aInfo.Epoch)), nil
|
||||
}
|
||||
|
||||
// NewActiveCountCache creates a new active count cache for storing/accessing active validator count.
|
||||
func NewActiveCountCache() *ActiveCountCache {
|
||||
return &ActiveCountCache{
|
||||
activeCountCache: cache.NewFIFO(activeCountKeyFn),
|
||||
}
|
||||
}
|
||||
|
||||
// ActiveCountInEpoch fetches ActiveCountByEpoch by epoch. Returns true with a
|
||||
// reference to the ActiveCountInEpoch info, if exists. Otherwise returns false, nil.
|
||||
func (c *ActiveCountCache) ActiveCountInEpoch(epoch uint64) (uint64, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.activeCountCache.GetByKey(strconv.Itoa(int(epoch)))
|
||||
if err != nil {
|
||||
return params.BeaconConfig().FarFutureEpoch, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
activeCountCacheHit.Inc()
|
||||
} else {
|
||||
activeCountCacheMiss.Inc()
|
||||
return params.BeaconConfig().FarFutureEpoch, nil
|
||||
}
|
||||
|
||||
aInfo, ok := obj.(*ActiveCountByEpoch)
|
||||
if !ok {
|
||||
return params.BeaconConfig().FarFutureEpoch, ErrNotActiveCountInfo
|
||||
}
|
||||
|
||||
return aInfo.ActiveCount, nil
|
||||
}
|
||||
|
||||
// AddActiveCount adds ActiveCountByEpoch object to the cache. This method also trims the least
|
||||
// recently added ActiveCountByEpoch object if the cache size has ready the max cache size limit.
|
||||
func (c *ActiveCountCache) AddActiveCount(activeCount *ActiveCountByEpoch) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if err := c.activeCountCache.AddIfNotPresent(activeCount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trim(c.activeCountCache, maxActiveCountListSize)
|
||||
return nil
|
||||
}
|
||||
83
beacon-chain/cache/active_count_test.go
vendored
Normal file
83
beacon-chain/cache/active_count_test.go
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestActiveCountKeyFn_OK(t *testing.T) {
|
||||
aInfo := &ActiveCountByEpoch{
|
||||
Epoch: 999,
|
||||
ActiveCount: 10,
|
||||
}
|
||||
|
||||
key, err := activeCountKeyFn(aInfo)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if key != strconv.Itoa(int(aInfo.Epoch)) {
|
||||
t.Errorf("Incorrect hash key: %s, expected %s", key, strconv.Itoa(int(aInfo.Epoch)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestActiveCountKeyFn_InvalidObj(t *testing.T) {
|
||||
_, err := activeCountKeyFn("bad")
|
||||
if err != ErrNotActiveCountInfo {
|
||||
t.Errorf("Expected error %v, got %v", ErrNotActiveCountInfo, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActiveCountCache_ActiveCountByEpoch(t *testing.T) {
|
||||
cache := NewActiveCountCache()
|
||||
|
||||
aInfo := &ActiveCountByEpoch{
|
||||
Epoch: 99,
|
||||
ActiveCount: 11,
|
||||
}
|
||||
activeCount, err := cache.ActiveCountInEpoch(aInfo.Epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if activeCount != params.BeaconConfig().FarFutureEpoch {
|
||||
t.Error("Expected active count not to exist in empty cache")
|
||||
}
|
||||
|
||||
if err := cache.AddActiveCount(aInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
activeCount, err = cache.ActiveCountInEpoch(aInfo.Epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(activeCount, aInfo.ActiveCount) {
|
||||
t.Errorf(
|
||||
"Expected fetched active count to be %v, got %v",
|
||||
aInfo.ActiveCount,
|
||||
activeCount,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActiveCount_MaxSize(t *testing.T) {
|
||||
cache := NewActiveCountCache()
|
||||
|
||||
for i := uint64(0); i < 1001; i++ {
|
||||
aInfo := &ActiveCountByEpoch{
|
||||
Epoch: i,
|
||||
}
|
||||
if err := cache.AddActiveCount(aInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cache.activeCountCache.ListKeys()) != maxActiveCountListSize {
|
||||
t.Errorf(
|
||||
"Expected hash cache key size to be %d, got %d",
|
||||
maxActiveCountListSize,
|
||||
len(cache.activeCountCache.ListKeys()),
|
||||
)
|
||||
}
|
||||
}
|
||||
102
beacon-chain/cache/active_indices.go
vendored
Normal file
102
beacon-chain/cache/active_indices.go
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotActiveIndicesInfo will be returned when a cache object is not a pointer to
|
||||
// a ActiveIndicesByEpoch struct.
|
||||
ErrNotActiveIndicesInfo = errors.New("object is not a active indices list")
|
||||
|
||||
// maxActiveIndicesListSize defines the max number of active indices can cache.
|
||||
maxActiveIndicesListSize = 4
|
||||
|
||||
// Metrics.
|
||||
activeIndicesCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "active_validator_indices_cache_miss",
|
||||
Help: "The number of active validator indices requests that aren't present in the cache.",
|
||||
})
|
||||
activeIndicesCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "active_validator_indices_cache_hit",
|
||||
Help: "The number of active validator indices requests that are present in the cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// ActiveIndicesByEpoch defines the active validator indices per epoch.
|
||||
type ActiveIndicesByEpoch struct {
|
||||
Epoch uint64
|
||||
ActiveIndices []uint64
|
||||
}
|
||||
|
||||
// ActiveIndicesCache is a struct with 1 queue for looking up active indices by epoch.
|
||||
type ActiveIndicesCache struct {
|
||||
activeIndicesCache *cache.FIFO
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// activeIndicesKeyFn takes the epoch as the key for the active indices of a given epoch.
|
||||
func activeIndicesKeyFn(obj interface{}) (string, error) {
|
||||
aInfo, ok := obj.(*ActiveIndicesByEpoch)
|
||||
if !ok {
|
||||
return "", ErrNotActiveIndicesInfo
|
||||
}
|
||||
|
||||
return strconv.Itoa(int(aInfo.Epoch)), nil
|
||||
}
|
||||
|
||||
// NewActiveIndicesCache creates a new active indices cache for storing/accessing active validator indices.
|
||||
func NewActiveIndicesCache() *ActiveIndicesCache {
|
||||
return &ActiveIndicesCache{
|
||||
activeIndicesCache: cache.NewFIFO(activeIndicesKeyFn),
|
||||
}
|
||||
}
|
||||
|
||||
// ActiveIndicesInEpoch fetches ActiveIndicesByEpoch by epoch. Returns true with a
|
||||
// reference to the ActiveIndicesInEpoch info, if exists. Otherwise returns false, nil.
|
||||
func (c *ActiveIndicesCache) ActiveIndicesInEpoch(epoch uint64) ([]uint64, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.activeIndicesCache.GetByKey(strconv.Itoa(int(epoch)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
activeIndicesCacheHit.Inc()
|
||||
} else {
|
||||
activeIndicesCacheMiss.Inc()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
aInfo, ok := obj.(*ActiveIndicesByEpoch)
|
||||
if !ok {
|
||||
return nil, ErrNotActiveIndicesInfo
|
||||
}
|
||||
|
||||
return aInfo.ActiveIndices, nil
|
||||
}
|
||||
|
||||
// AddActiveIndicesList adds ActiveIndicesByEpoch object to the cache. This method also trims the least
|
||||
// recently added ActiveIndicesByEpoch object if the cache size has ready the max cache size limit.
|
||||
func (c *ActiveIndicesCache) AddActiveIndicesList(activeIndices *ActiveIndicesByEpoch) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if err := c.activeIndicesCache.AddIfNotPresent(activeIndices); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trim(c.activeIndicesCache, maxActiveIndicesListSize)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActiveIndicesKeys returns the keys of the active indices cache.
|
||||
func (c *ActiveIndicesCache) ActiveIndicesKeys() []string {
|
||||
return c.activeIndicesCache.ListKeys()
|
||||
}
|
||||
82
beacon-chain/cache/active_indices_test.go
vendored
Normal file
82
beacon-chain/cache/active_indices_test.go
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestActiveIndicesKeyFn_OK(t *testing.T) {
|
||||
aInfo := &ActiveIndicesByEpoch{
|
||||
Epoch: 999,
|
||||
ActiveIndices: []uint64{1, 2, 3, 4, 5},
|
||||
}
|
||||
|
||||
key, err := activeIndicesKeyFn(aInfo)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if key != strconv.Itoa(int(aInfo.Epoch)) {
|
||||
t.Errorf("Incorrect hash key: %s, expected %s", key, strconv.Itoa(int(aInfo.Epoch)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestActiveIndicesKeyFn_InvalidObj(t *testing.T) {
|
||||
_, err := activeIndicesKeyFn("bad")
|
||||
if err != ErrNotActiveIndicesInfo {
|
||||
t.Errorf("Expected error %v, got %v", ErrNotActiveIndicesInfo, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActiveIndicesCache_ActiveIndicesByEpoch(t *testing.T) {
|
||||
cache := NewActiveIndicesCache()
|
||||
|
||||
aInfo := &ActiveIndicesByEpoch{
|
||||
Epoch: 99,
|
||||
ActiveIndices: []uint64{1, 2, 3, 4},
|
||||
}
|
||||
|
||||
activeIndices, err := cache.ActiveIndicesInEpoch(aInfo.Epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if activeIndices != nil {
|
||||
t.Error("Expected active indices not to exist in empty cache")
|
||||
}
|
||||
|
||||
if err := cache.AddActiveIndicesList(aInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
activeIndices, err = cache.ActiveIndicesInEpoch(aInfo.Epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(activeIndices, aInfo.ActiveIndices) {
|
||||
t.Errorf(
|
||||
"Expected fetched active indices to be %v, got %v",
|
||||
aInfo.ActiveIndices,
|
||||
activeIndices,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActiveIndices_MaxSize(t *testing.T) {
|
||||
cache := NewActiveIndicesCache()
|
||||
|
||||
for i := uint64(0); i < 100; i++ {
|
||||
aInfo := &ActiveIndicesByEpoch{
|
||||
Epoch: i,
|
||||
}
|
||||
if err := cache.AddActiveIndicesList(aInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cache.activeIndicesCache.ListKeys()) != maxActiveIndicesListSize {
|
||||
t.Errorf(
|
||||
"Expected hash cache key size to be %d, got %d",
|
||||
maxActiveIndicesListSize,
|
||||
len(cache.activeIndicesCache.ListKeys()),
|
||||
)
|
||||
}
|
||||
}
|
||||
15
beacon-chain/cache/attestation_data.go
vendored
15
beacon-chain/cache/attestation_data.go
vendored
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
@@ -57,7 +58,7 @@ func NewAttestationCache() *AttestationCache {
|
||||
|
||||
// Get waits for any in progress calculation to complete before returning a
|
||||
// cached response, if any.
|
||||
func (c *AttestationCache) Get(ctx context.Context, req *pb.AttestationDataRequest) (*pb.AttestationDataResponse, error) {
|
||||
func (c *AttestationCache) Get(ctx context.Context, req *pb.AttestationRequest) (*pbp2p.AttestationData, error) {
|
||||
if req == nil {
|
||||
return nil, errors.New("nil attestation data request")
|
||||
}
|
||||
@@ -105,7 +106,7 @@ func (c *AttestationCache) Get(ctx context.Context, req *pb.AttestationDataReque
|
||||
|
||||
// MarkInProgress a request so that any other similar requests will block on
|
||||
// Get until MarkNotInProgress is called.
|
||||
func (c *AttestationCache) MarkInProgress(req *pb.AttestationDataRequest) error {
|
||||
func (c *AttestationCache) MarkInProgress(req *pb.AttestationRequest) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
s, e := reqToKey(req)
|
||||
@@ -121,7 +122,7 @@ func (c *AttestationCache) MarkInProgress(req *pb.AttestationDataRequest) error
|
||||
|
||||
// MarkNotInProgress will release the lock on a given request. This should be
|
||||
// called after put.
|
||||
func (c *AttestationCache) MarkNotInProgress(req *pb.AttestationDataRequest) error {
|
||||
func (c *AttestationCache) MarkNotInProgress(req *pb.AttestationRequest) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
s, e := reqToKey(req)
|
||||
@@ -133,7 +134,7 @@ func (c *AttestationCache) MarkNotInProgress(req *pb.AttestationDataRequest) err
|
||||
}
|
||||
|
||||
// Put the response in the cache.
|
||||
func (c *AttestationCache) Put(ctx context.Context, req *pb.AttestationDataRequest, res *pb.AttestationDataResponse) error {
|
||||
func (c *AttestationCache) Put(ctx context.Context, req *pb.AttestationRequest, res *pbp2p.AttestationData) error {
|
||||
data := &attestationReqResWrapper{
|
||||
req,
|
||||
res,
|
||||
@@ -158,11 +159,11 @@ func wrapperToKey(i interface{}) (string, error) {
|
||||
return reqToKey(w.req)
|
||||
}
|
||||
|
||||
func reqToKey(req *pb.AttestationDataRequest) (string, error) {
|
||||
func reqToKey(req *pb.AttestationRequest) (string, error) {
|
||||
return fmt.Sprintf("%d-%d", req.Shard, req.Slot), nil
|
||||
}
|
||||
|
||||
type attestationReqResWrapper struct {
|
||||
req *pb.AttestationDataRequest
|
||||
res *pb.AttestationDataResponse
|
||||
req *pb.AttestationRequest
|
||||
res *pbp2p.AttestationData
|
||||
}
|
||||
|
||||
7
beacon-chain/cache/attestation_data_test.go
vendored
7
beacon-chain/cache/attestation_data_test.go
vendored
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1"
|
||||
)
|
||||
|
||||
@@ -13,7 +14,7 @@ func TestAttestationCache_RoundTrip(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
c := cache.NewAttestationCache()
|
||||
|
||||
req := &pb.AttestationDataRequest{
|
||||
req := &pb.AttestationRequest{
|
||||
Shard: 0,
|
||||
Slot: 1,
|
||||
}
|
||||
@@ -31,8 +32,8 @@ func TestAttestationCache_RoundTrip(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
res := &pb.AttestationDataResponse{
|
||||
HeadSlot: 5,
|
||||
res := &pbp2p.AttestationData{
|
||||
Target: &pbp2p.Checkpoint{Epoch: 5},
|
||||
}
|
||||
|
||||
if err = c.Put(ctx, req, res); err != nil {
|
||||
|
||||
2
beacon-chain/cache/block.go
vendored
2
beacon-chain/cache/block.go
vendored
@@ -82,7 +82,7 @@ func (a *AncestorBlockCache) AncestorBySlot(blockHash []byte, height uint64) (*A
|
||||
|
||||
aInfo, ok := obj.(*AncestorInfo)
|
||||
if !ok {
|
||||
return nil, ErrNotACommitteeInfo
|
||||
return nil, ErrNotAncestorCacheObj
|
||||
}
|
||||
|
||||
return aInfo, nil
|
||||
|
||||
127
beacon-chain/cache/committee.go
vendored
127
beacon-chain/cache/committee.go
vendored
@@ -1,127 +0,0 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotACommitteeInfo will be returned when a cache object is not a pointer to
|
||||
// a committeeInfo struct.
|
||||
ErrNotACommitteeInfo = errors.New("object is not an committee info")
|
||||
|
||||
// maxCacheSize is 4x of the epoch length for additional cache padding.
|
||||
// Requests should be only accessing committees within defined epoch length.
|
||||
maxCacheSize = int(4 * params.BeaconConfig().SlotsPerEpoch)
|
||||
|
||||
// Metrics
|
||||
committeeCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "committee_cache_miss",
|
||||
Help: "The number of committee requests that aren't present in the cache.",
|
||||
})
|
||||
committeeCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "committee_cache_hit",
|
||||
Help: "The number of committee requests that are present in the cache.",
|
||||
})
|
||||
committeeCacheSize = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "committee_cache_size",
|
||||
Help: "The number of committees in the committee cache",
|
||||
})
|
||||
)
|
||||
|
||||
// CommitteeInfo defines the validator committee of slot and shard combinations.
|
||||
type CommitteeInfo struct {
|
||||
Committee []uint64
|
||||
Shard uint64
|
||||
}
|
||||
|
||||
// CommitteesInSlot specifies how many CommitteeInfos are in a given slot.
|
||||
type CommitteesInSlot struct {
|
||||
Slot uint64
|
||||
Committees []*CommitteeInfo
|
||||
}
|
||||
|
||||
// CommitteesCache structs with 1 queue for looking up committees by slot.
|
||||
type CommitteesCache struct {
|
||||
committeesCache *cache.FIFO
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// slotKeyFn takes the string representation of the slot number as the key
|
||||
// for the committees of a given slot (CommitteesInSlot).
|
||||
func slotKeyFn(obj interface{}) (string, error) {
|
||||
cInfo, ok := obj.(*CommitteesInSlot)
|
||||
if !ok {
|
||||
return "", ErrNotACommitteeInfo
|
||||
}
|
||||
|
||||
return strconv.Itoa(int(cInfo.Slot)), nil
|
||||
}
|
||||
|
||||
// NewCommitteesCache creates a new committee cache for storing/accessing blockInfo from
|
||||
// memory.
|
||||
func NewCommitteesCache() *CommitteesCache {
|
||||
return &CommitteesCache{
|
||||
committeesCache: cache.NewFIFO(slotKeyFn),
|
||||
}
|
||||
}
|
||||
|
||||
// CommitteesInfoBySlot fetches CommitteesInSlot by slot. Returns true with a
|
||||
// reference to the committees info, if exists. Otherwise returns false, nil.
|
||||
func (c *CommitteesCache) CommitteesInfoBySlot(slot uint64) (*CommitteesInSlot, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
|
||||
obj, exists, err := c.committeesCache.GetByKey(strconv.Itoa(int(slot)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
committeeCacheHit.Inc()
|
||||
} else {
|
||||
committeeCacheMiss.Inc()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
cInfo, ok := obj.(*CommitteesInSlot)
|
||||
if !ok {
|
||||
return nil, ErrNotACommitteeInfo
|
||||
}
|
||||
|
||||
return cInfo, nil
|
||||
}
|
||||
|
||||
// AddCommittees adds CommitteesInSlot object to the cache. This method also trims the least
|
||||
// recently added committeeInfo object if the cache size has ready the max cache size limit.
|
||||
func (c *CommitteesCache) AddCommittees(committees *CommitteesInSlot) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
if err := c.committeesCache.AddIfNotPresent(committees); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trim(c.committeesCache, maxCacheSize)
|
||||
committeeCacheSize.Set(float64(len(c.committeesCache.ListKeys())))
|
||||
return nil
|
||||
}
|
||||
|
||||
// trim the FIFO queue to the maxSize.
|
||||
func trim(queue *cache.FIFO, maxSize int) {
|
||||
for s := len(queue.ListKeys()); s > maxSize; s-- {
|
||||
// #nosec G104 popProcessNoopFunc never returns an error
|
||||
_, _ = queue.Pop(popProcessNoopFunc)
|
||||
}
|
||||
}
|
||||
|
||||
// popProcessNoopFunc is a no-op function that never returns an error.
|
||||
func popProcessNoopFunc(obj interface{}) error {
|
||||
return nil
|
||||
}
|
||||
96
beacon-chain/cache/committee_test.go
vendored
96
beacon-chain/cache/committee_test.go
vendored
@@ -1,96 +0,0 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSlotKeyFn_OK(t *testing.T) {
|
||||
cInfo := &CommitteesInSlot{
|
||||
Slot: 999,
|
||||
Committees: []*CommitteeInfo{
|
||||
{Shard: 1, Committee: []uint64{1, 2, 3}},
|
||||
{Shard: 1, Committee: []uint64{4, 5, 6}},
|
||||
},
|
||||
}
|
||||
|
||||
key, err := slotKeyFn(cInfo)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
strSlot := strconv.Itoa(int(cInfo.Slot))
|
||||
if key != strSlot {
|
||||
t.Errorf("Incorrect hash key: %s, expected %s", key, strSlot)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSlotKeyFn_InvalidObj(t *testing.T) {
|
||||
_, err := slotKeyFn("bad")
|
||||
if err != ErrNotACommitteeInfo {
|
||||
t.Errorf("Expected error %v, got %v", ErrNotACommitteeInfo, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommitteesCache_CommitteesInfoBySlot(t *testing.T) {
|
||||
cache := NewCommitteesCache()
|
||||
|
||||
cInfo := &CommitteesInSlot{
|
||||
Slot: 123,
|
||||
Committees: []*CommitteeInfo{{Shard: 456}},
|
||||
}
|
||||
|
||||
fetchedInfo, err := cache.CommitteesInfoBySlot(cInfo.Slot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if fetchedInfo != nil {
|
||||
t.Error("Expected committees info not to exist in empty cache")
|
||||
}
|
||||
|
||||
if err := cache.AddCommittees(cInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fetchedInfo, err = cache.CommitteesInfoBySlot(cInfo.Slot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if fetchedInfo == nil {
|
||||
t.Error("Expected committee info to exist")
|
||||
}
|
||||
if fetchedInfo.Slot != cInfo.Slot {
|
||||
t.Errorf(
|
||||
"Expected fetched slot number to be %d, got %d",
|
||||
cInfo.Slot,
|
||||
fetchedInfo.Slot,
|
||||
)
|
||||
}
|
||||
if !reflect.DeepEqual(fetchedInfo.Committees, cInfo.Committees) {
|
||||
t.Errorf(
|
||||
"Expected fetched info committee to be %v, got %v",
|
||||
cInfo.Committees,
|
||||
fetchedInfo.Committees,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockCache_maxSize(t *testing.T) {
|
||||
cache := NewCommitteesCache()
|
||||
|
||||
for i := 0; i < maxCacheSize+10; i++ {
|
||||
cInfo := &CommitteesInSlot{
|
||||
Slot: uint64(i),
|
||||
}
|
||||
if err := cache.AddCommittees(cInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cache.committeesCache.ListKeys()) != maxCacheSize {
|
||||
t.Errorf(
|
||||
"Expected hash cache key size to be %d, got %d",
|
||||
maxCacheSize,
|
||||
len(cache.committeesCache.ListKeys()),
|
||||
)
|
||||
}
|
||||
}
|
||||
25
beacon-chain/cache/common.go
vendored
Normal file
25
beacon-chain/cache/common.go
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
// maxCacheSize is 4x of the epoch length for additional cache padding.
|
||||
// Requests should be only accessing committees within defined epoch length.
|
||||
maxCacheSize = int(4 * params.BeaconConfig().SlotsPerEpoch)
|
||||
)
|
||||
|
||||
// trim the FIFO queue to the maxSize.
|
||||
func trim(queue *cache.FIFO, maxSize int) {
|
||||
for s := len(queue.ListKeys()); s > maxSize; s-- {
|
||||
// #nosec G104 popProcessNoopFunc never returns an error
|
||||
_, _ = queue.Pop(popProcessNoopFunc)
|
||||
}
|
||||
}
|
||||
|
||||
// popProcessNoopFunc is a no-op function that never returns an error.
|
||||
func popProcessNoopFunc(obj interface{}) error {
|
||||
return nil
|
||||
}
|
||||
121
beacon-chain/cache/eth1_data.go
vendored
Normal file
121
beacon-chain/cache/eth1_data.go
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotEth1DataVote will be returned when a cache object is not a pointer to
|
||||
// a Eth1DataVote struct.
|
||||
ErrNotEth1DataVote = errors.New("object is not a eth1 data vote obj")
|
||||
|
||||
// maxEth1DataVoteSize defines the max number of eth1 data votes can cache.
|
||||
maxEth1DataVoteSize = 1000
|
||||
|
||||
// Metrics.
|
||||
eth1DataVoteCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "eth1_data_vote_cache_miss",
|
||||
Help: "The number of eth1 data vote count requests that aren't present in the cache.",
|
||||
})
|
||||
eth1DataVoteCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "eth1_data_vote_cache_hit",
|
||||
Help: "The number of eth1 data vote count requests that are present in the cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// Eth1DataVote defines the struct which keeps track of the vote count of individual deposit root.
|
||||
type Eth1DataVote struct {
|
||||
DepositRoot []byte
|
||||
VoteCount uint64
|
||||
}
|
||||
|
||||
// Eth1DataVoteCache is a struct with 1 queue for looking up eth1 data vote count by deposit root.
|
||||
type Eth1DataVoteCache struct {
|
||||
eth1DataVoteCache *cache.FIFO
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// eth1DataVoteKeyFn takes the deposit root as the key for the eth1 data vote count of a given root.
|
||||
func eth1DataVoteKeyFn(obj interface{}) (string, error) {
|
||||
eInfo, ok := obj.(*Eth1DataVote)
|
||||
if !ok {
|
||||
return "", ErrNotEth1DataVote
|
||||
}
|
||||
|
||||
return string(eInfo.DepositRoot), nil
|
||||
}
|
||||
|
||||
// NewEth1DataVoteCache creates a new eth1 data vote count cache for storing/accessing Eth1DataVote.
|
||||
func NewEth1DataVoteCache() *Eth1DataVoteCache {
|
||||
return &Eth1DataVoteCache{
|
||||
eth1DataVoteCache: cache.NewFIFO(eth1DataVoteKeyFn),
|
||||
}
|
||||
}
|
||||
|
||||
// Eth1DataVote fetches eth1 data vote count by deposit root. Returns vote count,
|
||||
// if exists. Otherwise returns false, nil.
|
||||
func (c *Eth1DataVoteCache) Eth1DataVote(depositRoot []byte) (uint64, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.eth1DataVoteCache.GetByKey(string(depositRoot))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
eth1DataVoteCacheHit.Inc()
|
||||
} else {
|
||||
eth1DataVoteCacheMiss.Inc()
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
eInfo, ok := obj.(*Eth1DataVote)
|
||||
if !ok {
|
||||
return 0, ErrNotEth1DataVote
|
||||
}
|
||||
|
||||
return eInfo.VoteCount, nil
|
||||
}
|
||||
|
||||
// AddEth1DataVote adds eth1 data vote object to the cache. This method also trims the least
|
||||
// recently added Eth1DataVoteByEpoch object if the cache size has ready the max cache size limit.
|
||||
func (c *Eth1DataVoteCache) AddEth1DataVote(eth1DataVote *Eth1DataVote) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if err := c.eth1DataVoteCache.Add(eth1DataVote); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trim(c.eth1DataVoteCache, maxEth1DataVoteSize)
|
||||
return nil
|
||||
}
|
||||
|
||||
// IncrementEth1DataVote increments the existing eth1 data object's vote count by 1,
|
||||
// and returns the vote count.
|
||||
func (c *Eth1DataVoteCache) IncrementEth1DataVote(depositRoot []byte) (uint64, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.eth1DataVoteCache.GetByKey(string(depositRoot))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !exists {
|
||||
return 0, errors.New("eth1 data vote object does not exist")
|
||||
}
|
||||
|
||||
eth1DataVoteCacheHit.Inc()
|
||||
|
||||
eInfo, _ := obj.(*Eth1DataVote)
|
||||
eInfo.VoteCount++
|
||||
|
||||
if err := c.eth1DataVoteCache.Add(eInfo); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return eInfo.VoteCount, nil
|
||||
}
|
||||
108
beacon-chain/cache/eth1_data_test.go
vendored
Normal file
108
beacon-chain/cache/eth1_data_test.go
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEth1DataVoteKeyFn_OK(t *testing.T) {
|
||||
eInfo := &Eth1DataVote{
|
||||
VoteCount: 44,
|
||||
DepositRoot: []byte{'A'},
|
||||
}
|
||||
|
||||
key, err := eth1DataVoteKeyFn(eInfo)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if key != string(eInfo.DepositRoot) {
|
||||
t.Errorf("Incorrect hash key: %s, expected %s", key, string(eInfo.DepositRoot))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEth1DataVoteKeyFn_InvalidObj(t *testing.T) {
|
||||
_, err := eth1DataVoteKeyFn("bad")
|
||||
if err != ErrNotEth1DataVote {
|
||||
t.Errorf("Expected error %v, got %v", ErrNotEth1DataVote, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEth1DataVoteCache_CanAdd(t *testing.T) {
|
||||
cache := NewEth1DataVoteCache()
|
||||
|
||||
eInfo := &Eth1DataVote{
|
||||
VoteCount: 55,
|
||||
DepositRoot: []byte{'B'},
|
||||
}
|
||||
count, err := cache.Eth1DataVote(eInfo.DepositRoot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if count != 0 {
|
||||
t.Error("Expected seed not to exist in empty cache")
|
||||
}
|
||||
|
||||
if err := cache.AddEth1DataVote(eInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
count, err = cache.Eth1DataVote(eInfo.DepositRoot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if count != eInfo.VoteCount {
|
||||
t.Errorf(
|
||||
"Expected vote count to be %d, got %d",
|
||||
eInfo.VoteCount,
|
||||
count,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEth1DataVoteCache_CanIncrement(t *testing.T) {
|
||||
cache := NewEth1DataVoteCache()
|
||||
|
||||
eInfo := &Eth1DataVote{
|
||||
VoteCount: 55,
|
||||
DepositRoot: []byte{'B'},
|
||||
}
|
||||
|
||||
if err := cache.AddEth1DataVote(eInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err := cache.IncrementEth1DataVote(eInfo.DepositRoot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, _ = cache.IncrementEth1DataVote(eInfo.DepositRoot)
|
||||
count, _ := cache.IncrementEth1DataVote(eInfo.DepositRoot)
|
||||
|
||||
if count != 58 {
|
||||
t.Errorf(
|
||||
"Expected vote count to be %d, got %d",
|
||||
58,
|
||||
count,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEth1Data_MaxSize(t *testing.T) {
|
||||
cache := NewEth1DataVoteCache()
|
||||
|
||||
for i := 0; i < maxEth1DataVoteSize+1; i++ {
|
||||
eInfo := &Eth1DataVote{
|
||||
DepositRoot: []byte(strconv.Itoa(i)),
|
||||
}
|
||||
if err := cache.AddEth1DataVote(eInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cache.eth1DataVoteCache.ListKeys()) != maxEth1DataVoteSize {
|
||||
t.Errorf(
|
||||
"Expected hash cache key size to be %d, got %d",
|
||||
maxEth1DataVoteSize,
|
||||
len(cache.eth1DataVoteCache.ListKeys()),
|
||||
)
|
||||
}
|
||||
}
|
||||
97
beacon-chain/cache/seed.go
vendored
Normal file
97
beacon-chain/cache/seed.go
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotSeedInfo will be returned when a cache object is not a pointer to
|
||||
// a SeedByEpoch struct.
|
||||
ErrNotSeedInfo = errors.New("object is not a seed obj")
|
||||
|
||||
// maxSeedListSize defines the max number of seed can cache.
|
||||
maxSeedListSize = 1000
|
||||
|
||||
// Metrics.
|
||||
seedCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "seed_cache_miss",
|
||||
Help: "The number of seed requests that aren't present in the cache.",
|
||||
})
|
||||
seedCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "seed_cache_hit",
|
||||
Help: "The number of seed requests that are present in the cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// SeedByEpoch defines the seed of the epoch.
|
||||
type SeedByEpoch struct {
|
||||
Epoch uint64
|
||||
Seed []byte
|
||||
}
|
||||
|
||||
// SeedCache is a struct with 1 queue for looking up seed by epoch.
|
||||
type SeedCache struct {
|
||||
seedCache *cache.FIFO
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// seedKeyFn takes the epoch as the key for the seed of a given epoch.
|
||||
func seedKeyFn(obj interface{}) (string, error) {
|
||||
sInfo, ok := obj.(*SeedByEpoch)
|
||||
if !ok {
|
||||
return "", ErrNotSeedInfo
|
||||
}
|
||||
|
||||
return strconv.Itoa(int(sInfo.Epoch)), nil
|
||||
}
|
||||
|
||||
// NewSeedCache creates a new seed cache for storing/accessing seed.
|
||||
func NewSeedCache() *SeedCache {
|
||||
return &SeedCache{
|
||||
seedCache: cache.NewFIFO(seedKeyFn),
|
||||
}
|
||||
}
|
||||
|
||||
// SeedInEpoch fetches SeedByEpoch by epoch. Returns true with a
|
||||
// reference to the SeedInEpoch info, if exists. Otherwise returns false, nil.
|
||||
func (c *SeedCache) SeedInEpoch(epoch uint64) ([]byte, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.seedCache.GetByKey(strconv.Itoa(int(epoch)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
seedCacheHit.Inc()
|
||||
} else {
|
||||
seedCacheMiss.Inc()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sInfo, ok := obj.(*SeedByEpoch)
|
||||
if !ok {
|
||||
return nil, ErrNotSeedInfo
|
||||
}
|
||||
|
||||
return sInfo.Seed, nil
|
||||
}
|
||||
|
||||
// AddSeed adds SeedByEpoch object to the cache. This method also trims the least
|
||||
// recently added SeedByEpoch object if the cache size has ready the max cache size limit.
|
||||
func (c *SeedCache) AddSeed(seed *SeedByEpoch) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if err := c.seedCache.AddIfNotPresent(seed); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trim(c.seedCache, maxSeedListSize)
|
||||
return nil
|
||||
}
|
||||
83
beacon-chain/cache/seed_test.go
vendored
Normal file
83
beacon-chain/cache/seed_test.go
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestSeedKeyFn_OK(t *testing.T) {
|
||||
tInfo := &SeedByEpoch{
|
||||
Epoch: 44,
|
||||
Seed: []byte{'A'},
|
||||
}
|
||||
|
||||
key, err := seedKeyFn(tInfo)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if key != strconv.Itoa(int(tInfo.Epoch)) {
|
||||
t.Errorf("Incorrect hash key: %s, expected %s", key, strconv.Itoa(int(tInfo.Epoch)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSeedKeyFn_InvalidObj(t *testing.T) {
|
||||
_, err := seedKeyFn("bad")
|
||||
if err != ErrNotSeedInfo {
|
||||
t.Errorf("Expected error %v, got %v", ErrNotSeedInfo, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSeedCache_SeedByEpoch(t *testing.T) {
|
||||
cache := NewSeedCache()
|
||||
|
||||
tInfo := &SeedByEpoch{
|
||||
Epoch: 55,
|
||||
Seed: []byte{'B'},
|
||||
}
|
||||
seed, err := cache.SeedInEpoch(tInfo.Epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if seed != nil {
|
||||
t.Error("Expected seed not to exist in empty cache")
|
||||
}
|
||||
|
||||
if err := cache.AddSeed(tInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
seed, err = cache.SeedInEpoch(tInfo.Epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(seed, tInfo.Seed) {
|
||||
t.Errorf(
|
||||
"Expected fetched seed to be %v, got %v",
|
||||
tInfo.Seed,
|
||||
seed,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSeed_MaxSize(t *testing.T) {
|
||||
cache := NewSeedCache()
|
||||
|
||||
for i := uint64(0); i < params.BeaconConfig().EpochsPerHistoricalVector+100; i++ {
|
||||
tInfo := &SeedByEpoch{
|
||||
Epoch: i,
|
||||
}
|
||||
if err := cache.AddSeed(tInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cache.seedCache.ListKeys()) != maxSeedListSize {
|
||||
t.Errorf(
|
||||
"Expected hash cache key size to be %d, got %d",
|
||||
maxSeedListSize,
|
||||
len(cache.seedCache.ListKeys()),
|
||||
)
|
||||
}
|
||||
}
|
||||
99
beacon-chain/cache/shuffled_indices.go
vendored
Normal file
99
beacon-chain/cache/shuffled_indices.go
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotValidatorListInfo will be returned when a cache object is not a pointer to
|
||||
// a ValidatorList struct.
|
||||
ErrNotValidatorListInfo = errors.New("object is not a shuffled validator list")
|
||||
|
||||
// maxShuffledListSize defines the max number of shuffled list can cache.
|
||||
maxShuffledListSize = 1000
|
||||
|
||||
// Metrics.
|
||||
shuffledIndicesCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "shuffled_validators_cache_miss",
|
||||
Help: "The number of shuffled validators requests that aren't present in the cache.",
|
||||
})
|
||||
shuffledIndicesCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "shuffled_validators_cache_hit",
|
||||
Help: "The number of shuffled validators requests that are present in the cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// IndicesByIndexSeed defines the shuffled validator indices per randao seed.
|
||||
type IndicesByIndexSeed struct {
|
||||
Index uint64
|
||||
Seed []byte
|
||||
ShuffledIndices []uint64
|
||||
}
|
||||
|
||||
// ShuffledIndicesCache is a struct with 1 queue for looking up shuffled validators by seed.
|
||||
type ShuffledIndicesCache struct {
|
||||
shuffledIndicesCache *cache.FIFO
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// slotKeyFn takes the randao seed as the key for the shuffled validators of a given epoch.
|
||||
func shuffleKeyFn(obj interface{}) (string, error) {
|
||||
sInfo, ok := obj.(*IndicesByIndexSeed)
|
||||
if !ok {
|
||||
return "", ErrNotValidatorListInfo
|
||||
}
|
||||
|
||||
return string(sInfo.Seed) + strconv.Itoa(int(sInfo.Index)), nil
|
||||
}
|
||||
|
||||
// NewShuffledIndicesCache creates a new shuffled validators cache for storing/accessing shuffled validator indices
|
||||
func NewShuffledIndicesCache() *ShuffledIndicesCache {
|
||||
return &ShuffledIndicesCache{
|
||||
shuffledIndicesCache: cache.NewFIFO(shuffleKeyFn),
|
||||
}
|
||||
}
|
||||
|
||||
// IndicesByIndexSeed fetches IndicesByIndexSeed by epoch and seed. Returns true with a
|
||||
// reference to the ShuffledIndicesInEpoch info, if exists. Otherwise returns false, nil.
|
||||
func (c *ShuffledIndicesCache) IndicesByIndexSeed(index uint64, seed []byte) ([]uint64, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
key := string(seed) + strconv.Itoa(int(index))
|
||||
obj, exists, err := c.shuffledIndicesCache.GetByKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
shuffledIndicesCacheHit.Inc()
|
||||
} else {
|
||||
shuffledIndicesCacheMiss.Inc()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
cInfo, ok := obj.(*IndicesByIndexSeed)
|
||||
if !ok {
|
||||
return nil, ErrNotValidatorListInfo
|
||||
}
|
||||
|
||||
return cInfo.ShuffledIndices, nil
|
||||
}
|
||||
|
||||
// AddShuffledValidatorList adds IndicesByIndexSeed object to the cache. This method also trims the least
|
||||
// recently added IndicesByIndexSeed object if the cache size has ready the max cache size limit.
|
||||
func (c *ShuffledIndicesCache) AddShuffledValidatorList(shuffledIndices *IndicesByIndexSeed) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if err := c.shuffledIndicesCache.AddIfNotPresent(shuffledIndices); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trim(c.shuffledIndicesCache, maxShuffledListSize)
|
||||
return nil
|
||||
}
|
||||
85
beacon-chain/cache/shuffled_indices_test.go
vendored
Normal file
85
beacon-chain/cache/shuffled_indices_test.go
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestShuffleKeyFn_OK(t *testing.T) {
|
||||
sInfo := &IndicesByIndexSeed{
|
||||
Index: 999,
|
||||
Seed: []byte{'A'},
|
||||
ShuffledIndices: []uint64{1, 2, 3, 4, 5},
|
||||
}
|
||||
|
||||
key, err := shuffleKeyFn(sInfo)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if key != string(sInfo.Seed)+strconv.Itoa(int(sInfo.Index)) {
|
||||
t.Errorf("Incorrect hash key: %s, expected %s", key, string(sInfo.Seed)+strconv.Itoa(int(sInfo.Index)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestShuffleKeyFn_InvalidObj(t *testing.T) {
|
||||
_, err := shuffleKeyFn("bad")
|
||||
if err != ErrNotValidatorListInfo {
|
||||
t.Errorf("Expected error %v, got %v", ErrNotValidatorListInfo, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShuffledIndicesCache_ShuffledIndicesBySeed2(t *testing.T) {
|
||||
cache := NewShuffledIndicesCache()
|
||||
|
||||
sInfo := &IndicesByIndexSeed{
|
||||
Index: 99,
|
||||
Seed: []byte{'A'},
|
||||
ShuffledIndices: []uint64{1, 2, 3, 4},
|
||||
}
|
||||
|
||||
shuffledIndices, err := cache.IndicesByIndexSeed(sInfo.Index, sInfo.Seed)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if shuffledIndices != nil {
|
||||
t.Error("Expected shuffled indices not to exist in empty cache")
|
||||
}
|
||||
|
||||
if err := cache.AddShuffledValidatorList(sInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shuffledIndices, err = cache.IndicesByIndexSeed(sInfo.Index, sInfo.Seed)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(shuffledIndices, sInfo.ShuffledIndices) {
|
||||
t.Errorf(
|
||||
"Expected fetched info committee to be %v, got %v",
|
||||
sInfo.ShuffledIndices,
|
||||
shuffledIndices,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShuffledIndices_MaxSize(t *testing.T) {
|
||||
cache := NewShuffledIndicesCache()
|
||||
|
||||
for i := uint64(0); i < 1001; i++ {
|
||||
sInfo := &IndicesByIndexSeed{
|
||||
Index: i,
|
||||
Seed: []byte{byte(i)},
|
||||
}
|
||||
if err := cache.AddShuffledValidatorList(sInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cache.shuffledIndicesCache.ListKeys()) != maxShuffledListSize {
|
||||
t.Errorf(
|
||||
"Expected hash cache key size to be %d, got %d",
|
||||
maxShuffledListSize,
|
||||
len(cache.shuffledIndicesCache.ListKeys()),
|
||||
)
|
||||
}
|
||||
}
|
||||
98
beacon-chain/cache/start_shard.go
vendored
Normal file
98
beacon-chain/cache/start_shard.go
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotStartShardInfo will be returned when a cache object is not a pointer to
|
||||
// a StartShardByEpoch struct.
|
||||
ErrNotStartShardInfo = errors.New("object is not a start shard obj")
|
||||
|
||||
// maxStartShardListSize defines the max number of start shard can cache.
|
||||
maxStartShardListSize = int(params.BeaconConfig().ShardCount)
|
||||
|
||||
// Metrics.
|
||||
startShardCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "start_shard_cache_miss",
|
||||
Help: "The number of start shard requests that aren't present in the cache.",
|
||||
})
|
||||
startShardCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "start_shard_cache_hit",
|
||||
Help: "The number of start shard requests that are present in the cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// StartShardByEpoch defines the start shard of the epoch.
|
||||
type StartShardByEpoch struct {
|
||||
Epoch uint64
|
||||
StartShard uint64
|
||||
}
|
||||
|
||||
// StartShardCache is a struct with 1 queue for looking up start shard by epoch.
|
||||
type StartShardCache struct {
|
||||
startShardCache *cache.FIFO
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// startShardKeyFn takes the epoch as the key for the start shard of a given epoch.
|
||||
func startShardKeyFn(obj interface{}) (string, error) {
|
||||
sInfo, ok := obj.(*StartShardByEpoch)
|
||||
if !ok {
|
||||
return "", ErrNotStartShardInfo
|
||||
}
|
||||
|
||||
return strconv.Itoa(int(sInfo.Epoch)), nil
|
||||
}
|
||||
|
||||
// NewStartShardCache creates a new start shard cache for storing/accessing start shard.
|
||||
func NewStartShardCache() *StartShardCache {
|
||||
return &StartShardCache{
|
||||
startShardCache: cache.NewFIFO(startShardKeyFn),
|
||||
}
|
||||
}
|
||||
|
||||
// StartShardInEpoch fetches StartShardByEpoch by epoch. Returns true with a
|
||||
// reference to the StartShardInEpoch info, if exists. Otherwise returns false, nil.
|
||||
func (c *StartShardCache) StartShardInEpoch(epoch uint64) (uint64, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.startShardCache.GetByKey(strconv.Itoa(int(epoch)))
|
||||
if err != nil {
|
||||
return params.BeaconConfig().FarFutureEpoch, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
startShardCacheHit.Inc()
|
||||
} else {
|
||||
startShardCacheMiss.Inc()
|
||||
return params.BeaconConfig().FarFutureEpoch, nil
|
||||
}
|
||||
|
||||
sInfo, ok := obj.(*StartShardByEpoch)
|
||||
if !ok {
|
||||
return params.BeaconConfig().FarFutureEpoch, ErrNotStartShardInfo
|
||||
}
|
||||
|
||||
return sInfo.StartShard, nil
|
||||
}
|
||||
|
||||
// AddStartShard adds StartShardByEpoch object to the cache. This method also trims the least
|
||||
// recently added StartShardByEpoch object if the cache size has ready the max cache size limit.
|
||||
func (c *StartShardCache) AddStartShard(startShard *StartShardByEpoch) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if err := c.startShardCache.AddIfNotPresent(startShard); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trim(c.startShardCache, maxStartShardListSize)
|
||||
return nil
|
||||
}
|
||||
83
beacon-chain/cache/start_shard_test.go
vendored
Normal file
83
beacon-chain/cache/start_shard_test.go
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestStartShardKeyFn_OK(t *testing.T) {
|
||||
tInfo := &StartShardByEpoch{
|
||||
Epoch: 44,
|
||||
StartShard: 3,
|
||||
}
|
||||
|
||||
key, err := startShardKeyFn(tInfo)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if key != strconv.Itoa(int(tInfo.Epoch)) {
|
||||
t.Errorf("Incorrect hash key: %s, expected %s", key, strconv.Itoa(int(tInfo.Epoch)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartShardKeyFn_InvalidObj(t *testing.T) {
|
||||
_, err := startShardKeyFn("bad")
|
||||
if err != ErrNotStartShardInfo {
|
||||
t.Errorf("Expected error %v, got %v", ErrNotStartShardInfo, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartShardCache_StartShardByEpoch(t *testing.T) {
|
||||
cache := NewStartShardCache()
|
||||
|
||||
tInfo := &StartShardByEpoch{
|
||||
Epoch: 55,
|
||||
StartShard: 3,
|
||||
}
|
||||
startShard, err := cache.StartShardInEpoch(tInfo.Epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if startShard != params.BeaconConfig().FarFutureEpoch {
|
||||
t.Error("Expected start shard not to exist in empty cache")
|
||||
}
|
||||
|
||||
if err := cache.AddStartShard(tInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
startShard, err = cache.StartShardInEpoch(tInfo.Epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(startShard, tInfo.StartShard) {
|
||||
t.Errorf(
|
||||
"Expected fetched start shard to be %v, got %v",
|
||||
tInfo.StartShard,
|
||||
startShard,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartShard_MaxSize(t *testing.T) {
|
||||
cache := NewStartShardCache()
|
||||
|
||||
for i := uint64(0); i < params.BeaconConfig().ShardCount+1; i++ {
|
||||
tInfo := &StartShardByEpoch{
|
||||
Epoch: i,
|
||||
}
|
||||
if err := cache.AddStartShard(tInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cache.startShardCache.ListKeys()) != maxStartShardListSize {
|
||||
t.Errorf(
|
||||
"Expected hash cache key size to be %d, got %d",
|
||||
maxStartShardListSize,
|
||||
len(cache.startShardCache.ListKeys()),
|
||||
)
|
||||
}
|
||||
}
|
||||
98
beacon-chain/cache/total_balance.go
vendored
Normal file
98
beacon-chain/cache/total_balance.go
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotTotalBalanceInfo will be returned when a cache object is not a pointer to
|
||||
// a TotalBalanceByEpoch struct.
|
||||
ErrNotTotalBalanceInfo = errors.New("object is not a total balance obj")
|
||||
|
||||
// maxTotalBalanceListSize defines the max number of total balance can cache.
|
||||
maxTotalBalanceListSize = 1000
|
||||
|
||||
// Metrics.
|
||||
totalBalanceCacheMiss = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "total_balance_cache_miss",
|
||||
Help: "The number of total balance requests that aren't present in the cache.",
|
||||
})
|
||||
totalBalanceCacheHit = promauto.NewCounter(prometheus.CounterOpts{
|
||||
Name: "total_balance_cache_hit",
|
||||
Help: "The number of total balance requests that are present in the cache.",
|
||||
})
|
||||
)
|
||||
|
||||
// TotalBalanceByEpoch defines the total validator balance per epoch.
|
||||
type TotalBalanceByEpoch struct {
|
||||
Epoch uint64
|
||||
TotalBalance uint64
|
||||
}
|
||||
|
||||
// TotalBalanceCache is a struct with 1 queue for looking up total balance by epoch.
|
||||
type TotalBalanceCache struct {
|
||||
totalBalanceCache *cache.FIFO
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// totalBalanceKeyFn takes the epoch as the key for the total balance of a given epoch.
|
||||
func totalBalanceKeyFn(obj interface{}) (string, error) {
|
||||
tInfo, ok := obj.(*TotalBalanceByEpoch)
|
||||
if !ok {
|
||||
return "", ErrNotTotalBalanceInfo
|
||||
}
|
||||
|
||||
return strconv.Itoa(int(tInfo.Epoch)), nil
|
||||
}
|
||||
|
||||
// NewTotalBalanceCache creates a new total balance cache for storing/accessing total validator balance.
|
||||
func NewTotalBalanceCache() *TotalBalanceCache {
|
||||
return &TotalBalanceCache{
|
||||
totalBalanceCache: cache.NewFIFO(totalBalanceKeyFn),
|
||||
}
|
||||
}
|
||||
|
||||
// TotalBalanceInEpoch fetches TotalBalanceByEpoch by epoch. Returns true with a
|
||||
// reference to the TotalBalanceInEpoch info, if exists. Otherwise returns false, nil.
|
||||
func (c *TotalBalanceCache) TotalBalanceInEpoch(epoch uint64) (uint64, error) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
obj, exists, err := c.totalBalanceCache.GetByKey(strconv.Itoa(int(epoch)))
|
||||
if err != nil {
|
||||
return params.BeaconConfig().FarFutureEpoch, err
|
||||
}
|
||||
|
||||
if exists {
|
||||
totalBalanceCacheHit.Inc()
|
||||
} else {
|
||||
totalBalanceCacheMiss.Inc()
|
||||
return params.BeaconConfig().FarFutureEpoch, nil
|
||||
}
|
||||
|
||||
tInfo, ok := obj.(*TotalBalanceByEpoch)
|
||||
if !ok {
|
||||
return params.BeaconConfig().FarFutureEpoch, ErrNotTotalBalanceInfo
|
||||
}
|
||||
|
||||
return tInfo.TotalBalance, nil
|
||||
}
|
||||
|
||||
// AddTotalBalance adds TotalBalanceByEpoch object to the cache. This method also trims the least
|
||||
// recently added TotalBalanceByEpoch object if the cache size has ready the max cache size limit.
|
||||
func (c *TotalBalanceCache) AddTotalBalance(totalBalance *TotalBalanceByEpoch) error {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if err := c.totalBalanceCache.AddIfNotPresent(totalBalance); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trim(c.totalBalanceCache, maxTotalBalanceListSize)
|
||||
return nil
|
||||
}
|
||||
83
beacon-chain/cache/total_balance_test.go
vendored
Normal file
83
beacon-chain/cache/total_balance_test.go
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestTotalBalanceKeyFn_OK(t *testing.T) {
|
||||
tInfo := &TotalBalanceByEpoch{
|
||||
Epoch: 333,
|
||||
TotalBalance: 321321323,
|
||||
}
|
||||
|
||||
key, err := totalBalanceKeyFn(tInfo)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if key != strconv.Itoa(int(tInfo.Epoch)) {
|
||||
t.Errorf("Incorrect hash key: %s, expected %s", key, strconv.Itoa(int(tInfo.Epoch)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalBalanceKeyFn_InvalidObj(t *testing.T) {
|
||||
_, err := totalBalanceKeyFn("bad")
|
||||
if err != ErrNotTotalBalanceInfo {
|
||||
t.Errorf("Expected error %v, got %v", ErrNotTotalBalanceInfo, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalBalanceCache_TotalBalanceByEpoch(t *testing.T) {
|
||||
cache := NewTotalBalanceCache()
|
||||
|
||||
tInfo := &TotalBalanceByEpoch{
|
||||
Epoch: 111,
|
||||
TotalBalance: 345435435,
|
||||
}
|
||||
totalBalance, err := cache.TotalBalanceInEpoch(tInfo.Epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if totalBalance != params.BeaconConfig().FarFutureEpoch {
|
||||
t.Error("Expected total balance not to exist in empty cache")
|
||||
}
|
||||
|
||||
if err := cache.AddTotalBalance(tInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
totalBalance, err = cache.TotalBalanceInEpoch(tInfo.Epoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(totalBalance, tInfo.TotalBalance) {
|
||||
t.Errorf(
|
||||
"Expected fetched total balance to be %v, got %v",
|
||||
tInfo.TotalBalance,
|
||||
totalBalance,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalBalance_MaxSize(t *testing.T) {
|
||||
cache := NewTotalBalanceCache()
|
||||
|
||||
for i := uint64(0); i < params.BeaconConfig().EpochsPerHistoricalVector+100; i++ {
|
||||
tInfo := &TotalBalanceByEpoch{
|
||||
Epoch: i,
|
||||
}
|
||||
if err := cache.AddTotalBalance(tInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cache.totalBalanceCache.ListKeys()) != maxTotalBalanceListSize {
|
||||
t.Errorf(
|
||||
"Expected hash cache key size to be %d, got %d",
|
||||
maxTotalBalanceListSize,
|
||||
len(cache.totalBalanceCache.ListKeys()),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["main.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/chaintest",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//beacon-chain/chaintest/backend:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"@com_github_go_yaml_yaml//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_x_cray_logrus_prefixed_formatter//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_binary(
|
||||
name = "chaintest",
|
||||
embed = [":go_default_library"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = ["yaml_test.go"],
|
||||
data = glob(["tests/**"]),
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/chaintest/backend:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -1,238 +0,0 @@
|
||||
# Ethereum 2.0 E2E Test Suite
|
||||
|
||||
This is a test-suite for conformity end-2-end tests for Prysm's implementation of the Ethereum 2.0 specification. Implementation teams have decided to utilize YAML as a general conformity test format for the current beacon chain's runtime functionality.
|
||||
|
||||
The test suite opts for YAML due to wide language support and support for inline comments.
|
||||
|
||||
# Testing Format
|
||||
|
||||
The testing format follows the official ETH2.0 Specification created [here](https://github.com/ethereum/eth2.0-specs/blob/master/specs/test-format.md)
|
||||
|
||||
## Stateful Tests
|
||||
|
||||
Chain tests check for conformity of a certain client to the beacon chain specification for items such as the fork choice rule and Casper FFG validator rewards & penalties. Stateful tests need to specify a certain configuration of a beacon chain, with items such as the number validators, in the YAML file. Sample tests will all required fields are shown below.
|
||||
|
||||
### State Transition
|
||||
|
||||
The most important use case for this test format is to verify the ins and outs of the Ethereum Phase 0 Beacon Chain state advancement. The specification details very strict guidelines for blocks to successfully trigger a state transition, including items such as Casper Proof of Stake slashing conditions of validators, pseudorandomness in the form of RANDAO, and attestation on shard blocks being processed all inside each incoming beacon block. The YAML configuration for this test type allows for configuring a state transition run over N slots, triggering slashing conditions, processing deposits of new validators, and more.
|
||||
|
||||
An example state transition test for testing slot and block processing will look as follows:
|
||||
|
||||
```yaml
|
||||
title: Sample Ethereum Serenity State Transition Tests
|
||||
summary: Testing full state transition block processing
|
||||
test_suite: prysm
|
||||
fork: sapphire
|
||||
version: 1.0
|
||||
test_cases:
|
||||
- config:
|
||||
epoch_length: 64
|
||||
deposits_for_chain_start: 1000
|
||||
num_slots: 32 # Testing advancing state to slot < SlotsPerEpoch
|
||||
results:
|
||||
slot: 32
|
||||
num_validators: 1000
|
||||
- config:
|
||||
epoch_length: 64
|
||||
deposits_for_chain_start: 16384
|
||||
num_slots: 64
|
||||
deposits:
|
||||
- slot: 1
|
||||
amount: 32
|
||||
merkle_index: 0
|
||||
pubkey: !!binary |
|
||||
SlAAbShSkUg7PLiPHZI/rTS1uAvKiieOrifPN6Moso0=
|
||||
- slot: 15
|
||||
amount: 32
|
||||
merkle_index: 1
|
||||
pubkey: !!binary |
|
||||
Oklajsjdkaklsdlkajsdjlajslkdjlkasjlkdjlajdsd
|
||||
- slot: 55
|
||||
amount: 32
|
||||
merkle_index: 2
|
||||
pubkey: !!binary |
|
||||
LkmqmqoodLKAslkjdkajsdljasdkajlksjdasldjasdd
|
||||
proposer_slashings:
|
||||
- slot: 16 # At slot 16, we trigger a proposal slashing occurring
|
||||
proposer_index: 16385 # We penalize the proposer that was just added from slot 15
|
||||
proposal_1_shard: 0
|
||||
proposal_1_slot: 15
|
||||
proposal_1_root: !!binary |
|
||||
LkmqmqoodLKAslkjdkajsdljasdkajlksjdasldjasdd
|
||||
proposal_2_shard: 0
|
||||
proposal_2_slot: 15
|
||||
proposal_2_root: !!binary |
|
||||
LkmqmqoodLKAslkjdkajsdljasdkajlksjdasldjasdd
|
||||
attester_slashings:
|
||||
- slot: 59 # At slot 59, we trigger a attester slashing
|
||||
slashable_vote_data_1_slot: 55
|
||||
slashable_vote_data_2_slot: 55
|
||||
slashable_vote_data_1_justified_slot: 0
|
||||
slashable_vote_data_2_justified_slot: 1
|
||||
slashable_vote_data_1_custody_0_indices: [16386]
|
||||
slashable_vote_data_1_custody_1_indices: []
|
||||
slashable_vote_data_2_custody_0_indices: []
|
||||
slashable_vote_data_2_custody_1_indices: [16386]
|
||||
results:
|
||||
slot: 64
|
||||
num_validators: 16387
|
||||
penalized_validators: [16385, 16386] # We test that the validators at indices 16385, 16386 were indeed penalized
|
||||
- config:
|
||||
skip_slots: [10, 20]
|
||||
epoch_length: 64
|
||||
deposits_for_chain_start: 1000
|
||||
num_slots: 128 # Testing advancing state's slot == 2*SlotsPerEpoch
|
||||
deposits:
|
||||
- slot: 10
|
||||
amount: 32
|
||||
merkle_index: 0
|
||||
pubkey: !!binary |
|
||||
SlAAbShSkUg7PLiPHZI/rTS1uAvKiieOrifPN6Moso0=
|
||||
- slot: 20
|
||||
amount: 32
|
||||
merkle_index: 1
|
||||
pubkey: !!binary |
|
||||
Oklajsjdkaklsdlkajsdjlajslkdjlkasjlkdjlajdsd
|
||||
results:
|
||||
slot: 128
|
||||
num_validators: 1000 # Validator registry should not have grown if slots 10 and 20 were skipped
|
||||
```
|
||||
|
||||
#### Test Configuration Options
|
||||
|
||||
The following configuration options are available for state transition tests:
|
||||
|
||||
**Config**
|
||||
|
||||
- **skip_slots**: `[int]` determines which slot numbers to simulate a proposer not submitting a block in the state transition TODO
|
||||
- **epoch_length**: `int` the number of slots in an epoch
|
||||
- **deposits_for_chain_start**: `int` the number of eth deposits needed for the beacon chain to initialize (this simulates an initial validator registry based on this number in the test)
|
||||
- **num_slots**: `int` the number of times we run a state transition in the test
|
||||
- **deposits**: `[Deposit Config]` trigger a new validator deposit into the beacon state based on configuration options
|
||||
- **proposer_slashings**: `[Proposer Slashing Config]` trigger a proposer slashing at a certain slot for a certain proposer index
|
||||
- **attester_slashings**: `[Casper Slashing Config]` trigger a attester slashing at a certain slot
|
||||
- **validator_exits**: `[Validator Exit Config]` trigger a voluntary validator exit at a certain slot for a validator index
|
||||
|
||||
**Deposit Config**
|
||||
|
||||
- **slot**: `int` a slot in which to trigger a deposit during a state transition test
|
||||
- **amount**: `int` the ETH deposit amount to trigger
|
||||
- **merkle_index**: `int` the index of the deposit in the validator deposit contract's Merkle trie
|
||||
- **pubkey**: `!!binary` the public key of the validator in the triggered deposit object
|
||||
|
||||
**Proposer Slashing Config**
|
||||
|
||||
- **slot**: `int` a slot in which to trigger a proposer slashing during a state transition test
|
||||
- **proposer_index**: `int` the proposer to penalize
|
||||
- **proposal_1_shard**: `int` the first proposal data's shard id
|
||||
- **proposal_1_slot**: `int` the first proposal data's slot
|
||||
- **proposal_1_root**: `!!binary` the second proposal data's block root
|
||||
- **proposal_2_shard**: `int` the second proposal data's shard id
|
||||
- **proposal_2_slot**: `int` the second proposal data's slot
|
||||
- **proposal_2_root**: `!!binary` the second proposal data's block root
|
||||
|
||||
**Casper Slashing Config**
|
||||
|
||||
- **slot**: `int` a slot in which to trigger a attester slashing during a state transition test
|
||||
- **slashable_vote_data_1_slot**: `int` the slot of the attestation data of slashableVoteData1
|
||||
- **slashable_vote_data_2_slot**: `int` the slot of the attestation data of slashableVoteData2
|
||||
- **slashable_vote_data_1_justified_slot**: `int` the justified slot of the attestation data of slashableVoteData1
|
||||
- **slashable_vote_data_2_justified_slot**: `int` the justified slot of the attestation data of slashableVoteData2
|
||||
- **slashable_vote_data_1_custody_0_indices**: `[int]` the custody indices 0 for slashableVoteData1
|
||||
- **slashable_vote_data_1_custody_1_indices**: `[int]` the custody indices 1 for slashableVoteData1
|
||||
- **slashable_vote_data_2_custody_0_indices**: `[int]` the custody indices 0 for slashableVoteData2
|
||||
- **slashable_vote_data_2_custody_1_indices**: `[int]` the custody indices 1 for slashableVoteData2
|
||||
|
||||
**Validator Exit Config**
|
||||
|
||||
- **slot**: `int` the slot at which a validator wants to voluntarily exit the validator registry
|
||||
- **validator_index**: `int` the index of the validator in the registry that is exiting
|
||||
|
||||
#### Test Results
|
||||
|
||||
The following are **mandatory** fields as they correspond to checks done at the end of the test run.
|
||||
|
||||
- **slot**: `int` check the slot of the state resulting from applying N state transitions in the test
|
||||
- **num_validators** `[int]` check the number of validators in the validator registry after applying N state transitions
|
||||
- **penalized_validators** `[int]` the list of validator indices we verify were penalized during the test
|
||||
- **exited_validators**: `[int]` the list of validator indices we verify voluntarily exited the registry during the test
|
||||
|
||||
## Stateless Tests
|
||||
|
||||
Stateless tests represent simple unit test definitions for important invariants in the ETH2.0 runtime. In particular, these test conformity across clients with respect to items such as Simple Serialize (SSZ), Signature Aggregation (BLS), and Validator Shuffling
|
||||
|
||||
**Simple Serialize**
|
||||
|
||||
TODO
|
||||
|
||||
**Signature Aggregation**
|
||||
|
||||
TODO
|
||||
|
||||
**Validator Shuffling**
|
||||
|
||||
```yaml
|
||||
title: Shuffling Algorithm Tests
|
||||
summary: Test vectors for shuffling a list based upon a seed using `shuffle`
|
||||
test_suite: shuffle
|
||||
fork: tchaikovsky
|
||||
version: 1.0
|
||||
|
||||
test_cases:
|
||||
- input: []
|
||||
output: []
|
||||
seed: !!binary ""
|
||||
- name: boring_list
|
||||
description: List with a single element, 0
|
||||
input: [0]
|
||||
output: [0]
|
||||
seed: !!binary ""
|
||||
- input: [255]
|
||||
output: [255]
|
||||
seed: !!binary ""
|
||||
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||
output: [1, 6, 4, 1, 6, 6, 2, 2, 4, 5]
|
||||
seed: !!binary ""
|
||||
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||
output: [4, 7, 10, 13, 3, 1, 2, 9, 12, 6, 11, 8, 5]
|
||||
seed: !!binary ""
|
||||
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||
output: [6, 65, 2, 5, 4, 2, 6, 6, 1, 1]
|
||||
seed: !!binary |
|
||||
JlAYJ5H2j8g7PLiPHZI/rTS1uAvKiieOrifPN6Moso0=
|
||||
```
|
||||
|
||||
# Using the Runner
|
||||
|
||||
First, create a directory containing the YAML files you wish to test (or use the default `./sampletests` directory included with Prysm).
|
||||
Then, make sure you have the following folder structure for the directory:
|
||||
|
||||
```
|
||||
yourtestdir/
|
||||
fork-choice-tests/
|
||||
*.yaml
|
||||
...
|
||||
shuffle-tests/
|
||||
*.yaml
|
||||
...
|
||||
state-tests/
|
||||
*.yaml
|
||||
...
|
||||
```
|
||||
|
||||
Then, navigate to the test runner's directory and use the go tool as follows:
|
||||
|
||||
```bash
|
||||
go run main.go -tests-dir /path/to/your/testsdir
|
||||
```
|
||||
|
||||
The runner will then start up a simulated backend and run all your specified YAML tests.
|
||||
|
||||
```bash
|
||||
[2018-11-06 15:01:44] INFO ----Running Chain Tests----
|
||||
[2018-11-06 15:01:44] INFO Running 4 YAML Tests
|
||||
[2018-11-06 15:01:44] INFO Title: Sample Ethereum 2.0 Beacon Chain Test
|
||||
[2018-11-06 15:01:44] INFO Summary: Basic, functioning fork choice rule for Ethereum 2.0
|
||||
[2018-11-06 15:01:44] INFO Test Suite: prysm
|
||||
[2018-11-06 15:01:44] INFO Test Runs Finished In: 0.000643545 Seconds
|
||||
```
|
||||
@@ -1,43 +0,0 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"fork_choice_test_format.go",
|
||||
"helpers.go",
|
||||
"shuffle_test_format.go",
|
||||
"simulated_backend.go",
|
||||
"state_test_format.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/chaintest/backend",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/blockchain:go_default_library",
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/state:go_default_library",
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//beacon-chain/utils:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/forkutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/sliceutil:go_default_library",
|
||||
"//shared/trieutil:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = ["simulated_backend_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/db:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -1,51 +0,0 @@
|
||||
package backend
|
||||
|
||||
// ForkChoiceTest --
|
||||
type ForkChoiceTest struct {
|
||||
Title string
|
||||
Summary string
|
||||
TestSuite string `yaml:"test_suite"`
|
||||
TestCases []*ForkChoiceTestCase `yaml:"test_cases"`
|
||||
}
|
||||
|
||||
// ForkChoiceTestCase --
|
||||
type ForkChoiceTestCase struct {
|
||||
Config *ForkChoiceTestConfig `yaml:"config"`
|
||||
Slots []*ForkChoiceTestSlot `yaml:"slots,flow"`
|
||||
Results *ForkChoiceTestResult `yaml:"results"`
|
||||
}
|
||||
|
||||
// ForkChoiceTestConfig --
|
||||
type ForkChoiceTestConfig struct {
|
||||
ValidatorCount uint64 `yaml:"validator_count"`
|
||||
CycleLength uint64 `yaml:"cycle_length"`
|
||||
ShardCount uint64 `yaml:"shard_count"`
|
||||
MinCommitteeSize uint64 `yaml:"min_committee_size"`
|
||||
}
|
||||
|
||||
// ForkChoiceTestSlot --
|
||||
type ForkChoiceTestSlot struct {
|
||||
SlotNumber uint64 `yaml:"slot_number"`
|
||||
NewBlock *TestBlock `yaml:"new_block"`
|
||||
Attestations []*TestAttestation `yaml:",flow"`
|
||||
}
|
||||
|
||||
// ForkChoiceTestResult --
|
||||
type ForkChoiceTestResult struct {
|
||||
Head string
|
||||
LastJustifiedBlock string `yaml:"last_justified_block"`
|
||||
LastFinalizedBlock string `yaml:"last_finalized_block"`
|
||||
}
|
||||
|
||||
// TestBlock --
|
||||
type TestBlock struct {
|
||||
ID string `yaml:"ID"`
|
||||
Parent string `yaml:"parent"`
|
||||
}
|
||||
|
||||
// TestAttestation --
|
||||
type TestAttestation struct {
|
||||
Block string `yaml:"block"`
|
||||
ValidatorRegistry string `yaml:"validators"`
|
||||
CommitteeSlot uint64 `yaml:"committee_slot"`
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/forkutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/trieutil"
|
||||
)
|
||||
|
||||
// Generates a simulated beacon block to use
|
||||
// in the next state transition given the current state,
|
||||
// the previous beacon block, and previous beacon block root.
|
||||
func generateSimulatedBlock(
|
||||
beaconState *pb.BeaconState,
|
||||
prevBlockRoot [32]byte,
|
||||
historicalDeposits []*pb.Deposit,
|
||||
simObjects *SimulatedObjects,
|
||||
privKeys []*bls.SecretKey,
|
||||
) (*pb.BeaconBlock, [32]byte, error) {
|
||||
stateRoot, err := hashutil.HashProto(beaconState)
|
||||
if err != nil {
|
||||
return nil, [32]byte{}, fmt.Errorf("could not tree hash state: %v", err)
|
||||
}
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(beaconState, beaconState.Slot+1)
|
||||
if err != nil {
|
||||
return nil, [32]byte{}, err
|
||||
}
|
||||
epoch := helpers.SlotToEpoch(beaconState.Slot + 1)
|
||||
buf := make([]byte, 32)
|
||||
binary.LittleEndian.PutUint64(buf, epoch)
|
||||
domain := forkutil.DomainVersion(beaconState.Fork, epoch, params.BeaconConfig().DomainRandao)
|
||||
// We make the previous validator's index sign the message instead of the proposer.
|
||||
epochSignature := privKeys[proposerIdx].Sign(buf, domain)
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: beaconState.Slot + 1,
|
||||
RandaoReveal: epochSignature.Marshal(),
|
||||
ParentRootHash32: prevBlockRoot[:],
|
||||
StateRootHash32: stateRoot[:],
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{1},
|
||||
BlockHash32: []byte{2},
|
||||
},
|
||||
Body: &pb.BeaconBlockBody{
|
||||
ProposerSlashings: []*pb.ProposerSlashing{},
|
||||
AttesterSlashings: []*pb.AttesterSlashing{},
|
||||
Attestations: []*pb.Attestation{},
|
||||
Deposits: []*pb.Deposit{},
|
||||
VoluntaryExits: []*pb.VoluntaryExit{},
|
||||
},
|
||||
}
|
||||
if simObjects.simDeposit != nil {
|
||||
depositInput := &pb.DepositInput{
|
||||
Pubkey: []byte(simObjects.simDeposit.Pubkey),
|
||||
WithdrawalCredentialsHash32: make([]byte, 32),
|
||||
ProofOfPossession: make([]byte, 96),
|
||||
}
|
||||
|
||||
data, err := helpers.EncodeDepositData(depositInput, simObjects.simDeposit.Amount, time.Now().Unix())
|
||||
if err != nil {
|
||||
return nil, [32]byte{}, fmt.Errorf("could not encode deposit data: %v", err)
|
||||
}
|
||||
|
||||
// We then update the deposits Merkle trie with the deposit data and return
|
||||
// its Merkle branch leading up to the root of the trie.
|
||||
historicalDepositData := make([][]byte, len(historicalDeposits))
|
||||
for i := range historicalDeposits {
|
||||
historicalDepositData[i] = historicalDeposits[i].DepositData
|
||||
}
|
||||
newTrie, err := trieutil.GenerateTrieFromItems(append(historicalDepositData, data), int(params.BeaconConfig().DepositContractTreeDepth))
|
||||
if err != nil {
|
||||
return nil, [32]byte{}, fmt.Errorf("could not regenerate trie: %v", err)
|
||||
}
|
||||
proof, err := newTrie.MerkleProof(int(simObjects.simDeposit.MerkleIndex))
|
||||
if err != nil {
|
||||
return nil, [32]byte{}, fmt.Errorf("could not generate proof: %v", err)
|
||||
}
|
||||
|
||||
root := newTrie.Root()
|
||||
block.Eth1Data.DepositRootHash32 = root[:]
|
||||
block.Body.Deposits = append(block.Body.Deposits, &pb.Deposit{
|
||||
DepositData: data,
|
||||
MerkleProofHash32S: proof,
|
||||
MerkleTreeIndex: simObjects.simDeposit.MerkleIndex,
|
||||
})
|
||||
}
|
||||
if simObjects.simProposerSlashing != nil {
|
||||
block.Body.ProposerSlashings = append(block.Body.ProposerSlashings, &pb.ProposerSlashing{
|
||||
ProposerIndex: simObjects.simProposerSlashing.ProposerIndex,
|
||||
ProposalData_1: &pb.ProposalSignedData{
|
||||
Slot: simObjects.simProposerSlashing.Proposal1Slot,
|
||||
Shard: simObjects.simProposerSlashing.Proposal1Shard,
|
||||
BlockRootHash32: []byte(simObjects.simProposerSlashing.Proposal1Root),
|
||||
},
|
||||
ProposalData_2: &pb.ProposalSignedData{
|
||||
Slot: simObjects.simProposerSlashing.Proposal2Slot,
|
||||
Shard: simObjects.simProposerSlashing.Proposal2Shard,
|
||||
BlockRootHash32: []byte(simObjects.simProposerSlashing.Proposal2Root),
|
||||
},
|
||||
})
|
||||
}
|
||||
if simObjects.simAttesterSlashing != nil {
|
||||
block.Body.AttesterSlashings = append(block.Body.AttesterSlashings, &pb.AttesterSlashing{
|
||||
SlashableAttestation_1: &pb.SlashableAttestation{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: simObjects.simAttesterSlashing.SlashableAttestation1Slot,
|
||||
JustifiedEpoch: simObjects.simAttesterSlashing.SlashableAttestation1JustifiedEpoch,
|
||||
},
|
||||
CustodyBitfield: []byte(simObjects.simAttesterSlashing.SlashableAttestation1CustodyBitField),
|
||||
ValidatorIndices: simObjects.simAttesterSlashing.SlashableAttestation1ValidatorIndices,
|
||||
},
|
||||
SlashableAttestation_2: &pb.SlashableAttestation{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: simObjects.simAttesterSlashing.SlashableAttestation2Slot,
|
||||
JustifiedEpoch: simObjects.simAttesterSlashing.SlashableAttestation2JustifiedEpoch,
|
||||
},
|
||||
CustodyBitfield: []byte(simObjects.simAttesterSlashing.SlashableAttestation2CustodyBitField),
|
||||
ValidatorIndices: simObjects.simAttesterSlashing.SlashableAttestation2ValidatorIndices,
|
||||
},
|
||||
})
|
||||
}
|
||||
if simObjects.simValidatorExit != nil {
|
||||
block.Body.VoluntaryExits = append(block.Body.VoluntaryExits, &pb.VoluntaryExit{
|
||||
Epoch: simObjects.simValidatorExit.Epoch,
|
||||
ValidatorIndex: simObjects.simValidatorExit.ValidatorIndex,
|
||||
})
|
||||
}
|
||||
blockRoot, err := hashutil.HashBeaconBlock(block)
|
||||
if err != nil {
|
||||
return nil, [32]byte{}, fmt.Errorf("could not tree hash new block: %v", err)
|
||||
}
|
||||
return block, blockRoot, nil
|
||||
}
|
||||
|
||||
// generateInitialSimulatedDeposits generates initial deposits for creating a beacon state in the simulated
|
||||
// backend based on the yaml configuration.
|
||||
func generateInitialSimulatedDeposits(numDeposits uint64) ([]*pb.Deposit, []*bls.SecretKey, error) {
|
||||
genesisTime := time.Date(2018, 9, 0, 0, 0, 0, 0, time.UTC).Unix()
|
||||
deposits := make([]*pb.Deposit, numDeposits)
|
||||
privKeys := make([]*bls.SecretKey, numDeposits)
|
||||
for i := 0; i < len(deposits); i++ {
|
||||
priv, err := bls.RandKey(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("could not initialize key: %v", err)
|
||||
}
|
||||
depositInput := &pb.DepositInput{
|
||||
Pubkey: priv.PublicKey().Marshal(),
|
||||
WithdrawalCredentialsHash32: make([]byte, 32),
|
||||
ProofOfPossession: make([]byte, 96),
|
||||
}
|
||||
depositData, err := helpers.EncodeDepositData(
|
||||
depositInput,
|
||||
params.BeaconConfig().MaxDepositAmount,
|
||||
genesisTime,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("could not encode genesis block deposits: %v", err)
|
||||
}
|
||||
deposits[i] = &pb.Deposit{DepositData: depositData, MerkleTreeIndex: uint64(i)}
|
||||
privKeys[i] = priv
|
||||
}
|
||||
return deposits, privKeys, nil
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package backend
|
||||
|
||||
// ShuffleTest --
|
||||
type ShuffleTest struct {
|
||||
Title string `yaml:"title"`
|
||||
Summary string `yaml:"summary"`
|
||||
TestSuite string `yaml:"test_suite"`
|
||||
Fork string `yaml:"fork"`
|
||||
Version string `yaml:"version"`
|
||||
TestCases []*ShuffleTestCase `yaml:"test_cases"`
|
||||
}
|
||||
|
||||
// ShuffleTestCase --
|
||||
type ShuffleTestCase struct {
|
||||
Input []uint64 `yaml:"input,flow"`
|
||||
Output []uint64 `yaml:"output,flow"`
|
||||
Seed string
|
||||
}
|
||||
@@ -1,393 +0,0 @@
|
||||
// Package backend contains utilities for simulating an entire
|
||||
// ETH 2.0 beacon chain for e2e tests and benchmarking
|
||||
// purposes.
|
||||
package backend
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/blockchain"
|
||||
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/utils"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/sliceutil"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// SimulatedBackend allowing for a programmatic advancement
|
||||
// of an in-memory beacon chain for client test runs
|
||||
// and other e2e use cases.
|
||||
type SimulatedBackend struct {
|
||||
chainService *blockchain.ChainService
|
||||
beaconDB *db.BeaconDB
|
||||
state *pb.BeaconState
|
||||
prevBlockRoots [][32]byte
|
||||
inMemoryBlocks []*pb.BeaconBlock
|
||||
historicalDeposits []*pb.Deposit
|
||||
}
|
||||
|
||||
// SimulatedObjects is a container to hold the
|
||||
// required primitives for generation of a beacon
|
||||
// block.
|
||||
type SimulatedObjects struct {
|
||||
simDeposit *StateTestDeposit
|
||||
simProposerSlashing *StateTestProposerSlashing
|
||||
simAttesterSlashing *StateTestAttesterSlashing
|
||||
simValidatorExit *StateTestValidatorExit
|
||||
}
|
||||
|
||||
// NewSimulatedBackend creates an instance by initializing a chain service
|
||||
// utilizing a mockDB which will act according to test run parameters specified
|
||||
// in the common ETH 2.0 client test YAML format.
|
||||
func NewSimulatedBackend() (*SimulatedBackend, error) {
|
||||
db, err := db.SetupDB()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not setup simulated backend db: %v", err)
|
||||
}
|
||||
cs, err := blockchain.NewChainService(context.Background(), &blockchain.Config{
|
||||
BeaconDB: db,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SimulatedBackend{
|
||||
chainService: cs,
|
||||
beaconDB: db,
|
||||
inMemoryBlocks: make([]*pb.BeaconBlock, 0),
|
||||
historicalDeposits: make([]*pb.Deposit, 0),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SetupBackend sets up the simulated backend with simulated deposits, and initializes the
|
||||
// state and genesis block.
|
||||
func (sb *SimulatedBackend) SetupBackend(numOfDeposits uint64) ([]*bls.SecretKey, error) {
|
||||
initialDeposits, privKeys, err := generateInitialSimulatedDeposits(numOfDeposits)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not simulate initial validator deposits: %v", err)
|
||||
}
|
||||
if err := sb.setupBeaconStateAndGenesisBlock(initialDeposits); err != nil {
|
||||
return nil, fmt.Errorf("could not set up beacon state and initialize genesis block %v", err)
|
||||
}
|
||||
return privKeys, nil
|
||||
}
|
||||
|
||||
// DB returns the underlying db instance in the simulated
|
||||
// backend.
|
||||
func (sb *SimulatedBackend) DB() *db.BeaconDB {
|
||||
return sb.beaconDB
|
||||
}
|
||||
|
||||
// GenerateBlockAndAdvanceChain generates a simulated block and runs that block though
|
||||
// state transition.
|
||||
func (sb *SimulatedBackend) GenerateBlockAndAdvanceChain(objects *SimulatedObjects, privKeys []*bls.SecretKey) error {
|
||||
prevBlockRoot := sb.prevBlockRoots[len(sb.prevBlockRoots)-1]
|
||||
// We generate a new block to pass into the state transition.
|
||||
newBlock, newBlockRoot, err := generateSimulatedBlock(
|
||||
sb.state,
|
||||
prevBlockRoot,
|
||||
sb.historicalDeposits,
|
||||
objects,
|
||||
privKeys,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not generate simulated beacon block %v", err)
|
||||
}
|
||||
newState := sb.state
|
||||
newState.LatestEth1Data = newBlock.Eth1Data
|
||||
newState, err = state.ExecuteStateTransition(
|
||||
context.Background(),
|
||||
sb.state,
|
||||
newBlock,
|
||||
prevBlockRoot,
|
||||
state.DefaultConfig(),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not execute state transition: %v", err)
|
||||
}
|
||||
|
||||
sb.state = newState
|
||||
sb.prevBlockRoots = append(sb.prevBlockRoots, newBlockRoot)
|
||||
sb.inMemoryBlocks = append(sb.inMemoryBlocks, newBlock)
|
||||
if len(newBlock.Body.Deposits) > 0 {
|
||||
sb.historicalDeposits = append(sb.historicalDeposits, newBlock.Body.Deposits...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateNilBlockAndAdvanceChain would trigger a state transition with a nil block.
|
||||
func (sb *SimulatedBackend) GenerateNilBlockAndAdvanceChain() error {
|
||||
prevBlockRoot := sb.prevBlockRoots[len(sb.prevBlockRoots)-1]
|
||||
newState, err := state.ExecuteStateTransition(
|
||||
context.Background(),
|
||||
sb.state,
|
||||
nil,
|
||||
prevBlockRoot,
|
||||
state.DefaultConfig(),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not execute state transition: %v", err)
|
||||
}
|
||||
sb.state = newState
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shutdown closes the db associated with the simulated backend.
|
||||
func (sb *SimulatedBackend) Shutdown() error {
|
||||
return sb.beaconDB.Close()
|
||||
}
|
||||
|
||||
// State is a getter to return the current beacon state
|
||||
// of the backend.
|
||||
func (sb *SimulatedBackend) State() *pb.BeaconState {
|
||||
return sb.state
|
||||
}
|
||||
|
||||
// InMemoryBlocks returns the blocks that have been processed by the simulated
|
||||
// backend.
|
||||
func (sb *SimulatedBackend) InMemoryBlocks() []*pb.BeaconBlock {
|
||||
return sb.inMemoryBlocks
|
||||
}
|
||||
|
||||
// RunForkChoiceTest uses a parsed set of chaintests from a YAML file
|
||||
// according to the ETH 2.0 client chain test specification and runs them
|
||||
// against the simulated backend.
|
||||
func (sb *SimulatedBackend) RunForkChoiceTest(testCase *ForkChoiceTestCase) error {
|
||||
defer db.TeardownDB(sb.beaconDB)
|
||||
// Utilize the config parameters in the test case to setup
|
||||
// the DB and set global config parameters accordingly.
|
||||
// Config parameters include: ValidatorCount, ShardCount,
|
||||
// CycleLength, MinCommitteeSize, and more based on the YAML
|
||||
// test language specification.
|
||||
c := params.BeaconConfig()
|
||||
c.ShardCount = testCase.Config.ShardCount
|
||||
c.SlotsPerEpoch = testCase.Config.CycleLength
|
||||
c.TargetCommitteeSize = testCase.Config.MinCommitteeSize
|
||||
params.OverrideBeaconConfig(c)
|
||||
|
||||
// Then, we create the validators based on the custom test config.
|
||||
validators := make([]*pb.Validator, testCase.Config.ValidatorCount)
|
||||
for i := uint64(0); i < testCase.Config.ValidatorCount; i++ {
|
||||
validators[i] = &pb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().ActivationExitDelay,
|
||||
Pubkey: []byte{},
|
||||
}
|
||||
}
|
||||
// TODO(#718): Next step is to update and save the blocks specified
|
||||
// in the case case into the DB.
|
||||
//
|
||||
// Then, we call the updateHead routine and confirm the
|
||||
// chain's head is the expected result from the test case.
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunShuffleTest uses validator set specified from a YAML file, runs the validator shuffle
|
||||
// algorithm, then compare the output with the expected output from the YAML file.
|
||||
func (sb *SimulatedBackend) RunShuffleTest(testCase *ShuffleTestCase) error {
|
||||
defer db.TeardownDB(sb.beaconDB)
|
||||
seed := common.BytesToHash([]byte(testCase.Seed))
|
||||
output, err := utils.ShuffleIndices(seed, testCase.Input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !reflect.DeepEqual(output, testCase.Output) {
|
||||
return fmt.Errorf("shuffle result error: expected %v, actual %v", testCase.Output, output)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunStateTransitionTest advances a beacon chain state transition an N amount of
|
||||
// slots from a genesis state, with a block being processed at every iteration
|
||||
// of the state transition function.
|
||||
func (sb *SimulatedBackend) RunStateTransitionTest(testCase *StateTestCase) error {
|
||||
defer db.TeardownDB(sb.beaconDB)
|
||||
setTestConfig(testCase)
|
||||
|
||||
privKeys, err := sb.initializeStateTest(testCase)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not initialize state test %v", err)
|
||||
}
|
||||
averageTimesPerTransition := []time.Duration{}
|
||||
startSlot := params.BeaconConfig().GenesisSlot
|
||||
for i := startSlot; i < startSlot+testCase.Config.NumSlots; i++ {
|
||||
|
||||
// If the slot is marked as skipped in the configuration options,
|
||||
// we simply run the state transition with a nil block argument.
|
||||
if sliceutil.IsInUint64(i, testCase.Config.SkipSlots) {
|
||||
if err := sb.GenerateNilBlockAndAdvanceChain(); err != nil {
|
||||
return fmt.Errorf("could not advance the chain with a nil block %v", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
simulatedObjects := sb.generateSimulatedObjects(testCase, i)
|
||||
startTime := time.Now()
|
||||
|
||||
if err := sb.GenerateBlockAndAdvanceChain(simulatedObjects, privKeys); err != nil {
|
||||
return fmt.Errorf("could not generate the block and advance the chain %v", err)
|
||||
}
|
||||
|
||||
endTime := time.Now()
|
||||
averageTimesPerTransition = append(averageTimesPerTransition, endTime.Sub(startTime))
|
||||
}
|
||||
|
||||
log.Infof(
|
||||
"with %d initial deposits, each state transition took average time = %v",
|
||||
testCase.Config.DepositsForChainStart,
|
||||
averageDuration(averageTimesPerTransition),
|
||||
)
|
||||
|
||||
if err := sb.compareTestCase(testCase); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initializeStateTest sets up the environment by generating all the required objects in order
|
||||
// to proceed with the state test.
|
||||
func (sb *SimulatedBackend) initializeStateTest(testCase *StateTestCase) ([]*bls.SecretKey, error) {
|
||||
initialDeposits, privKeys, err := generateInitialSimulatedDeposits(testCase.Config.DepositsForChainStart)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not simulate initial validator deposits: %v", err)
|
||||
}
|
||||
if err := sb.setupBeaconStateAndGenesisBlock(initialDeposits); err != nil {
|
||||
return nil, fmt.Errorf("could not set up beacon state and initialize genesis block %v", err)
|
||||
}
|
||||
return privKeys, nil
|
||||
}
|
||||
|
||||
// setupBeaconStateAndGenesisBlock creates the initial beacon state and genesis block in order to
|
||||
// proceed with the test.
|
||||
func (sb *SimulatedBackend) setupBeaconStateAndGenesisBlock(initialDeposits []*pb.Deposit) error {
|
||||
var err error
|
||||
genesisTime := time.Date(2018, 9, 0, 0, 0, 0, 0, time.UTC).Unix()
|
||||
sb.state, err = state.GenesisBeaconState(initialDeposits, uint64(genesisTime), nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not initialize simulated beacon state: %v", err)
|
||||
}
|
||||
sb.historicalDeposits = initialDeposits
|
||||
|
||||
// We do not expect hashing initial beacon state and genesis block to
|
||||
// fail, so we can safely ignore the error below.
|
||||
// #nosec G104
|
||||
stateRoot, err := hashutil.HashProto(sb.state)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not tree hash state: %v", err)
|
||||
}
|
||||
genesisBlock := b.NewGenesisBlock(stateRoot[:])
|
||||
genesisBlockRoot, err := hashutil.HashBeaconBlock(genesisBlock)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not tree hash genesis block: %v", err)
|
||||
}
|
||||
|
||||
// We now keep track of generated blocks for each state transition in
|
||||
// a slice.
|
||||
sb.prevBlockRoots = [][32]byte{genesisBlockRoot}
|
||||
sb.inMemoryBlocks = append(sb.inMemoryBlocks, genesisBlock)
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateSimulatedObjects generates the simulated objects depending on the testcase and current slot.
|
||||
func (sb *SimulatedBackend) generateSimulatedObjects(testCase *StateTestCase, slotNumber uint64) *SimulatedObjects {
|
||||
// If the slot is not skipped, we check if we are simulating a deposit at the current slot.
|
||||
var simulatedDeposit *StateTestDeposit
|
||||
for _, deposit := range testCase.Config.Deposits {
|
||||
if deposit.Slot == slotNumber {
|
||||
simulatedDeposit = deposit
|
||||
break
|
||||
}
|
||||
}
|
||||
var simulatedProposerSlashing *StateTestProposerSlashing
|
||||
for _, pSlashing := range testCase.Config.ProposerSlashings {
|
||||
if pSlashing.Slot == slotNumber {
|
||||
simulatedProposerSlashing = pSlashing
|
||||
break
|
||||
}
|
||||
}
|
||||
var simulatedAttesterSlashing *StateTestAttesterSlashing
|
||||
for _, cSlashing := range testCase.Config.AttesterSlashings {
|
||||
if cSlashing.Slot == slotNumber {
|
||||
simulatedAttesterSlashing = cSlashing
|
||||
break
|
||||
}
|
||||
}
|
||||
var simulatedValidatorExit *StateTestValidatorExit
|
||||
for _, exit := range testCase.Config.ValidatorExits {
|
||||
if exit.Epoch == slotNumber/params.BeaconConfig().SlotsPerEpoch {
|
||||
simulatedValidatorExit = exit
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return &SimulatedObjects{
|
||||
simDeposit: simulatedDeposit,
|
||||
simProposerSlashing: simulatedProposerSlashing,
|
||||
simAttesterSlashing: simulatedAttesterSlashing,
|
||||
simValidatorExit: simulatedValidatorExit,
|
||||
}
|
||||
}
|
||||
|
||||
// compareTestCase compares the state in the simulated backend against the values in inputted test case. If
|
||||
// there are any discrepancies it returns an error.
|
||||
func (sb *SimulatedBackend) compareTestCase(testCase *StateTestCase) error {
|
||||
if sb.state.Slot != testCase.Results.Slot {
|
||||
return fmt.Errorf(
|
||||
"incorrect state slot after %d state transitions without blocks, wanted %d, received %d",
|
||||
testCase.Config.NumSlots,
|
||||
sb.state.Slot,
|
||||
testCase.Results.Slot,
|
||||
)
|
||||
}
|
||||
if len(sb.state.ValidatorRegistry) != testCase.Results.NumValidators {
|
||||
return fmt.Errorf(
|
||||
"incorrect num validators after %d state transitions without blocks, wanted %d, received %d",
|
||||
testCase.Config.NumSlots,
|
||||
testCase.Results.NumValidators,
|
||||
len(sb.state.ValidatorRegistry),
|
||||
)
|
||||
}
|
||||
for _, slashed := range testCase.Results.SlashedValidators {
|
||||
if sb.state.ValidatorRegistry[slashed].SlashedEpoch == params.BeaconConfig().FarFutureEpoch {
|
||||
return fmt.Errorf(
|
||||
"expected validator at index %d to have been slashed",
|
||||
slashed,
|
||||
)
|
||||
}
|
||||
}
|
||||
for _, exited := range testCase.Results.ExitedValidators {
|
||||
if sb.state.ValidatorRegistry[exited].StatusFlags != pb.Validator_INITIATED_EXIT {
|
||||
return fmt.Errorf(
|
||||
"expected validator at index %d to have exited",
|
||||
exited,
|
||||
)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setTestConfig(testCase *StateTestCase) {
|
||||
// We setup the initial configuration for running state
|
||||
// transition tests below.
|
||||
c := params.BeaconConfig()
|
||||
c.SlotsPerEpoch = testCase.Config.SlotsPerEpoch
|
||||
c.DepositsForChainStart = testCase.Config.DepositsForChainStart
|
||||
params.OverrideBeaconConfig(c)
|
||||
}
|
||||
|
||||
func averageDuration(times []time.Duration) time.Duration {
|
||||
sum := int64(0)
|
||||
for _, t := range times {
|
||||
sum += t.Nanoseconds()
|
||||
}
|
||||
return time.Duration(sum / int64(len(times)))
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package backend
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func init() {
|
||||
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
|
||||
EnableCrosslinks: true,
|
||||
})
|
||||
}
|
||||
|
||||
func TestSimulatedBackendStop_ShutsDown(t *testing.T) {
|
||||
|
||||
backend, err := NewSimulatedBackend()
|
||||
if err != nil {
|
||||
t.Fatalf("Could not create a new simulated backedn %v", err)
|
||||
}
|
||||
if err := backend.Shutdown(); err != nil {
|
||||
t.Errorf("Could not successfully shutdown simulated backend %v", err)
|
||||
}
|
||||
|
||||
db.TeardownDB(backend.beaconDB)
|
||||
}
|
||||
|
||||
func TestGenerateBlockAndAdvanceChain_IncreasesSlot(t *testing.T) {
|
||||
backend, err := NewSimulatedBackend()
|
||||
if err != nil {
|
||||
t.Fatalf("Could not create a new simulated backend %v", err)
|
||||
}
|
||||
|
||||
privKeys, err := backend.SetupBackend(100)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not set up backend %v", err)
|
||||
}
|
||||
defer backend.Shutdown()
|
||||
defer db.TeardownDB(backend.beaconDB)
|
||||
|
||||
slotLimit := params.BeaconConfig().SlotsPerEpoch + uint64(1)
|
||||
|
||||
for i := uint64(0); i < slotLimit; i++ {
|
||||
if err := backend.GenerateBlockAndAdvanceChain(&SimulatedObjects{}, privKeys); err != nil {
|
||||
t.Fatalf("Could not generate block and transition state successfully %v for slot %d", err, backend.state.Slot+1)
|
||||
}
|
||||
if backend.inMemoryBlocks[len(backend.inMemoryBlocks)-1].Slot != backend.state.Slot {
|
||||
t.Errorf("In memory Blocks do not have the same last slot as the state, expected %d but got %v",
|
||||
backend.state.Slot, backend.inMemoryBlocks[len(backend.inMemoryBlocks)-1])
|
||||
}
|
||||
}
|
||||
|
||||
if backend.state.Slot != params.BeaconConfig().GenesisSlot+uint64(slotLimit) {
|
||||
t.Errorf("Unequal state slot and expected slot %d %d", backend.state.Slot, slotLimit)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGenerateNilBlockAndAdvanceChain_IncreasesSlot(t *testing.T) {
|
||||
backend, err := NewSimulatedBackend()
|
||||
if err != nil {
|
||||
t.Fatalf("Could not create a new simulated backedn %v", err)
|
||||
}
|
||||
|
||||
if _, err := backend.SetupBackend(100); err != nil {
|
||||
t.Fatalf("Could not set up backend %v", err)
|
||||
}
|
||||
defer backend.Shutdown()
|
||||
defer db.TeardownDB(backend.beaconDB)
|
||||
|
||||
slotLimit := params.BeaconConfig().SlotsPerEpoch + uint64(1)
|
||||
|
||||
for i := uint64(0); i < slotLimit; i++ {
|
||||
if err := backend.GenerateNilBlockAndAdvanceChain(); err != nil {
|
||||
t.Fatalf("Could not generate block and transition state successfully %v for slot %d", err, backend.state.Slot+1)
|
||||
}
|
||||
}
|
||||
|
||||
if backend.state.Slot != params.BeaconConfig().GenesisSlot+uint64(slotLimit) {
|
||||
t.Errorf("Unequal state slot and expected slot %d %d", backend.state.Slot, slotLimit)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
package backend
|
||||
|
||||
// StateTest --
|
||||
type StateTest struct {
|
||||
Title string
|
||||
Summary string
|
||||
Fork string `yaml:"fork"`
|
||||
Version string `yaml:"version"`
|
||||
TestSuite string `yaml:"test_suite"`
|
||||
TestCases []*StateTestCase `yaml:"test_cases"`
|
||||
}
|
||||
|
||||
// StateTestCase --
|
||||
type StateTestCase struct {
|
||||
Config *StateTestConfig `yaml:"config"`
|
||||
Results *StateTestResults `yaml:"results"`
|
||||
}
|
||||
|
||||
// StateTestConfig --
|
||||
type StateTestConfig struct {
|
||||
SkipSlots []uint64 `yaml:"skip_slots"`
|
||||
DepositSlots []uint64 `yaml:"deposit_slots"`
|
||||
Deposits []*StateTestDeposit `yaml:"deposits"`
|
||||
ProposerSlashings []*StateTestProposerSlashing `yaml:"proposer_slashings"`
|
||||
AttesterSlashings []*StateTestAttesterSlashing `yaml:"attester_slashings"`
|
||||
ValidatorExits []*StateTestValidatorExit `yaml:"validator_exits"`
|
||||
SlotsPerEpoch uint64 `yaml:"slots_per_epoch"`
|
||||
ShardCount uint64 `yaml:"shard_count"`
|
||||
DepositsForChainStart uint64 `yaml:"deposits_for_chain_start"`
|
||||
NumSlots uint64 `yaml:"num_slots"`
|
||||
}
|
||||
|
||||
// StateTestDeposit --
|
||||
type StateTestDeposit struct {
|
||||
Slot uint64 `yaml:"slot"`
|
||||
Amount uint64 `yaml:"amount"`
|
||||
MerkleIndex uint64 `yaml:"merkle_index"`
|
||||
Pubkey string `yaml:"pubkey"`
|
||||
}
|
||||
|
||||
// StateTestProposerSlashing --
|
||||
type StateTestProposerSlashing struct {
|
||||
Slot uint64 `yaml:"slot"`
|
||||
ProposerIndex uint64 `yaml:"proposer_index"`
|
||||
Proposal1Shard uint64 `yaml:"proposal_1_shard"`
|
||||
Proposal2Shard uint64 `yaml:"proposal_2_shard"`
|
||||
Proposal1Slot uint64 `yaml:"proposal_1_slot"`
|
||||
Proposal2Slot uint64 `yaml:"proposal_2_slot"`
|
||||
Proposal1Root string `yaml:"proposal_1_root"`
|
||||
Proposal2Root string `yaml:"proposal_2_root"`
|
||||
}
|
||||
|
||||
// StateTestAttesterSlashing --
|
||||
type StateTestAttesterSlashing struct {
|
||||
Slot uint64 `yaml:"slot"`
|
||||
SlashableAttestation1Slot uint64 `yaml:"slashable_attestation_1_slot"`
|
||||
SlashableAttestation1JustifiedEpoch uint64 `yaml:"slashable_attestation_1_justified_epoch"`
|
||||
SlashableAttestation1ValidatorIndices []uint64 `yaml:"slashable_attestation_1_validator_indices"`
|
||||
SlashableAttestation1CustodyBitField string `yaml:"slashable_attestation_1_custody_bitfield"`
|
||||
SlashableAttestation2Slot uint64 `yaml:"slashable_attestation_2_slot"`
|
||||
SlashableAttestation2JustifiedEpoch uint64 `yaml:"slashable_attestation_2_justified_epoch"`
|
||||
SlashableAttestation2ValidatorIndices []uint64 `yaml:"slashable_attestation_2_validator_indices"`
|
||||
SlashableAttestation2CustodyBitField string `yaml:"slashable_attestation_2_custody_bitfield"`
|
||||
}
|
||||
|
||||
// StateTestValidatorExit --
|
||||
type StateTestValidatorExit struct {
|
||||
Epoch uint64 `yaml:"epoch"`
|
||||
ValidatorIndex uint64 `yaml:"validator_index"`
|
||||
}
|
||||
|
||||
// StateTestResults --
|
||||
type StateTestResults struct {
|
||||
Slot uint64
|
||||
NumValidators int `yaml:"num_validators"`
|
||||
SlashedValidators []uint64 `yaml:"slashed_validators"`
|
||||
ExitedValidators []uint64 `yaml:"exited_validators"`
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/go-yaml/yaml"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/chaintest/backend"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
log "github.com/sirupsen/logrus"
|
||||
prefixed "github.com/x-cray/logrus-prefixed-formatter"
|
||||
)
|
||||
|
||||
func init() {
|
||||
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
|
||||
EnableCrosslinks: false,
|
||||
})
|
||||
}
|
||||
|
||||
func readTestsFromYaml(yamlDir string) ([]interface{}, error) {
|
||||
const forkChoiceTestsFolderName = "fork-choice-tests"
|
||||
const shuffleTestsFolderName = "shuffle-tests"
|
||||
const stateTestsFolderName = "state-tests"
|
||||
|
||||
var tests []interface{}
|
||||
|
||||
dirs, err := ioutil.ReadDir(yamlDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read YAML tests directory: %v", err)
|
||||
}
|
||||
for _, dir := range dirs {
|
||||
files, err := ioutil.ReadDir(path.Join(yamlDir, dir.Name()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read YAML tests directory: %v", err)
|
||||
}
|
||||
for _, file := range files {
|
||||
filePath := path.Join(yamlDir, dir.Name(), file.Name())
|
||||
// #nosec G304
|
||||
data, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read YAML file: %v", err)
|
||||
}
|
||||
switch dir.Name() {
|
||||
case forkChoiceTestsFolderName:
|
||||
decoded := &backend.ForkChoiceTest{}
|
||||
if err := yaml.Unmarshal(data, decoded); err != nil {
|
||||
return nil, fmt.Errorf("could not unmarshal YAML file into test struct: %v", err)
|
||||
}
|
||||
tests = append(tests, decoded)
|
||||
case shuffleTestsFolderName:
|
||||
decoded := &backend.ShuffleTest{}
|
||||
if err := yaml.Unmarshal(data, decoded); err != nil {
|
||||
return nil, fmt.Errorf("could not unmarshal YAML file into test struct: %v", err)
|
||||
}
|
||||
tests = append(tests, decoded)
|
||||
case stateTestsFolderName:
|
||||
decoded := &backend.StateTest{}
|
||||
if err := yaml.Unmarshal(data, decoded); err != nil {
|
||||
return nil, fmt.Errorf("could not unmarshal YAML file into test struct: %v", err)
|
||||
}
|
||||
tests = append(tests, decoded)
|
||||
}
|
||||
}
|
||||
}
|
||||
return tests, nil
|
||||
}
|
||||
|
||||
func runTests(tests []interface{}, sb *backend.SimulatedBackend) error {
|
||||
for _, tt := range tests {
|
||||
switch typedTest := tt.(type) {
|
||||
case *backend.ForkChoiceTest:
|
||||
log.Infof("Title: %v", typedTest.Title)
|
||||
log.Infof("Summary: %v", typedTest.Summary)
|
||||
log.Infof("Test Suite: %v", typedTest.TestSuite)
|
||||
for _, testCase := range typedTest.TestCases {
|
||||
if err := sb.RunForkChoiceTest(testCase); err != nil {
|
||||
return fmt.Errorf("chain test failed: %v", err)
|
||||
}
|
||||
}
|
||||
log.Info("Test PASSED")
|
||||
case *backend.ShuffleTest:
|
||||
log.Infof("Title: %v", typedTest.Title)
|
||||
log.Infof("Summary: %v", typedTest.Summary)
|
||||
log.Infof("Test Suite: %v", typedTest.TestSuite)
|
||||
log.Infof("Fork: %v", typedTest.Fork)
|
||||
log.Infof("Version: %v", typedTest.Version)
|
||||
for _, testCase := range typedTest.TestCases {
|
||||
if err := sb.RunShuffleTest(testCase); err != nil {
|
||||
return fmt.Errorf("chain test failed: %v", err)
|
||||
}
|
||||
}
|
||||
log.Info("Test PASSED")
|
||||
case *backend.StateTest:
|
||||
log.Infof("Title: %v", typedTest.Title)
|
||||
log.Infof("Summary: %v", typedTest.Summary)
|
||||
log.Infof("Test Suite: %v", typedTest.TestSuite)
|
||||
log.Infof("Fork: %v", typedTest.Fork)
|
||||
log.Infof("Version: %v", typedTest.Version)
|
||||
for _, testCase := range typedTest.TestCases {
|
||||
if err := sb.RunStateTransitionTest(testCase); err != nil {
|
||||
return fmt.Errorf("chain test failed: %v", err)
|
||||
}
|
||||
}
|
||||
log.Info("Test PASSED")
|
||||
default:
|
||||
return fmt.Errorf("receive unknown test type: %T", typedTest)
|
||||
}
|
||||
log.Info("-----------------------------")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
var yamlDir = flag.String("tests-dir", "", "path to directory of yaml tests")
|
||||
flag.Parse()
|
||||
|
||||
customFormatter := new(prefixed.TextFormatter)
|
||||
customFormatter.TimestampFormat = "2006-01-02 15:04:05"
|
||||
customFormatter.FullTimestamp = true
|
||||
log.SetFormatter(customFormatter)
|
||||
|
||||
tests, err := readTestsFromYaml(*yamlDir)
|
||||
if err != nil {
|
||||
log.Fatalf("Fail to load tests from yaml: %v", err)
|
||||
}
|
||||
|
||||
sb, err := backend.NewSimulatedBackend()
|
||||
if err != nil {
|
||||
log.Fatalf("Could not create backend: %v", err)
|
||||
}
|
||||
|
||||
log.Info("----Running Tests----")
|
||||
startTime := time.Now()
|
||||
|
||||
err = runTests(tests, sb)
|
||||
if err != nil {
|
||||
log.Fatalf("Test failed %v", err)
|
||||
}
|
||||
|
||||
endTime := time.Now()
|
||||
log.Infof("Test Runs Finished In: %v", endTime.Sub(startTime))
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
# Credits to Danny Ryan (Ethereum Foundation)
|
||||
---
|
||||
|
||||
title: Sample Ethereum 2.0 Beacon Chain Test
|
||||
summary: Basic, functioning fork choice rule for Ethereum 2.0
|
||||
test_suite: prysm
|
||||
test_cases:
|
||||
- config:
|
||||
validator_count: 100
|
||||
cycle_length: 8
|
||||
shard_count: 64
|
||||
min_committee_size: 8
|
||||
slots:
|
||||
# "slot_number" has a minimum of 1
|
||||
- slot_number: 1
|
||||
new_block:
|
||||
id: A
|
||||
# "*" is used for the genesis block
|
||||
parent: "*"
|
||||
attestations:
|
||||
- block: A
|
||||
# the following is a shorthand string for [0, 1, 2, 3, 4, 5]
|
||||
validators: "0-5"
|
||||
- slot_number: 2
|
||||
new_block:
|
||||
id: B
|
||||
parent: A
|
||||
attestations:
|
||||
- block: B
|
||||
validators: "0-5"
|
||||
- slot_number: 3
|
||||
new_block:
|
||||
id: C
|
||||
parent: A
|
||||
attestations:
|
||||
# attestation "committee_slot" defaults to the slot during which the attestation occurs
|
||||
- block: C
|
||||
validators: "2-7"
|
||||
# default "committee_slot" can be directly overridden
|
||||
- block: C
|
||||
committee_slot: 2
|
||||
validators: "6, 7"
|
||||
- slot_number: 4
|
||||
new_block:
|
||||
id: D
|
||||
parent: C
|
||||
attestations:
|
||||
- block: D
|
||||
validators: "1-4"
|
||||
# slots can be skipped entirely (5 in this case)
|
||||
- slot_number: 6
|
||||
new_block:
|
||||
id: E
|
||||
parent: D
|
||||
attestations:
|
||||
- block: E
|
||||
validators: "0-4"
|
||||
- block: B
|
||||
validators: "5, 6, 7"
|
||||
results:
|
||||
head: E
|
||||
last_justified_block: "*"
|
||||
last_finalized_block: "*"
|
||||
@@ -1,44 +0,0 @@
|
||||
# Credits to Danny Ryan (Ethereum Foundation)
|
||||
---
|
||||
|
||||
title: Shuffling Algorithm Tests
|
||||
summary: Test vectors for shuffling a list based upon a seed using `shuffle`
|
||||
test_suite: shuffle
|
||||
fork: tchaikovsky
|
||||
version: 1.0
|
||||
|
||||
test_cases:
|
||||
- config:
|
||||
validator_count: 100
|
||||
cycle_length: 8
|
||||
shard_count: 32
|
||||
min_committee_size: 8
|
||||
- input: []
|
||||
output: []
|
||||
seed: !!binary ""
|
||||
- name: boring_list
|
||||
description: List with a single element, 0
|
||||
input: [0]
|
||||
output: [0]
|
||||
seed: !!binary ""
|
||||
- input: [255]
|
||||
output: [255]
|
||||
seed: !!binary ""
|
||||
- input: [4, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||
output: [2, 1, 6, 1, 4, 5, 6, 4, 6, 2]
|
||||
seed: !!binary ""
|
||||
- input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||
output: [4, 9, 1, 13, 8, 3, 5, 10, 7, 6, 11, 2, 12]
|
||||
seed: !!binary ""
|
||||
- input: [65, 6, 2, 6, 1, 4, 6, 2, 1, 5]
|
||||
output: [6, 1, 2, 2, 6, 6, 1, 5, 65, 4]
|
||||
seed: !!binary |
|
||||
JlAYJ5H2j8g7PLiPHZI/rTS1uAvKiieOrifPN6Moso0=
|
||||
- input: [35, 6, 2, 6, 1, 4, 6, 2, 1, 5, 7, 98, 3, 2, 11]
|
||||
output: [35, 1, 6, 4, 6, 6, 5, 11, 2, 3, 7, 1, 2, 2, 98]
|
||||
seed: !!binary |
|
||||
VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIDEzIGxhenkgZG9ncy4=
|
||||
- input: [35, 6, 2, 6, 1, 4, 6, 2, 1, 5, 7, 98, 3, 2, 11]
|
||||
output: [98, 6, 6, 11, 5, 35, 2, 7, 2, 6, 4, 2, 1, 3, 1]
|
||||
seed: !!binary |
|
||||
rDTbe23J4UA0yLIurjbJqk49VcavAC0Nysas+l5MlwvLc0B/JqQ=
|
||||
@@ -1,82 +0,0 @@
|
||||
title: Sample Ethereum Serenity State Transition Tests
|
||||
summary: Testing full state transition block processing
|
||||
test_suite: prysm
|
||||
fork: sapphire
|
||||
version: 1.0
|
||||
test_cases:
|
||||
- config:
|
||||
slots_per_epoch: 64
|
||||
deposits_for_chain_start: 64
|
||||
num_slots: 32 # Testing advancing state to slot < SlotsPerEpoch
|
||||
results:
|
||||
slot: 9223372036854775840
|
||||
num_validators: 64
|
||||
- config:
|
||||
slots_per_epoch: 64
|
||||
deposits_for_chain_start: 64
|
||||
num_slots: 64 # Testing advancing state to exactly slot == SlotsPerEpoch
|
||||
deposits:
|
||||
- slot: 9223372036854775809
|
||||
amount: 32
|
||||
merkle_index: 64
|
||||
pubkey: !!binary |
|
||||
SlAAbShSkUg7PLiPHZI/rTS1uAvKiieOrifPN6Moso0=
|
||||
- slot: 9223372036854775823
|
||||
amount: 32
|
||||
merkle_index: 65
|
||||
pubkey: !!binary |
|
||||
Oklajsjdkaklsdlkajsdjlajslkdjlkasjlkdjlajdsd
|
||||
- slot: 9223372036854775863
|
||||
amount: 32
|
||||
merkle_index: 66
|
||||
pubkey: !!binary |
|
||||
LkmqmqoodLKAslkjdkajsdljasdkajlksjdasldjasdd
|
||||
proposer_slashings:
|
||||
- slot: 9223372036854775824 # At slot 9223372036854775824, we trigger a proposal slashing occurring
|
||||
proposer_index: 50 # We penalize the proposer that was just added from slot 15
|
||||
proposal_1_shard: 0
|
||||
proposal_1_slot: 15
|
||||
proposal_1_root: !!binary |
|
||||
LkmqmqoodLKAslkjdkajsdljasdkajlksjdasldjasdd
|
||||
proposal_2_shard: 0
|
||||
proposal_2_slot: 15
|
||||
proposal_2_root: !!binary |
|
||||
LkmqmqoodLKAslkjdkajsdljasdkajlksjdasldjasdd
|
||||
attester_slashings:
|
||||
- slot: 9223372036854775868 # At slot 59, we trigger a attester slashing
|
||||
slashable_attestation_1_slot: 9223372036854775864
|
||||
slashable_attestation_2_slot: 9223372036854775864
|
||||
slashable_attestation_1_justified_epoch: 0
|
||||
slashable_attestation_2_justified_epoch: 1
|
||||
slashable_attestation_1_custody_bitfield: !binary "F"
|
||||
slashable_attestation_1_validator_indices: [1, 2, 3, 4, 5, 6, 7, 51]
|
||||
slashable_attestation_2_custody_bitfield: !binary "F"
|
||||
slashable_attestation_2_validator_indices: [1, 2, 3, 4, 5, 6, 7, 51]
|
||||
validator_exits:
|
||||
- epoch: 144115188075855872
|
||||
validator_index: 45 # At slot 9223372036854775868, validator at index 45 triggers a voluntary exit
|
||||
results:
|
||||
slot: 9223372036854775872
|
||||
num_validators: 67
|
||||
penalized_validators: [50, 51] # We test that the validators at indices were indeed penalized
|
||||
exited_validators: [45] # We confirm the indices of validators that willingly exited the registry
|
||||
# TODO(1387): Waiting for spec to stable to proceed with this test case
|
||||
# - config:
|
||||
# skip_slots: [10, 20]
|
||||
# slots_per_epoch: 64
|
||||
# deposits_for_chain_start: 1000
|
||||
# num_slots: 128 # Testing advancing state's slot == 2*SlotsPerEpoch
|
||||
# deposits:
|
||||
# - slot: 10
|
||||
# amount: 32
|
||||
# merkle_index: 0
|
||||
# pubkey: !!binary |
|
||||
# SlAAbShSkUg7PLiPHZI/rTS1uAvKiieOrifPN6Moso0=
|
||||
# - slot: 20
|
||||
# amount: 32
|
||||
# merkle_index: 1
|
||||
# pubkey: !!binary |
|
||||
# Oklajsjdkaklsdlkajsdjlajslkdjlkasjlkdjlajdsd
|
||||
# results:
|
||||
# slot: 128
|
||||
# num_validators: 1000 # Validator registry should not have grown if slots 10 and 20 were skipped
|
||||
@@ -1,49 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/chaintest/backend"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
)
|
||||
|
||||
func init() {
|
||||
featureconfig.InitFeatureConfig(&featureconfig.FeatureFlagConfig{
|
||||
EnableCrosslinks: true,
|
||||
})
|
||||
}
|
||||
|
||||
func TestFromYaml_Pass(t *testing.T) {
|
||||
tests, err := readTestsFromYaml("./tests")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read yaml files: %v", err)
|
||||
}
|
||||
|
||||
sb, err := backend.NewSimulatedBackend()
|
||||
if err != nil {
|
||||
t.Fatalf("Could not create backend: %v", err)
|
||||
}
|
||||
|
||||
if err := runTests(tests, sb); err != nil {
|
||||
t.Errorf("Failed to run yaml tests %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkStateTestFromYaml(b *testing.B) {
|
||||
tests, err := readTestsFromYaml("./tests")
|
||||
if err != nil {
|
||||
b.Fatalf("Failed to read yaml files: %v", err)
|
||||
}
|
||||
|
||||
sb, err := backend.NewSimulatedBackend()
|
||||
if err != nil {
|
||||
b.Fatalf("Could not create backend: %v", err)
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if err := runTests(tests, sb); err != nil {
|
||||
b.Errorf("Failed to run yaml tests %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["rewards_penalties.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/balances",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/epoch:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/sliceutil:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = ["rewards_penalties_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -1,379 +0,0 @@
|
||||
// Package balances contains libraries to calculate reward and
|
||||
// penalty quotients. It computes new validator balances
|
||||
// for justifications, crosslinks and attestation inclusions. It
|
||||
// also computes penalties for the inactive validators.
|
||||
package balances
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/sliceutil"
|
||||
)
|
||||
|
||||
// ExpectedFFGSource applies rewards or penalties
|
||||
// for an expected FFG source. It uses total justified
|
||||
// attesting balances, total validator balances and base
|
||||
// reward quotient to calculate the reward amount.
|
||||
// Validators who voted for previous justified hash
|
||||
// will get a reward, everyone else will get a penalty.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Any validator index in previous_epoch_justified_attester_indices
|
||||
// gains base_reward(state, index) * previous_epoch_justified_attesting_balance // total_balance.
|
||||
// Any active validator v not in previous_epoch_justified_attester_indices
|
||||
// loses base_reward(state, index).
|
||||
func ExpectedFFGSource(
|
||||
state *pb.BeaconState,
|
||||
justifiedAttesterIndices []uint64,
|
||||
justifiedAttestingBalance uint64,
|
||||
totalBalance uint64) *pb.BeaconState {
|
||||
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
|
||||
|
||||
for _, index := range justifiedAttesterIndices {
|
||||
state.ValidatorBalances[index] +=
|
||||
helpers.BaseReward(state, index, baseRewardQuotient) *
|
||||
justifiedAttestingBalance /
|
||||
totalBalance
|
||||
}
|
||||
activeValidatorIndices := helpers.ActiveValidatorIndices(state.ValidatorRegistry, helpers.CurrentEpoch(state))
|
||||
didNotAttestIndices := sliceutil.NotUint64(justifiedAttesterIndices, activeValidatorIndices)
|
||||
|
||||
for _, index := range didNotAttestIndices {
|
||||
state.ValidatorBalances[index] -=
|
||||
helpers.BaseReward(state, index, baseRewardQuotient)
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
// ExpectedFFGTarget applies rewards or penalties
|
||||
// for an expected FFG target. It uses total boundary
|
||||
// attesting balances, total validator balances and base
|
||||
// reward quotient to calculate the reward amount.
|
||||
// Validators who voted for epoch boundary block
|
||||
// will get a reward, everyone else will get a penalty.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Any validator index in previous_epoch_boundary_attester_indices gains
|
||||
// base_reward(state, index) * previous_epoch_boundary_attesting_balance // total_balance.
|
||||
// Any active validator index not in previous_epoch_boundary_attester_indices loses
|
||||
// base_reward(state, index).
|
||||
func ExpectedFFGTarget(
|
||||
state *pb.BeaconState,
|
||||
boundaryAttesterIndices []uint64,
|
||||
boundaryAttestingBalance uint64,
|
||||
totalBalance uint64) *pb.BeaconState {
|
||||
|
||||
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
|
||||
|
||||
for _, index := range boundaryAttesterIndices {
|
||||
state.ValidatorBalances[index] +=
|
||||
helpers.BaseReward(state, index, baseRewardQuotient) *
|
||||
boundaryAttestingBalance /
|
||||
totalBalance
|
||||
}
|
||||
activeValidatorIndices := helpers.ActiveValidatorIndices(state.ValidatorRegistry, helpers.CurrentEpoch(state))
|
||||
didNotAttestIndices := sliceutil.NotUint64(boundaryAttesterIndices, activeValidatorIndices)
|
||||
|
||||
for _, index := range didNotAttestIndices {
|
||||
state.ValidatorBalances[index] -=
|
||||
helpers.BaseReward(state, index, baseRewardQuotient)
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
// ExpectedBeaconChainHead applies rewards or penalties
|
||||
// for an expected beacon chain head. It uses total head
|
||||
// attesting balances, total validator balances and base
|
||||
// reward quotient to calculate the reward amount.
|
||||
// Validators who voted for the canonical head block
|
||||
// will get a reward, everyone else will get a penalty.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Any validator index in previous_epoch_head_attester_indices gains
|
||||
// base_reward(state, index) * previous_epoch_head_attesting_balance // total_balance).
|
||||
// Any active validator index not in previous_epoch_head_attester_indices loses
|
||||
// base_reward(state, index).
|
||||
func ExpectedBeaconChainHead(
|
||||
state *pb.BeaconState,
|
||||
headAttesterIndices []uint64,
|
||||
headAttestingBalance uint64,
|
||||
totalBalance uint64) *pb.BeaconState {
|
||||
|
||||
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
|
||||
|
||||
for _, index := range headAttesterIndices {
|
||||
state.ValidatorBalances[index] +=
|
||||
helpers.BaseReward(state, index, baseRewardQuotient) *
|
||||
headAttestingBalance /
|
||||
totalBalance
|
||||
}
|
||||
activeValidatorIndices := helpers.ActiveValidatorIndices(state.ValidatorRegistry, helpers.CurrentEpoch(state))
|
||||
didNotAttestIndices := sliceutil.NotUint64(headAttesterIndices, activeValidatorIndices)
|
||||
|
||||
for _, index := range didNotAttestIndices {
|
||||
state.ValidatorBalances[index] -=
|
||||
helpers.BaseReward(state, index, baseRewardQuotient)
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
// InclusionDistance applies rewards based on
|
||||
// inclusion distance. It uses calculated inclusion distance
|
||||
// and base reward quotient to calculate the reward amount.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Any validator index in previous_epoch_attester_indices gains
|
||||
// base_reward(state, index) * MIN_ATTESTATION_INCLUSION_DELAY //
|
||||
// inclusion_distance(state, index)
|
||||
func InclusionDistance(
|
||||
state *pb.BeaconState,
|
||||
attesterIndices []uint64,
|
||||
totalBalance uint64,
|
||||
inclusionDistanceByAttester map[uint64]uint64) (*pb.BeaconState, error) {
|
||||
|
||||
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
|
||||
|
||||
for _, index := range attesterIndices {
|
||||
inclusionDistance, ok := inclusionDistanceByAttester[index]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("could not get inclusion distance for attester: %d", index)
|
||||
}
|
||||
if inclusionDistance == 0 {
|
||||
return nil, errors.New("could not process inclusion distance: 0")
|
||||
}
|
||||
state.ValidatorBalances[index] +=
|
||||
helpers.BaseReward(state, index, baseRewardQuotient) *
|
||||
params.BeaconConfig().MinAttestationInclusionDelay /
|
||||
inclusionDistance
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// InactivityFFGSource applies penalties to inactive
|
||||
// validators that missed to vote FFG source over an
|
||||
// extended of time. (epochs_since_finality > 4)
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Any active validator index not in previous_epoch_justified_attester_indices,
|
||||
// loses inactivity_penalty(state, index, epochs_since_finality)
|
||||
func InactivityFFGSource(
|
||||
state *pb.BeaconState,
|
||||
justifiedAttesterIndices []uint64,
|
||||
totalBalance uint64,
|
||||
epochsSinceFinality uint64) *pb.BeaconState {
|
||||
|
||||
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
|
||||
activeValidatorIndices := helpers.ActiveValidatorIndices(state.ValidatorRegistry, helpers.CurrentEpoch(state))
|
||||
didNotAttestIndices := sliceutil.NotUint64(justifiedAttesterIndices, activeValidatorIndices)
|
||||
|
||||
for _, index := range didNotAttestIndices {
|
||||
state.ValidatorBalances[index] -=
|
||||
helpers.InactivityPenalty(state, index, baseRewardQuotient, epochsSinceFinality)
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
// InactivityFFGTarget applies penalties to inactive
|
||||
// validators that missed to vote FFG target over an
|
||||
// extended of time. (epochs_since_finality > 4)
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Any active validator index not in previous_epoch_boundary_attester_indices,
|
||||
// loses inactivity_penalty(state, index, epochs_since_finality)
|
||||
func InactivityFFGTarget(
|
||||
state *pb.BeaconState,
|
||||
boundaryAttesterIndices []uint64,
|
||||
totalBalance uint64,
|
||||
epochsSinceFinality uint64) *pb.BeaconState {
|
||||
|
||||
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
|
||||
activeValidatorIndices := helpers.ActiveValidatorIndices(state.ValidatorRegistry, helpers.CurrentEpoch(state))
|
||||
didNotAttestIndices := sliceutil.NotUint64(boundaryAttesterIndices, activeValidatorIndices)
|
||||
|
||||
for _, index := range didNotAttestIndices {
|
||||
state.ValidatorBalances[index] -=
|
||||
helpers.InactivityPenalty(state, index, baseRewardQuotient, epochsSinceFinality)
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
// InactivityChainHead applies penalties to inactive validators
|
||||
// that missed to vote on canonical head over an extended of time.
|
||||
// (epochs_since_finality > 4)
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Any active validator index not in previous_epoch_head_attester_indices,
|
||||
// loses base_reward(state, index)
|
||||
func InactivityChainHead(
|
||||
state *pb.BeaconState,
|
||||
headAttesterIndices []uint64,
|
||||
totalBalance uint64) *pb.BeaconState {
|
||||
|
||||
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
|
||||
activeValidatorIndices := helpers.ActiveValidatorIndices(state.ValidatorRegistry, helpers.CurrentEpoch(state))
|
||||
didNotAttestIndices := sliceutil.NotUint64(headAttesterIndices, activeValidatorIndices)
|
||||
|
||||
for _, index := range didNotAttestIndices {
|
||||
state.ValidatorBalances[index] -=
|
||||
helpers.BaseReward(state, index, baseRewardQuotient)
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
// InactivityExitedPenalties applies additional (2x) penalties
|
||||
// to inactive validators with status EXITED_WITH_PENALTY.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Any active_validator index with validator.slashed_epoch <= current_epoch,
|
||||
// loses 2 * inactivity_penalty(state, index, epochs_since_finality) +
|
||||
// base_reward(state, index).
|
||||
func InactivityExitedPenalties(
|
||||
state *pb.BeaconState,
|
||||
totalBalance uint64,
|
||||
epochsSinceFinality uint64) *pb.BeaconState {
|
||||
|
||||
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
activeValidatorIndices := helpers.ActiveValidatorIndices(state.ValidatorRegistry, currentEpoch)
|
||||
|
||||
for _, index := range activeValidatorIndices {
|
||||
if state.ValidatorRegistry[index].SlashedEpoch <= currentEpoch {
|
||||
state.ValidatorBalances[index] -=
|
||||
2*helpers.InactivityPenalty(state, index, baseRewardQuotient, epochsSinceFinality) +
|
||||
helpers.BaseReward(state, index, baseRewardQuotient)
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
// InactivityInclusionDistance applies penalties in relation with
|
||||
// inclusion delay to inactive validators.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Any validator index in previous_epoch_attester_indices loses
|
||||
// base_reward(state, index) - base_reward(state, index) *
|
||||
// MIN_ATTESTATION_INCLUSION_DELAY // inclusion_distance(state, index)
|
||||
func InactivityInclusionDistance(
|
||||
state *pb.BeaconState,
|
||||
attesterIndices []uint64,
|
||||
totalBalance uint64,
|
||||
inclusionDistanceByAttester map[uint64]uint64) (*pb.BeaconState, error) {
|
||||
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
|
||||
|
||||
for _, index := range attesterIndices {
|
||||
inclusionDistance, ok := inclusionDistanceByAttester[index]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("could not get inclusion distance for attester: %d", index)
|
||||
}
|
||||
baseReward := helpers.BaseReward(state, index, baseRewardQuotient)
|
||||
state.ValidatorBalances[index] -= baseReward -
|
||||
baseReward*params.BeaconConfig().MinAttestationInclusionDelay/
|
||||
inclusionDistance
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// AttestationInclusion awards the the beacon
|
||||
// proposers who included previous epoch attestations.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// For each index in previous_epoch_attester_indices,
|
||||
// we determine the proposer proposer_index =
|
||||
// get_beacon_proposer_index(state, inclusion_slot(state, index))
|
||||
// and set state.validator_balances[proposer_index] +=
|
||||
// base_reward(state, index) // ATTESTATION_INCLUSION_REWARD_QUOTIENT
|
||||
func AttestationInclusion(
|
||||
state *pb.BeaconState,
|
||||
totalBalance uint64,
|
||||
prevEpochAttesterIndices []uint64,
|
||||
inclusionSlotByAttester map[uint64]uint64) (*pb.BeaconState, error) {
|
||||
|
||||
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
|
||||
for _, index := range prevEpochAttesterIndices {
|
||||
// Get the attestation's inclusion slot using the attestor's index.
|
||||
slot, ok := inclusionSlotByAttester[index]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("could not get inclusion slot for attester: %d", index)
|
||||
}
|
||||
proposerIndex, err := helpers.BeaconProposerIndex(state, slot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get proposer index: %v", err)
|
||||
}
|
||||
state.ValidatorBalances[proposerIndex] +=
|
||||
helpers.BaseReward(state, proposerIndex, baseRewardQuotient) /
|
||||
params.BeaconConfig().AttestationInclusionRewardQuotient
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// Crosslinks awards or slashs attesters
|
||||
// for attesting shard cross links.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// For slot in range(get_epoch_start_slot(previous_epoch), get_epoch_start_slot(current_epoch)),
|
||||
// let crosslink_committees_at_slot = get_crosslink_committees_at_slot(slot).
|
||||
// For every (crosslink_committee, shard) in crosslink_committee_at_slot,
|
||||
// and every index in crosslink_committee:
|
||||
// If index in attesting_validators(crosslink_committee),
|
||||
// state.validator_balances[index] += base_reward(state, index) *
|
||||
// total_attesting_balance(crosslink_committee) //
|
||||
// get_total_balance(state, crosslink_committee)).
|
||||
// If index not in attesting_validators(crosslink_committee),
|
||||
// state.validator_balances[index] -= base_reward(state, index).
|
||||
func Crosslinks(
|
||||
state *pb.BeaconState,
|
||||
thisEpochAttestations []*pb.PendingAttestation,
|
||||
prevEpochAttestations []*pb.PendingAttestation) (*pb.BeaconState, error) {
|
||||
|
||||
prevEpoch := helpers.PrevEpoch(state)
|
||||
currentEpoch := helpers.CurrentEpoch(state)
|
||||
startSlot := helpers.StartSlot(prevEpoch)
|
||||
endSlot := helpers.StartSlot(currentEpoch)
|
||||
|
||||
for i := startSlot; i < endSlot; i++ {
|
||||
// RegistryChange is a no-op when requesting slot in current and previous epoch.
|
||||
// Process crosslinks rewards will never request crosslink committees of next epoch.
|
||||
crosslinkCommittees, err := helpers.CrosslinkCommitteesAtSlot(state, i, false /* registryChange */)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get shard committees for slot %d: %v",
|
||||
i-params.BeaconConfig().GenesisSlot, err)
|
||||
}
|
||||
for _, crosslinkCommittee := range crosslinkCommittees {
|
||||
shard := crosslinkCommittee.Shard
|
||||
committee := crosslinkCommittee.Committee
|
||||
totalAttestingBalance, err :=
|
||||
epoch.TotalAttestingBalance(state, shard, thisEpochAttestations, prevEpochAttestations)
|
||||
if err != nil {
|
||||
return nil,
|
||||
fmt.Errorf("could not get attesting balance for shard committee %d: %v", shard, err)
|
||||
}
|
||||
totalBalance := epoch.TotalBalance(state, committee)
|
||||
baseRewardQuotient := helpers.BaseRewardQuotient(totalBalance)
|
||||
|
||||
attestingIndices, err := epoch.AttestingValidators(
|
||||
state,
|
||||
shard,
|
||||
thisEpochAttestations,
|
||||
prevEpochAttestations)
|
||||
if err != nil {
|
||||
return nil,
|
||||
fmt.Errorf("could not get attesting indices for shard committee %d: %v", shard, err)
|
||||
}
|
||||
for _, index := range committee {
|
||||
baseReward := helpers.BaseReward(state, index, baseRewardQuotient)
|
||||
if sliceutil.IsInUint64(index, attestingIndices) {
|
||||
state.ValidatorBalances[index] +=
|
||||
baseReward * totalAttestingBalance / totalBalance
|
||||
} else {
|
||||
state.ValidatorBalances[index] -= baseReward
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
@@ -1,677 +0,0 @@
|
||||
package balances
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestFFGSrcRewardsPenalties_AccurateBalances(t *testing.T) {
|
||||
tests := []struct {
|
||||
voted []uint64
|
||||
balanceAfterSrcRewardPenalties []uint64
|
||||
}{
|
||||
// voted represents the validator indices that voted for FFG source,
|
||||
// balanceAfterSrcRewardPenalties represents their final balances,
|
||||
// validators who voted should get an increase, who didn't should get a decrease.
|
||||
{[]uint64{}, []uint64{31999427550, 31999427550, 31999427550, 31999427550}},
|
||||
{[]uint64{0, 1}, []uint64{32000286225, 32000286225, 31999427550, 31999427550}},
|
||||
{[]uint64{0, 1, 2, 3}, []uint64{32000572450, 32000572450, 32000572450, 32000572450}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
validatorBalances := make([]uint64, 4)
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: []*pb.Validator{
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
},
|
||||
ValidatorBalances: validatorBalances,
|
||||
}
|
||||
state = ExpectedFFGSource(
|
||||
state,
|
||||
tt.voted,
|
||||
uint64(len(tt.voted))*params.BeaconConfig().MaxDepositAmount,
|
||||
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount)
|
||||
|
||||
if !reflect.DeepEqual(state.ValidatorBalances, tt.balanceAfterSrcRewardPenalties) {
|
||||
t.Errorf("FFGSrcRewardsPenalties(%v) = %v, wanted: %v",
|
||||
tt.voted, state.ValidatorBalances, tt.balanceAfterSrcRewardPenalties)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFFGTargetRewardsPenalties_AccurateBalances(t *testing.T) {
|
||||
tests := []struct {
|
||||
voted []uint64
|
||||
balanceAfterTgtRewardPenalties []uint64
|
||||
}{
|
||||
// voted represents the validator indices that voted for FFG target,
|
||||
// balanceAfterTgtRewardPenalties represents their final balances,
|
||||
// validators who voted should get an increase, who didn't should get a decrease.
|
||||
{[]uint64{}, []uint64{31999427550, 31999427550, 31999427550, 31999427550}},
|
||||
{[]uint64{0, 1}, []uint64{32000286225, 32000286225, 31999427550, 31999427550}},
|
||||
{[]uint64{0, 1, 2, 3}, []uint64{32000572450, 32000572450, 32000572450, 32000572450}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
validatorBalances := make([]uint64, 4)
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: []*pb.Validator{
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
},
|
||||
ValidatorBalances: validatorBalances,
|
||||
}
|
||||
state = ExpectedFFGTarget(
|
||||
state,
|
||||
tt.voted,
|
||||
uint64(len(tt.voted))*params.BeaconConfig().MaxDepositAmount,
|
||||
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount)
|
||||
|
||||
if !reflect.DeepEqual(state.ValidatorBalances, tt.balanceAfterTgtRewardPenalties) {
|
||||
t.Errorf("FFGTargetRewardsPenalties(%v) = %v, wanted: %v",
|
||||
tt.voted, state.ValidatorBalances, tt.balanceAfterTgtRewardPenalties)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestChainHeadRewardsPenalties_AccuratePenalties(t *testing.T) {
|
||||
tests := []struct {
|
||||
voted []uint64
|
||||
balanceAfterHeadRewardPenalties []uint64
|
||||
}{
|
||||
// voted represents the validator indices that voted for canonical chain,
|
||||
// balanceAfterHeadRewardPenalties represents their final balances,
|
||||
// validators who voted should get an increase, who didn't should get a decrease.
|
||||
{[]uint64{}, []uint64{31999427550, 31999427550, 31999427550, 31999427550}},
|
||||
{[]uint64{0, 1}, []uint64{32000286225, 32000286225, 31999427550, 31999427550}},
|
||||
{[]uint64{0, 1, 2, 3}, []uint64{32000572450, 32000572450, 32000572450, 32000572450}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
validatorBalances := make([]uint64, 4)
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: []*pb.Validator{
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
},
|
||||
ValidatorBalances: validatorBalances,
|
||||
}
|
||||
state = ExpectedBeaconChainHead(
|
||||
state,
|
||||
tt.voted,
|
||||
uint64(len(tt.voted))*params.BeaconConfig().MaxDepositAmount,
|
||||
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount)
|
||||
|
||||
if !reflect.DeepEqual(state.ValidatorBalances, tt.balanceAfterHeadRewardPenalties) {
|
||||
t.Errorf("ChainHeadRewardsPenalties(%v) = %v, wanted: %v",
|
||||
tt.voted, state.ValidatorBalances, tt.balanceAfterHeadRewardPenalties)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInclusionDistRewards_AccurateRewards(t *testing.T) {
|
||||
validators := make([]*pb.Validator, params.BeaconConfig().DepositsForChainStart)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = &pb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
var participationBitfield []byte
|
||||
// participation byte length = number of validators / target committee size / bits in a byte.
|
||||
byteLength := int(params.BeaconConfig().DepositsForChainStart / params.BeaconConfig().TargetCommitteeSize / 8)
|
||||
for i := 0; i < byteLength; i++ {
|
||||
participationBitfield = append(participationBitfield, byte(0xff))
|
||||
}
|
||||
|
||||
attestations := []*pb.PendingAttestation{
|
||||
{Data: &pb.AttestationData{
|
||||
Slot: params.BeaconConfig().GenesisSlot,
|
||||
JustifiedBlockRootHash32: []byte{},
|
||||
Shard: 0,
|
||||
CrosslinkDataRootHash32: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
AggregationBitfield: participationBitfield,
|
||||
InclusionSlot: params.BeaconConfig().GenesisSlot + 5,
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
voted []uint64
|
||||
}{
|
||||
{[]uint64{}},
|
||||
{[]uint64{251, 192}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
validatorBalances := make([]uint64, len(validators))
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 5,
|
||||
ValidatorRegistry: validators,
|
||||
ValidatorBalances: validatorBalances,
|
||||
LatestAttestations: attestations,
|
||||
PreviousJustifiedRoot: []byte{},
|
||||
LatestCrosslinks: []*pb.Crosslink{
|
||||
{
|
||||
CrosslinkDataRootHash32: params.BeaconConfig().ZeroHash[:],
|
||||
Epoch: params.BeaconConfig().GenesisEpoch,
|
||||
},
|
||||
},
|
||||
}
|
||||
block := &pb.BeaconBlock{
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Attestations: []*pb.Attestation{
|
||||
{
|
||||
Data: attestations[0].Data,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
if _, err := blocks.ProcessBlockAttestations(state, block, false /* verify sig */); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
inclusionMap := make(map[uint64]uint64)
|
||||
for _, voted := range tt.voted {
|
||||
inclusionMap[voted] = state.Slot
|
||||
}
|
||||
state, err := InclusionDistance(
|
||||
state,
|
||||
tt.voted,
|
||||
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount,
|
||||
inclusionMap)
|
||||
if err != nil {
|
||||
t.Fatalf("could not execute InclusionDistRewards:%v", err)
|
||||
}
|
||||
|
||||
for _, i := range tt.voted {
|
||||
validatorBalances[i] = 32000055555
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(state.ValidatorBalances, validatorBalances) {
|
||||
t.Errorf("InclusionDistRewards(%v) = %v, wanted: %v",
|
||||
tt.voted, state.ValidatorBalances, validatorBalances)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInclusionDistRewards_OutOfBounds(t *testing.T) {
|
||||
validators := make([]*pb.Validator, params.BeaconConfig().SlotsPerEpoch*2)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = &pb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
attestation := []*pb.PendingAttestation{
|
||||
{Data: &pb.AttestationData{Shard: 1, Slot: 0},
|
||||
AggregationBitfield: []byte{0xff}},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
voted []uint64
|
||||
balanceAfterInclusionRewards []uint64
|
||||
}{
|
||||
{[]uint64{0, 1, 2, 3}, []uint64{}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: validators,
|
||||
LatestAttestations: attestation,
|
||||
}
|
||||
inclusionMap := make(map[uint64]uint64)
|
||||
_, err := InclusionDistance(state, tt.voted, 0, inclusionMap)
|
||||
if err == nil {
|
||||
t.Fatal("InclusionDistRewards should have failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInactivityFFGSrcPenalty_AccuratePenalties(t *testing.T) {
|
||||
tests := []struct {
|
||||
voted []uint64
|
||||
balanceAfterFFGSrcPenalty []uint64
|
||||
epochsSinceFinality uint64
|
||||
}{
|
||||
// The higher the epochs since finality, the more penalties applied.
|
||||
{[]uint64{0, 1}, []uint64{32000000000, 32000000000, 31999422782, 31999422782}, 5},
|
||||
{[]uint64{}, []uint64{31999422782, 31999422782, 31999422782, 31999422782}, 5},
|
||||
{[]uint64{}, []uint64{31999418014, 31999418014, 31999418014, 31999418014}, 10},
|
||||
{[]uint64{}, []uint64{31999408477, 31999408477, 31999408477, 31999408477}, 20},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
validatorBalances := make([]uint64, 4)
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: []*pb.Validator{
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
},
|
||||
ValidatorBalances: validatorBalances,
|
||||
}
|
||||
state = InactivityFFGSource(
|
||||
state,
|
||||
tt.voted,
|
||||
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount,
|
||||
tt.epochsSinceFinality)
|
||||
|
||||
if !reflect.DeepEqual(state.ValidatorBalances, tt.balanceAfterFFGSrcPenalty) {
|
||||
t.Errorf("InactivityFFGSrcPenalty(%v) = %v, wanted: %v",
|
||||
tt.voted, state.ValidatorBalances, tt.balanceAfterFFGSrcPenalty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInactivityFFGTargetPenalty_AccuratePenalties(t *testing.T) {
|
||||
tests := []struct {
|
||||
voted []uint64
|
||||
balanceAfterFFGTargetPenalty []uint64
|
||||
epochsSinceFinality uint64
|
||||
}{
|
||||
// The higher the epochs since finality, the more penalties applied.
|
||||
{[]uint64{0, 1}, []uint64{32000000000, 32000000000, 31999422782, 31999422782}, 5},
|
||||
{[]uint64{}, []uint64{31999422782, 31999422782, 31999422782, 31999422782}, 5},
|
||||
{[]uint64{}, []uint64{31999418014, 31999418014, 31999418014, 31999418014}, 10},
|
||||
{[]uint64{}, []uint64{31999408477, 31999408477, 31999408477, 31999408477}, 20},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
validatorBalances := make([]uint64, 4)
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: []*pb.Validator{
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
},
|
||||
ValidatorBalances: validatorBalances,
|
||||
}
|
||||
state = InactivityFFGTarget(
|
||||
state,
|
||||
tt.voted,
|
||||
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount,
|
||||
tt.epochsSinceFinality)
|
||||
|
||||
if !reflect.DeepEqual(state.ValidatorBalances, tt.balanceAfterFFGTargetPenalty) {
|
||||
t.Errorf("InactivityFFGTargetPenalty(%v) = %v, wanted: %v",
|
||||
tt.voted, state.ValidatorBalances, tt.balanceAfterFFGTargetPenalty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInactivityHeadPenalty_AccuratePenalties(t *testing.T) {
|
||||
tests := []struct {
|
||||
voted []uint64
|
||||
balanceAfterInactivityHeadPenalty []uint64
|
||||
}{
|
||||
{[]uint64{}, []uint64{31999427550, 31999427550, 31999427550, 31999427550}},
|
||||
{[]uint64{0, 1}, []uint64{32000000000, 32000000000, 31999427550, 31999427550}},
|
||||
{[]uint64{0, 1, 2, 3}, []uint64{32000000000, 32000000000, 32000000000, 32000000000}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
validatorBalances := make([]uint64, 4)
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: []*pb.Validator{
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
},
|
||||
ValidatorBalances: validatorBalances,
|
||||
}
|
||||
state = InactivityChainHead(
|
||||
state,
|
||||
tt.voted,
|
||||
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount)
|
||||
|
||||
if !reflect.DeepEqual(state.ValidatorBalances, tt.balanceAfterInactivityHeadPenalty) {
|
||||
t.Errorf("InactivityHeadPenalty(%v) = %v, wanted: %v",
|
||||
tt.voted, state.ValidatorBalances, tt.balanceAfterInactivityHeadPenalty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInactivityExitedPenality_AccuratePenalties(t *testing.T) {
|
||||
tests := []struct {
|
||||
balanceAfterExitedPenalty []uint64
|
||||
epochsSinceFinality uint64
|
||||
}{
|
||||
{[]uint64{31998273114, 31998273114, 31998273114, 31998273114}, 5},
|
||||
{[]uint64{31998263578, 31998263578, 31998263578, 31998263578}, 10},
|
||||
{[]uint64{31997328976, 31997328976, 31997328976, 31997328976}, 500},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
validatorBalances := make([]uint64, 4)
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: []*pb.Validator{
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch},
|
||||
{ExitEpoch: params.BeaconConfig().FarFutureEpoch}},
|
||||
ValidatorBalances: validatorBalances,
|
||||
}
|
||||
state = InactivityExitedPenalties(
|
||||
state,
|
||||
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount,
|
||||
tt.epochsSinceFinality,
|
||||
)
|
||||
|
||||
if !reflect.DeepEqual(state.ValidatorBalances, tt.balanceAfterExitedPenalty) {
|
||||
t.Errorf("InactivityExitedPenalty(epochSinceFinality=%v) = %v, wanted: %v",
|
||||
tt.epochsSinceFinality, state.ValidatorBalances, tt.balanceAfterExitedPenalty)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInactivityInclusionPenalty_AccuratePenalties(t *testing.T) {
|
||||
validators := make([]*pb.Validator, params.BeaconConfig().DepositsForChainStart)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = &pb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
var participationBitfield []byte
|
||||
// participation byte length = number of validators / target committee size / bits in a byte.
|
||||
byteLength := int(params.BeaconConfig().DepositsForChainStart / params.BeaconConfig().TargetCommitteeSize / 8)
|
||||
for i := 0; i < byteLength; i++ {
|
||||
participationBitfield = append(participationBitfield, byte(0xff))
|
||||
}
|
||||
attestation := []*pb.PendingAttestation{
|
||||
{Data: &pb.AttestationData{Slot: params.BeaconConfig().GenesisSlot},
|
||||
AggregationBitfield: participationBitfield,
|
||||
InclusionSlot: 5},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
voted []uint64
|
||||
}{
|
||||
{[]uint64{}},
|
||||
{[]uint64{251, 192}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
validatorBalances := make([]uint64, params.BeaconConfig().SlotsPerEpoch*4)
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot,
|
||||
ValidatorRegistry: validators,
|
||||
ValidatorBalances: validatorBalances,
|
||||
LatestAttestations: attestation,
|
||||
}
|
||||
inclusionMap := make(map[uint64]uint64)
|
||||
for _, voted := range tt.voted {
|
||||
inclusionMap[voted] = state.Slot + 1
|
||||
}
|
||||
state, err := InactivityInclusionDistance(
|
||||
state,
|
||||
tt.voted,
|
||||
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount,
|
||||
inclusionMap)
|
||||
|
||||
for _, i := range tt.voted {
|
||||
validatorBalances[i] = 32000055555
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("could not execute InactivityInclusionPenalty:%v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(state.ValidatorBalances, validatorBalances) {
|
||||
t.Errorf("InactivityInclusionPenalty(%v) = %v, wanted: %v",
|
||||
tt.voted, state.ValidatorBalances, validatorBalances)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInactivityInclusionPenalty_OutOfBounds(t *testing.T) {
|
||||
validators := make([]*pb.Validator, params.BeaconConfig().SlotsPerEpoch*2)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = &pb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
attestation := []*pb.PendingAttestation{
|
||||
{Data: &pb.AttestationData{Shard: 1, Slot: 0},
|
||||
AggregationBitfield: []byte{0xff}},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
voted []uint64
|
||||
balanceAfterInclusionRewards []uint64
|
||||
}{
|
||||
{[]uint64{0, 1, 2, 3}, []uint64{}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: validators,
|
||||
LatestAttestations: attestation,
|
||||
}
|
||||
inclusionMap := make(map[uint64]uint64)
|
||||
_, err := InactivityInclusionDistance(state, tt.voted, 0, inclusionMap)
|
||||
if err == nil {
|
||||
t.Fatal("InclusionDistRewards should have failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationInclusionRewards_AccurateRewards(t *testing.T) {
|
||||
validators := make([]*pb.Validator, params.BeaconConfig().DepositsForChainStart)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = &pb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
var participationBitfield []byte
|
||||
// participation byte length = number of validators / target committee size / bits in a byte.
|
||||
byteLength := int(params.BeaconConfig().DepositsForChainStart / params.BeaconConfig().TargetCommitteeSize / 8)
|
||||
for i := 0; i < byteLength; i++ {
|
||||
participationBitfield = append(participationBitfield, byte(0xff))
|
||||
}
|
||||
atts := []*pb.Attestation{
|
||||
{Data: &pb.AttestationData{
|
||||
Slot: params.BeaconConfig().GenesisSlot,
|
||||
LatestCrosslink: &pb.Crosslink{},
|
||||
CrosslinkDataRootHash32: params.BeaconConfig().ZeroHash[:]}}}
|
||||
pendingAtts := []*pb.PendingAttestation{
|
||||
{Data: &pb.AttestationData{Slot: params.BeaconConfig().GenesisSlot},
|
||||
AggregationBitfield: participationBitfield,
|
||||
InclusionSlot: params.BeaconConfig().GenesisSlot},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
voted []uint64
|
||||
}{
|
||||
{[]uint64{}},
|
||||
{[]uint64{251}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
validatorBalances := make([]uint64, params.BeaconConfig().DepositsForChainStart)
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 10,
|
||||
ValidatorRegistry: validators,
|
||||
ValidatorBalances: validatorBalances,
|
||||
LatestAttestations: pendingAtts,
|
||||
LatestCrosslinks: []*pb.Crosslink{{}},
|
||||
}
|
||||
|
||||
_, err := blocks.ProcessBlockAttestations(state, &pb.BeaconBlock{
|
||||
Body: &pb.BeaconBlockBody{
|
||||
Attestations: atts,
|
||||
},
|
||||
}, false /* sig verification */)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
inclusionMap := make(map[uint64]uint64)
|
||||
for _, voted := range tt.voted {
|
||||
inclusionMap[voted] = state.Slot
|
||||
}
|
||||
|
||||
state, err = AttestationInclusion(
|
||||
state,
|
||||
uint64(len(validatorBalances))*params.BeaconConfig().MaxDepositAmount,
|
||||
tt.voted,
|
||||
inclusionMap)
|
||||
|
||||
for _, i := range tt.voted {
|
||||
validatorBalances[i] = 32000008680
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("could not execute InactivityInclusionPenalty:%v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(state.ValidatorBalances, validatorBalances) {
|
||||
t.Errorf("AttestationInclusionRewards(%v) = %v, wanted: %v",
|
||||
tt.voted, state.ValidatorBalances, validatorBalances)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationInclusionRewards_NoInclusionSlot(t *testing.T) {
|
||||
validators := make([]*pb.Validator, params.BeaconConfig().SlotsPerEpoch*2)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = &pb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
voted []uint64
|
||||
balanceAfterAttestationInclusion []uint64
|
||||
}{
|
||||
{[]uint64{0, 1, 2, 3}, []uint64{32000000000, 32000000000, 32000000000, 32000000000}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
validatorBalances := make([]uint64, 128)
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: validators,
|
||||
ValidatorBalances: validatorBalances,
|
||||
}
|
||||
inclusionMap := make(map[uint64]uint64)
|
||||
if _, err := AttestationInclusion(state, 0, tt.voted, inclusionMap); err == nil {
|
||||
t.Fatal("AttestationInclusionRewards should have failed with no inclusion slot")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationInclusionRewards_NoProposerIndex(t *testing.T) {
|
||||
validators := make([]*pb.Validator, params.BeaconConfig().SlotsPerEpoch*2)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = &pb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
attestation := []*pb.PendingAttestation{
|
||||
{Data: &pb.AttestationData{Shard: 1, Slot: 0},
|
||||
AggregationBitfield: []byte{0xff},
|
||||
InclusionSlot: 0},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
voted []uint64
|
||||
balanceAfterAttestationInclusion []uint64
|
||||
}{
|
||||
{[]uint64{0}, []uint64{32000071022, 32000000000, 32000000000, 32000000000}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
validatorBalances := make([]uint64, 4)
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
Slot: 1000,
|
||||
ValidatorRegistry: validators,
|
||||
ValidatorBalances: validatorBalances,
|
||||
LatestAttestations: attestation,
|
||||
}
|
||||
inclusionMap := make(map[uint64]uint64)
|
||||
if _, err := AttestationInclusion(state, 0, tt.voted, inclusionMap); err == nil {
|
||||
t.Fatal("AttestationInclusionRewards should have failed with no proposer index")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCrosslinksRewardsPenalties_AccurateBalances(t *testing.T) {
|
||||
validators := make([]*pb.Validator, params.BeaconConfig().SlotsPerEpoch*4)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = &pb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
voted []byte
|
||||
balanceAfterCrosslinkRewards []uint64
|
||||
}{
|
||||
{[]byte{0x0}, []uint64{
|
||||
32 * 1e9, 32 * 1e9, 32 * 1e9, 32 * 1e9, 32 * 1e9, 32 * 1e9, 32 * 1e9, 32 * 1e9}},
|
||||
{[]byte{0xF}, []uint64{
|
||||
31585730498, 31585730498, 31585730498, 31585730498,
|
||||
32416931985, 32416931985, 32416931985, 32416931985}},
|
||||
{[]byte{0xFF}, []uint64{
|
||||
32829149760, 32829149760, 32829149760, 32829149760,
|
||||
32829149760, 32829149760, 32829149760, 32829149760}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
validatorBalances := make([]uint64, params.BeaconConfig().SlotsPerEpoch*4)
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
|
||||
}
|
||||
attestation := []*pb.PendingAttestation{
|
||||
{Data: &pb.AttestationData{Shard: 1, Slot: 0},
|
||||
AggregationBitfield: tt.voted,
|
||||
InclusionSlot: 0},
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
ValidatorRegistry: validators,
|
||||
ValidatorBalances: validatorBalances,
|
||||
LatestAttestations: attestation,
|
||||
}
|
||||
state, err := Crosslinks(
|
||||
state,
|
||||
attestation,
|
||||
nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not apply Crosslinks rewards: %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(state.ValidatorBalances, validatorBalances) {
|
||||
t.Errorf("CrosslinksRewardsPenalties(%v) = %v, wanted: %v",
|
||||
tt.voted, state.ValidatorBalances, validatorBalances)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ go_library(
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/state/stateutils:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
@@ -17,14 +18,14 @@ go_library(
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/forkutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/sliceutil:go_default_library",
|
||||
"//shared/trieutil:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -34,16 +35,18 @@ go_test(
|
||||
srcs = [
|
||||
"block_operations_test.go",
|
||||
"block_test.go",
|
||||
"eth1_data_test.go",
|
||||
"validity_conditions_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/state:go_default_library",
|
||||
"//beacon-chain/core/state/stateutils:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/forkutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
@@ -51,8 +54,9 @@ go_test(
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//core/types:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -6,9 +6,9 @@ package blocks
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/utils"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
@@ -16,65 +16,39 @@ var clock utils.Clock = &utils.RealClock{}
|
||||
|
||||
// NewGenesisBlock returns the canonical, genesis block for the beacon chain protocol.
|
||||
func NewGenesisBlock(stateRoot []byte) *pb.BeaconBlock {
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot,
|
||||
ParentRootHash32: params.BeaconConfig().ZeroHash[:],
|
||||
StateRootHash32: stateRoot,
|
||||
RandaoReveal: params.BeaconConfig().ZeroHash[:],
|
||||
Signature: params.BeaconConfig().EmptySignature[:],
|
||||
Eth1Data: &pb.Eth1Data{
|
||||
DepositRootHash32: params.BeaconConfig().ZeroHash[:],
|
||||
BlockHash32: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
Body: &pb.BeaconBlockBody{
|
||||
ProposerSlashings: []*pb.ProposerSlashing{},
|
||||
AttesterSlashings: []*pb.AttesterSlashing{},
|
||||
Attestations: []*pb.Attestation{},
|
||||
Deposits: []*pb.Deposit{},
|
||||
VoluntaryExits: []*pb.VoluntaryExit{},
|
||||
},
|
||||
zeroHash := params.BeaconConfig().ZeroHash[:]
|
||||
genBlock := &pb.BeaconBlock{
|
||||
ParentRoot: zeroHash,
|
||||
StateRoot: stateRoot,
|
||||
Body: &pb.BeaconBlockBody{},
|
||||
Signature: params.BeaconConfig().EmptySignature[:],
|
||||
}
|
||||
return block
|
||||
return genBlock
|
||||
}
|
||||
|
||||
// BlockRoot returns the block root stored in the BeaconState for a given slot.
|
||||
// It returns an error if the requested block root is not within the BeaconState.
|
||||
// Spec pseudocode definition:
|
||||
// def get_block_root(state: BeaconState, slot: int) -> Hash32:
|
||||
// """
|
||||
// returns the block root at a recent ``slot``.
|
||||
// """
|
||||
// assert state.slot <= slot + LATEST_BLOCK_ROOTS_LENGTH
|
||||
// assert slot < state.slot
|
||||
// return state.latest_block_roots[slot % LATEST_BLOCK_ROOTS_LENGTH]
|
||||
func BlockRoot(state *pb.BeaconState, slot uint64) ([]byte, error) {
|
||||
earliestSlot := state.Slot - params.BeaconConfig().LatestBlockRootsLength
|
||||
|
||||
if slot < earliestSlot || slot >= state.Slot {
|
||||
if earliestSlot < params.BeaconConfig().GenesisSlot {
|
||||
earliestSlot = params.BeaconConfig().GenesisSlot
|
||||
}
|
||||
return []byte{}, fmt.Errorf("slot %d is not within expected range of %d to %d",
|
||||
slot-params.BeaconConfig().GenesisSlot,
|
||||
earliestSlot-params.BeaconConfig().GenesisSlot,
|
||||
state.Slot-params.BeaconConfig().GenesisSlot,
|
||||
)
|
||||
// BlockFromHeader manufactures a block from its header. It contains all its fields,
|
||||
// except for the block body.
|
||||
func BlockFromHeader(header *pb.BeaconBlockHeader) *pb.BeaconBlock {
|
||||
return &pb.BeaconBlock{
|
||||
StateRoot: header.StateRoot,
|
||||
Slot: header.Slot,
|
||||
Signature: header.Signature,
|
||||
ParentRoot: header.ParentRoot,
|
||||
}
|
||||
|
||||
return state.LatestBlockRootHash32S[slot%params.BeaconConfig().LatestBlockRootsLength], nil
|
||||
}
|
||||
|
||||
// ProcessBlockRoots processes the previous block root into the state, by appending it
|
||||
// to the most recent block roots.
|
||||
// Spec:
|
||||
// Let previous_block_root be the tree_hash_root of the previous beacon block processed in the chain.
|
||||
// Set state.latest_block_roots[(state.slot - 1) % LATEST_BLOCK_ROOTS_LENGTH] = previous_block_root.
|
||||
// If state.slot % LATEST_BLOCK_ROOTS_LENGTH == 0 append merkle_root(state.latest_block_roots) to state.batched_block_roots.
|
||||
func ProcessBlockRoots(state *pb.BeaconState, parentRoot [32]byte) *pb.BeaconState {
|
||||
state.LatestBlockRootHash32S[(state.Slot-1)%params.BeaconConfig().LatestBlockRootsLength] = parentRoot[:]
|
||||
if state.Slot%params.BeaconConfig().LatestBlockRootsLength == 0 {
|
||||
merkleRoot := hashutil.MerkleRoot(state.LatestBlockRootHash32S)
|
||||
state.BatchedBlockRootHash32S = append(state.BatchedBlockRootHash32S, merkleRoot)
|
||||
// HeaderFromBlock extracts the block header from a block.
|
||||
func HeaderFromBlock(block *pb.BeaconBlock) (*pb.BeaconBlockHeader, error) {
|
||||
header := &pb.BeaconBlockHeader{
|
||||
Slot: block.Slot,
|
||||
ParentRoot: block.ParentRoot,
|
||||
Signature: block.Signature,
|
||||
StateRoot: block.StateRoot,
|
||||
}
|
||||
return state
|
||||
root, err := ssz.HashTreeRoot(block.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not tree hash block body %v", err)
|
||||
}
|
||||
header.BodyRoot = root[:]
|
||||
return header, nil
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2,170 +2,83 @@ package blocks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestGenesisBlock_InitializedCorrectly(t *testing.T) {
|
||||
stateHash := []byte{0}
|
||||
b1 := NewGenesisBlock(stateHash)
|
||||
|
||||
if b1.ParentRootHash32 == nil {
|
||||
if b1.ParentRoot == nil {
|
||||
t.Error("genesis block missing ParentHash field")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(b1.Body.Attestations, []*pb.Attestation{}) {
|
||||
t.Errorf("genesis block should have 0 attestations")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b1.RandaoReveal, params.BeaconConfig().ZeroHash[:]) {
|
||||
t.Error("genesis block missing RandaoReveal field")
|
||||
}
|
||||
|
||||
if !bytes.Equal(b1.StateRootHash32, stateHash) {
|
||||
if !bytes.Equal(b1.StateRoot, stateHash) {
|
||||
t.Error("genesis block StateRootHash32 isn't initialized correctly")
|
||||
}
|
||||
expectedEth1 := &pb.Eth1Data{
|
||||
DepositRootHash32: params.BeaconConfig().ZeroHash[:],
|
||||
BlockHash32: params.BeaconConfig().ZeroHash[:],
|
||||
}
|
||||
|
||||
func TestHeaderFromBlock(t *testing.T) {
|
||||
dummyBody := &pb.BeaconBlockBody{
|
||||
RandaoReveal: []byte("Reveal"),
|
||||
}
|
||||
if !proto.Equal(b1.Eth1Data, expectedEth1) {
|
||||
t.Error("genesis block Eth1Data isn't initialized correctly")
|
||||
|
||||
dummyBlock := &pb.BeaconBlock{
|
||||
Slot: 10,
|
||||
Signature: []byte{'S'},
|
||||
ParentRoot: []byte("Parent"),
|
||||
StateRoot: []byte("State"),
|
||||
Body: dummyBody,
|
||||
}
|
||||
|
||||
header, err := HeaderFromBlock(dummyBlock)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedHeader := &pb.BeaconBlockHeader{
|
||||
Slot: dummyBlock.Slot,
|
||||
Signature: dummyBlock.Signature,
|
||||
ParentRoot: dummyBlock.ParentRoot,
|
||||
StateRoot: dummyBlock.StateRoot,
|
||||
}
|
||||
|
||||
bodyRoot, err := ssz.HashTreeRoot(dummyBody)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedHeader.BodyRoot = bodyRoot[:]
|
||||
|
||||
if !proto.Equal(expectedHeader, header) {
|
||||
t.Errorf("Expected Header not Equal to Retrieved Header. Expected %v , Got %v",
|
||||
proto.MarshalTextString(expectedHeader), proto.MarshalTextString(header))
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockRootAtSlot_AccurateBlockRoot(t *testing.T) {
|
||||
if params.BeaconConfig().SlotsPerEpoch != 64 {
|
||||
t.Errorf("slotsPerEpoch should be 64 for these tests to pass")
|
||||
}
|
||||
var blockRoots [][]byte
|
||||
|
||||
for i := uint64(0); i < params.BeaconConfig().LatestBlockRootsLength; i++ {
|
||||
blockRoots = append(blockRoots, []byte{byte(i)})
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
LatestBlockRootHash32S: blockRoots,
|
||||
func TestBlockFromHeader(t *testing.T) {
|
||||
dummyHeader := &pb.BeaconBlockHeader{
|
||||
Slot: 10,
|
||||
Signature: []byte{'S'},
|
||||
ParentRoot: []byte("Parent"),
|
||||
StateRoot: []byte("State"),
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
slot uint64
|
||||
stateSlot uint64
|
||||
expectedRoot []byte
|
||||
}{
|
||||
{
|
||||
slot: 0,
|
||||
stateSlot: 1,
|
||||
expectedRoot: []byte{0},
|
||||
},
|
||||
{
|
||||
slot: 2,
|
||||
stateSlot: 5,
|
||||
expectedRoot: []byte{2},
|
||||
},
|
||||
{
|
||||
slot: 64,
|
||||
stateSlot: 128,
|
||||
expectedRoot: []byte{64},
|
||||
}, {
|
||||
slot: 2999,
|
||||
stateSlot: 3000,
|
||||
expectedRoot: []byte{183},
|
||||
}, {
|
||||
slot: 2873,
|
||||
stateSlot: 3000,
|
||||
expectedRoot: []byte{57},
|
||||
},
|
||||
block := BlockFromHeader(dummyHeader)
|
||||
|
||||
expectedBlock := &pb.BeaconBlock{
|
||||
Slot: dummyHeader.Slot,
|
||||
Signature: dummyHeader.Signature,
|
||||
ParentRoot: dummyHeader.ParentRoot,
|
||||
StateRoot: dummyHeader.StateRoot,
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state.Slot = tt.stateSlot + params.BeaconConfig().GenesisSlot
|
||||
wantedSlot := tt.slot + params.BeaconConfig().GenesisSlot
|
||||
result, err := BlockRoot(state, wantedSlot)
|
||||
if err != nil {
|
||||
t.Errorf("failed to get block root at slot %d: %v", wantedSlot, err)
|
||||
}
|
||||
if !bytes.Equal(result, tt.expectedRoot) {
|
||||
t.Errorf(
|
||||
"result block root was an unexpected value. Wanted %d, got %d",
|
||||
tt.expectedRoot,
|
||||
result,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockRootAtSlot_OutOfBounds(t *testing.T) {
|
||||
if params.BeaconConfig().SlotsPerEpoch != 64 {
|
||||
t.Errorf("slotsPerEpoch should be 64 for these tests to pass")
|
||||
}
|
||||
|
||||
var blockRoots [][]byte
|
||||
|
||||
for i := uint64(0); i < params.BeaconConfig().LatestBlockRootsLength; i++ {
|
||||
blockRoots = append(blockRoots, []byte{byte(i)})
|
||||
}
|
||||
state := &pb.BeaconState{
|
||||
LatestBlockRootHash32S: blockRoots,
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
slot uint64
|
||||
stateSlot uint64
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
slot: params.BeaconConfig().GenesisSlot + 1000,
|
||||
stateSlot: params.BeaconConfig().GenesisSlot + 500,
|
||||
expectedErr: fmt.Sprintf("slot %d is not within expected range of %d to %d",
|
||||
1000,
|
||||
0,
|
||||
500),
|
||||
},
|
||||
{
|
||||
slot: params.BeaconConfig().GenesisSlot + 129,
|
||||
stateSlot: params.BeaconConfig().GenesisSlot + 400,
|
||||
expectedErr: "slot 129 is not within expected range of 272 to 399",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
state.Slot = tt.stateSlot
|
||||
_, err := BlockRoot(state, tt.slot)
|
||||
if err != nil && err.Error() != tt.expectedErr {
|
||||
t.Errorf("Expected error \"%s\" got \"%v\"", tt.expectedErr, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessBlockRoots_AccurateMerkleTree(t *testing.T) {
|
||||
state := &pb.BeaconState{}
|
||||
|
||||
state.LatestBlockRootHash32S = make([][]byte, params.BeaconConfig().LatestBlockRootsLength)
|
||||
state.Slot = params.BeaconConfig().LatestBlockRootsLength + 1
|
||||
|
||||
testRoot := [32]byte{'a'}
|
||||
|
||||
newState := ProcessBlockRoots(state, testRoot)
|
||||
if !bytes.Equal(newState.LatestBlockRootHash32S[0], testRoot[:]) {
|
||||
t.Fatalf("Latest Block root hash not saved."+
|
||||
" Supposed to get %#x , but got %#x", testRoot, newState.LatestBlockRootHash32S[0])
|
||||
}
|
||||
|
||||
newState.Slot = newState.Slot - 1
|
||||
|
||||
newState = ProcessBlockRoots(newState, testRoot)
|
||||
expectedHashes := make([][]byte, params.BeaconConfig().LatestBlockRootsLength)
|
||||
expectedHashes[0] = testRoot[:]
|
||||
expectedHashes[params.BeaconConfig().LatestBlockRootsLength-1] = testRoot[:]
|
||||
|
||||
expectedRoot := hashutil.MerkleRoot(expectedHashes)
|
||||
|
||||
if !bytes.Equal(newState.BatchedBlockRootHash32S[0], expectedRoot[:]) {
|
||||
t.Errorf("saved merkle root is not equal to expected merkle root"+
|
||||
"\n expected %#x but got %#x", expectedRoot, newState.BatchedBlockRootHash32S[0])
|
||||
|
||||
if !proto.Equal(expectedBlock, block) {
|
||||
t.Errorf("Expected block not equal to retrieved block. Expected %v , Got %v",
|
||||
proto.MarshalTextString(expectedBlock), proto.MarshalTextString(block))
|
||||
}
|
||||
}
|
||||
|
||||
115
beacon-chain/core/blocks/eth1_data_test.go
Normal file
115
beacon-chain/core/blocks/eth1_data_test.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package blocks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/cache"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func TestEth1DataHasEnoughSupport(t *testing.T) {
|
||||
tests := []struct {
|
||||
stateVotes []*pb.Eth1Data
|
||||
data *pb.Eth1Data
|
||||
hasSupport bool
|
||||
votingPeriodLength uint64
|
||||
}{
|
||||
{
|
||||
stateVotes: []*pb.Eth1Data{
|
||||
{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
},
|
||||
},
|
||||
data: &pb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
},
|
||||
hasSupport: true,
|
||||
votingPeriodLength: 7,
|
||||
}, {
|
||||
stateVotes: []*pb.Eth1Data{
|
||||
{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
},
|
||||
},
|
||||
data: &pb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
},
|
||||
hasSupport: false,
|
||||
votingPeriodLength: 8,
|
||||
}, {
|
||||
stateVotes: []*pb.Eth1Data{
|
||||
{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
}, {
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
},
|
||||
},
|
||||
data: &pb.Eth1Data{
|
||||
DepositCount: 1,
|
||||
DepositRoot: []byte("root"),
|
||||
},
|
||||
hasSupport: false,
|
||||
votingPeriodLength: 10,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
eth1DataCache = cache.NewEth1DataVoteCache()
|
||||
|
||||
c := params.BeaconConfig()
|
||||
c.SlotsPerEth1VotingPeriod = tt.votingPeriodLength
|
||||
params.OverrideBeaconConfig(c)
|
||||
|
||||
s := &pb.BeaconState{
|
||||
Eth1DataVotes: tt.stateVotes,
|
||||
}
|
||||
result, err := Eth1DataHasEnoughSupport(s, tt.data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if result != tt.hasSupport {
|
||||
t.Errorf(
|
||||
"blocks.Eth1DataHasEnoughSupport(%+v, %+v) = %t, wanted %t",
|
||||
s,
|
||||
tt.data,
|
||||
result,
|
||||
tt.hasSupport,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
48
beacon-chain/core/blocks/spectest/BUILD.bazel
Normal file
48
beacon-chain/core/blocks/spectest/BUILD.bazel
Normal file
@@ -0,0 +1,48 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"attestation_test.yaml.go",
|
||||
"block_operations.yaml.go",
|
||||
"blocks_mainnet.yaml.go",
|
||||
"blocks_minimal.yaml.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks/spectest",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = ["//proto/beacon/p2p/v1:go_default_library"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "medium",
|
||||
srcs = [
|
||||
"attestation_test.go",
|
||||
"attester_slashing_test.go",
|
||||
"block_header_test.go",
|
||||
"block_processing_test.go",
|
||||
"deposit_test.go",
|
||||
"proposer_slashing_test.go",
|
||||
"transfer_test.go",
|
||||
"voluntary_exit_test.go",
|
||||
],
|
||||
data = glob(["*.yaml"]) + [
|
||||
"@eth2_spec_tests//:test_data",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
shard_count = 4,
|
||||
tags = ["spectest"],
|
||||
deps = [
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/state:go_default_library",
|
||||
"//beacon-chain/core/state/stateutils:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params/spectest:go_default_library",
|
||||
"@com_github_ghodss_yaml//:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
|
||||
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
|
||||
],
|
||||
)
|
||||
82
beacon-chain/core/blocks/spectest/attestation_test.go
Normal file
82
beacon-chain/core/blocks/spectest/attestation_test.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
)
|
||||
|
||||
func runAttestationTest(t *testing.T, filename string) {
|
||||
filepath, err := bazel.Runfile("tests/operations/attestation/" + filename)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
file, err := ioutil.ReadFile(filepath)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read file: %v", err)
|
||||
}
|
||||
|
||||
test := &AttestationTest{}
|
||||
if err := yaml.Unmarshal(file, test); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if err := spectest.SetConfig(test.Config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, tt := range test.TestCases {
|
||||
t.Run(tt.Description, func(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
body := &pb.BeaconBlockBody{
|
||||
Attestations: []*pb.Attestation{
|
||||
tt.Attestation,
|
||||
},
|
||||
}
|
||||
|
||||
post, err := blocks.ProcessAttestations(tt.Pre, body, true /*verify sig*/)
|
||||
if !reflect.ValueOf(tt.Post).IsValid() {
|
||||
// Note: This doesn't test anything worthwhile. It essentially tests
|
||||
// that *any* error has occurred, not any specific error.
|
||||
if err == nil {
|
||||
t.Fatal("did not fail when expected")
|
||||
}
|
||||
return
|
||||
}
|
||||
// Note: This doesn't test anything worthwhile. It essentially tests
|
||||
// that *any* error has occurred, not any specific error.
|
||||
if tt.Post == nil {
|
||||
if err == nil {
|
||||
t.Fatal("Did not fail when expected")
|
||||
}
|
||||
t.Logf("Expected failure; failure reason = %v", err)
|
||||
return
|
||||
} else if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !proto.Equal(post, tt.Post) {
|
||||
diff, _ := messagediff.PrettyDiff(post, tt.Post)
|
||||
t.Log(diff)
|
||||
t.Fatal("Post state does not match expected")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationMinimal(t *testing.T) {
|
||||
runAttestationTest(t, "attestation_minimal.yaml")
|
||||
}
|
||||
|
||||
func TestAttestationMainnet(t *testing.T) {
|
||||
runAttestationTest(t, "attestation_mainnet.yaml")
|
||||
}
|
||||
23
beacon-chain/core/blocks/spectest/attestation_test.yaml.go
Normal file
23
beacon-chain/core/blocks/spectest/attestation_test.yaml.go
Normal file
@@ -0,0 +1,23 @@
|
||||
// Code generated by yaml_to_go. DO NOT EDIT.
|
||||
// source: attestation_minimal.yaml
|
||||
|
||||
package spectest
|
||||
|
||||
import pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
|
||||
type AttestationTest struct {
|
||||
Title string `json:"title"`
|
||||
Summary string `json:"summary"`
|
||||
ForksTimeline string `json:"forks_timeline"`
|
||||
Forks []string `json:"forks"`
|
||||
Config string `json:"config"`
|
||||
Runner string `json:"runner"`
|
||||
Handler string `json:"handler"`
|
||||
TestCases []struct {
|
||||
Description string `json:"description"`
|
||||
Pre *pb.BeaconState `json:"pre"`
|
||||
Attestation *pb.Attestation `json:"attestation"`
|
||||
Post *pb.BeaconState `json:"post"`
|
||||
BlsSetting uint64 `json:"bls_setting,omitempty"`
|
||||
} `json:"test_cases"`
|
||||
}
|
||||
76
beacon-chain/core/blocks/spectest/attester_slashing_test.go
Normal file
76
beacon-chain/core/blocks/spectest/attester_slashing_test.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
)
|
||||
|
||||
func runAttesterSlashingTest(t *testing.T, filename string) {
|
||||
file, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not load file %v", err)
|
||||
}
|
||||
|
||||
test := &BlockOperationTest{}
|
||||
if err := yaml.Unmarshal(file, test); err != nil {
|
||||
t.Fatalf("Failed to Unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if err := spectest.SetConfig(test.Config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, tt := range test.TestCases {
|
||||
t.Run(tt.Description, func(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
|
||||
body := &pb.BeaconBlockBody{AttesterSlashings: []*pb.AttesterSlashing{tt.AttesterSlashing}}
|
||||
|
||||
postState, err := blocks.ProcessAttesterSlashings(tt.Pre, body, true)
|
||||
// Note: This doesn't test anything worthwhile. It essentially tests
|
||||
// that *any* error has occurred, not any specific error.
|
||||
if tt.Post == nil {
|
||||
if err == nil {
|
||||
t.Fatal("Did not fail when expected")
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !proto.Equal(postState, tt.Post) {
|
||||
diff, _ := messagediff.PrettyDiff(postState, tt.Post)
|
||||
t.Log(diff)
|
||||
t.Fatal("Post state does not match expected")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var attesterSlashingPrefix = "tests/operations/attester_slashing/"
|
||||
|
||||
func TestAttesterSlashingMinimal(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(attesterSlashingPrefix + "attester_slashing_minimal.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runAttesterSlashingTest(t, filepath)
|
||||
}
|
||||
|
||||
func TestAttesterSlashingMainnet(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(attesterSlashingPrefix + "attester_slashing_mainnet.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runAttesterSlashingTest(t, filepath)
|
||||
}
|
||||
78
beacon-chain/core/blocks/spectest/block_header_test.go
Normal file
78
beacon-chain/core/blocks/spectest/block_header_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
)
|
||||
|
||||
// Block header test is actually a full block processing test. Not sure why it
|
||||
// was named "block_header". The note in the test format readme says "Note that
|
||||
// block_header is not strictly an operation (and is a full Block), but
|
||||
// processed in the same manner, and hence included here."
|
||||
func runBlockHeaderTest(t *testing.T, filename string) {
|
||||
file, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to read file: %v", err)
|
||||
}
|
||||
|
||||
test := &BlockOperationTest{}
|
||||
if err := yaml.Unmarshal(file, test); err != nil {
|
||||
t.Fatalf("Failed to unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if err := spectest.SetConfig(test.Config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, tt := range test.TestCases {
|
||||
t.Run(tt.Description, func(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
|
||||
post, err := blocks.ProcessBlockHeader(tt.Pre, tt.Block, true)
|
||||
|
||||
if tt.Post == nil {
|
||||
// Note: This doesn't test anything worthwhile. It essentially tests
|
||||
// that *any* error has occurred, not any specific error.
|
||||
if err == nil {
|
||||
t.Fatal("did not fail when expected")
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !proto.Equal(post, tt.Post) {
|
||||
diff, _ := messagediff.PrettyDiff(post, tt.Post)
|
||||
t.Log(diff)
|
||||
t.Fatal("Post state does not match expected")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var blkHeaderPrefix = "tests/operations/block_header/"
|
||||
|
||||
func TestBlockHeaderMinimal(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(blkHeaderPrefix + "block_header_minimal.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runBlockHeaderTest(t, filepath)
|
||||
}
|
||||
|
||||
func TestBlockHeaderMainnet(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(blkHeaderPrefix + "block_header_mainnet.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runBlockHeaderTest(t, filepath)
|
||||
}
|
||||
28
beacon-chain/core/blocks/spectest/block_operations.yaml.go
Normal file
28
beacon-chain/core/blocks/spectest/block_operations.yaml.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// Code generated by yaml_to_go. DO NOT EDIT.
|
||||
// source: voluntary_exit_minimal.yaml
|
||||
|
||||
package spectest
|
||||
|
||||
import pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
|
||||
type BlockOperationTest struct {
|
||||
Title string `json:"title"`
|
||||
Summary string `json:"summary"`
|
||||
ForksTimeline string `json:"forks_timeline"`
|
||||
Forks []string `json:"forks"`
|
||||
Config string `json:"config"`
|
||||
Runner string `json:"runner"`
|
||||
Handler string `json:"handler"`
|
||||
TestCases []struct {
|
||||
BlsSetting uint64 `json:"bls_setting,omitempty"`
|
||||
Description string `json:"description"`
|
||||
Pre *pb.BeaconState `json:"pre"`
|
||||
VoluntaryExit *pb.VoluntaryExit `json:"voluntary_exit"`
|
||||
ProposerSlashing *pb.ProposerSlashing `json:"proposer_slashing"`
|
||||
AttesterSlashing *pb.AttesterSlashing `json:"attester_slashing"`
|
||||
Deposit *pb.Deposit `json:"deposit"`
|
||||
Transfer *pb.Transfer `json:"transfer"`
|
||||
Block *pb.BeaconBlock `json:"block"`
|
||||
Post *pb.BeaconState `json:"post"`
|
||||
} `json:"test_cases"`
|
||||
}
|
||||
80
beacon-chain/core/blocks/spectest/block_processing_test.go
Normal file
80
beacon-chain/core/blocks/spectest/block_processing_test.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
)
|
||||
|
||||
func TestBlockProcessingMinimalYaml(t *testing.T) {
|
||||
t.Skip("Test will fail with mainnet protos")
|
||||
|
||||
runBlockProcessingTest(t, "sanity_blocks_minimal.yaml")
|
||||
}
|
||||
|
||||
func TestBlockProcessingMainnetYaml(t *testing.T) {
|
||||
runBlockProcessingTest(t, "sanity_blocks_mainnet.yaml")
|
||||
}
|
||||
|
||||
func runBlockProcessingTest(t *testing.T, filename string) {
|
||||
filepath, err := bazel.Runfile("tests/sanity/blocks/" + filename)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
file, err := ioutil.ReadFile(filepath)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not load file %v", err)
|
||||
}
|
||||
|
||||
s := &BlocksMainnet{}
|
||||
if err := yaml.Unmarshal(file, s); err != nil {
|
||||
t.Fatalf("Failed to Unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if err := spectest.SetConfig(s.Config); err != nil {
|
||||
t.Fatalf("Could not set config: %v", err)
|
||||
}
|
||||
|
||||
for _, tt := range s.TestCases {
|
||||
t.Run(tt.Description, func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
helpers.ClearAllCaches()
|
||||
blocks.ClearEth1DataVoteCache()
|
||||
|
||||
stateConfig := &state.TransitionConfig{
|
||||
VerifySignatures: true,
|
||||
VerifyStateRoot: true,
|
||||
}
|
||||
|
||||
s := tt.Pre
|
||||
for _, b := range tt.Blocks {
|
||||
tt.Pre, err = state.ExecuteStateTransition(ctx, tt.Pre, b, stateConfig)
|
||||
if tt.Post == nil {
|
||||
if err == nil {
|
||||
t.Fatal("Transition did not fail despite being invalid")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("Transition failed with block at slot %d: %v", b.Slot, err)
|
||||
}
|
||||
}
|
||||
if tt.Post != nil {
|
||||
if !proto.Equal(s, tt.Post) {
|
||||
diff, _ := messagediff.PrettyDiff(s, tt.Post)
|
||||
t.Log(diff)
|
||||
t.Fatal("Post state does not match expected")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
22
beacon-chain/core/blocks/spectest/blocks_mainnet.yaml.go
Normal file
22
beacon-chain/core/blocks/spectest/blocks_mainnet.yaml.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// Code generated by yaml_to_go. DO NOT EDIT.
|
||||
// source: sanity_blocks_mainnet.yaml
|
||||
|
||||
package spectest
|
||||
|
||||
import pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
|
||||
type BlocksMainnet struct {
|
||||
Title string `json:"title"`
|
||||
Summary string `json:"summary"`
|
||||
ForksTimeline string `json:"forks_timeline"`
|
||||
Forks []string `json:"forks"`
|
||||
Config string `json:"config"`
|
||||
Runner string `json:"runner"`
|
||||
Handler string `json:"handler"`
|
||||
TestCases []struct {
|
||||
Description string `json:"description"`
|
||||
Pre *pb.BeaconState `json:"pre"`
|
||||
Blocks []*pb.BeaconBlock `json:"blocks"`
|
||||
Post *pb.BeaconState `json:"post"`
|
||||
} `json:"test_cases"`
|
||||
}
|
||||
22
beacon-chain/core/blocks/spectest/blocks_minimal.yaml.go
Normal file
22
beacon-chain/core/blocks/spectest/blocks_minimal.yaml.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// Code generated by yaml_to_go. DO NOT EDIT.
|
||||
// source: sanity_blocks_minimal.yaml
|
||||
|
||||
package spectest
|
||||
|
||||
import pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
|
||||
type BlocksMinimal struct {
|
||||
Title string `json:"title"`
|
||||
Summary string `json:"summary"`
|
||||
ForksTimeline string `json:"forks_timeline"`
|
||||
Forks []string `json:"forks"`
|
||||
Config string `json:"config"`
|
||||
Runner string `json:"runner"`
|
||||
Handler string `json:"handler"`
|
||||
TestCases []struct {
|
||||
Description string `json:"description"`
|
||||
Pre *pb.BeaconState `json:"pre"`
|
||||
Blocks []*pb.BeaconBlock `json:"blocks"`
|
||||
Post *pb.BeaconState `json:"post"`
|
||||
} `json:"test_cases"`
|
||||
}
|
||||
76
beacon-chain/core/blocks/spectest/deposit_test.go
Normal file
76
beacon-chain/core/blocks/spectest/deposit_test.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state/stateutils"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
)
|
||||
|
||||
func runDepositTest(t *testing.T, filename string) {
|
||||
file, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not load file %v", err)
|
||||
}
|
||||
|
||||
test := &BlockOperationTest{}
|
||||
if err := yaml.Unmarshal(file, test); err != nil {
|
||||
t.Fatalf("Failed to Unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if err := spectest.SetConfig(test.Config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, tt := range test.TestCases {
|
||||
helpers.ClearAllCaches()
|
||||
t.Run(tt.Description, func(t *testing.T) {
|
||||
if tt.Description == "invalid_sig_new_deposit" {
|
||||
// TODO(#2857): uncompressed signature format is not supported
|
||||
t.Skip("Uncompressed BLS signature format is not supported")
|
||||
}
|
||||
|
||||
valMap := stateutils.ValidatorIndexMap(tt.Pre)
|
||||
post, err := blocks.ProcessDeposit(tt.Pre, tt.Deposit, valMap, true, true)
|
||||
// Note: This doesn't test anything worthwhile. It essentially tests
|
||||
// that *any* error has occurred, not any specific error.
|
||||
if tt.Post == nil {
|
||||
if err == nil {
|
||||
t.Fatal("Did not fail when expected")
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(post, tt.Post) {
|
||||
t.Error("Post state does not match expected")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var depositPrefix = "tests/operations/deposit/"
|
||||
|
||||
func TestDepositMinimalYaml(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(depositPrefix + "deposit_minimal.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runDepositTest(t, filepath)
|
||||
}
|
||||
|
||||
func TestDepositMainnetYaml(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(depositPrefix + "deposit_mainnet.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runDepositTest(t, filepath)
|
||||
}
|
||||
76
beacon-chain/core/blocks/spectest/proposer_slashing_test.go
Normal file
76
beacon-chain/core/blocks/spectest/proposer_slashing_test.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
)
|
||||
|
||||
func runProposerSlashingTest(t *testing.T, filename string) {
|
||||
file, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not load file %v", err)
|
||||
}
|
||||
|
||||
test := &BlockOperationTest{}
|
||||
if err := yaml.Unmarshal(file, test); err != nil {
|
||||
t.Fatalf("Failed to Unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if err := spectest.SetConfig(test.Config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, tt := range test.TestCases {
|
||||
t.Run(tt.Description, func(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
|
||||
body := &pb.BeaconBlockBody{ProposerSlashings: []*pb.ProposerSlashing{tt.ProposerSlashing}}
|
||||
|
||||
postState, err := blocks.ProcessProposerSlashings(tt.Pre, body, true)
|
||||
// Note: This doesn't test anything worthwhile. It essentially tests
|
||||
// that *any* error has occurred, not any specific error.
|
||||
if tt.Post == nil {
|
||||
if err == nil {
|
||||
t.Fatal("Did not fail when expected")
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !proto.Equal(postState, tt.Post) {
|
||||
diff, _ := messagediff.PrettyDiff(postState, tt.Post)
|
||||
t.Log(diff)
|
||||
t.Fatal("Post state does not match expected")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var proposerSlashingPrefix = "tests/operations/proposer_slashing/"
|
||||
|
||||
func TestProposerSlashingMinimal(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(proposerSlashingPrefix + "proposer_slashing_minimal.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runProposerSlashingTest(t, filepath)
|
||||
}
|
||||
|
||||
func TestProposerSlashingMainnet(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(proposerSlashingPrefix + "proposer_slashing_mainnet.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runProposerSlashingTest(t, filepath)
|
||||
}
|
||||
78
beacon-chain/core/blocks/spectest/transfer_test.go
Normal file
78
beacon-chain/core/blocks/spectest/transfer_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
)
|
||||
|
||||
func runTransferTest(t *testing.T, filename string) {
|
||||
file, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not load file %v", err)
|
||||
}
|
||||
|
||||
test := &BlockOperationTest{}
|
||||
if err := yaml.Unmarshal(file, test); err != nil {
|
||||
t.Fatalf("Failed to Unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if err := spectest.SetConfig(test.Config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, tt := range test.TestCases {
|
||||
t.Run(tt.Description, func(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
|
||||
body := &pb.BeaconBlockBody{Transfers: []*pb.Transfer{tt.Transfer}}
|
||||
|
||||
postState, err := blocks.ProcessTransfers(tt.Pre, body, true)
|
||||
// Note: This doesn't test anything worthwhile. It essentially tests
|
||||
// that *any* error has occurred, not any specific error.
|
||||
if tt.Post == nil {
|
||||
if err == nil {
|
||||
t.Fatal("Did not fail when expected")
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !proto.Equal(postState, tt.Post) {
|
||||
diff, _ := messagediff.PrettyDiff(postState, tt.Post)
|
||||
t.Log(diff)
|
||||
t.Fatal("Post state does not match expected")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var transferPrefix = "tests/operations/transfer/"
|
||||
|
||||
func TestTransferMinimal(t *testing.T) {
|
||||
t.Skip("Transfer tests are disabled. See https://github.com/ethereum/eth2.0-specs/pull/1238#issuecomment-507054595")
|
||||
filepath, err := bazel.Runfile(transferPrefix + "transfer_minimal.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runTransferTest(t, filepath)
|
||||
}
|
||||
|
||||
func TestTransferMainnet(t *testing.T) {
|
||||
t.Skip("Transfer tests are disabled. See https://github.com/ethereum/eth2.0-specs/pull/1238#issuecomment-507054595")
|
||||
filepath, err := bazel.Runfile(transferPrefix + "transfer_mainnet.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runTransferTest(t, filepath)
|
||||
}
|
||||
76
beacon-chain/core/blocks/spectest/voluntary_exit_test.go
Normal file
76
beacon-chain/core/blocks/spectest/voluntary_exit_test.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
)
|
||||
|
||||
func runVoluntaryExitTest(t *testing.T, filename string) {
|
||||
file, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not load file %v", err)
|
||||
}
|
||||
|
||||
test := &BlockOperationTest{}
|
||||
if err := yaml.Unmarshal(file, test); err != nil {
|
||||
t.Fatalf("Failed to Unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if err := spectest.SetConfig(test.Config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, tt := range test.TestCases {
|
||||
t.Run(tt.Description, func(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
|
||||
body := &pb.BeaconBlockBody{VoluntaryExits: []*pb.VoluntaryExit{tt.VoluntaryExit}}
|
||||
|
||||
postState, err := blocks.ProcessVoluntaryExits(tt.Pre, body, true)
|
||||
// Note: This doesn't test anything worthwhile. It essentially tests
|
||||
// that *any* error has occurred, not any specific error.
|
||||
if tt.Post == nil {
|
||||
if err == nil {
|
||||
t.Fatal("Did not fail when expected")
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !proto.Equal(postState, tt.Post) {
|
||||
diff, _ := messagediff.PrettyDiff(postState, tt.Post)
|
||||
t.Log(diff)
|
||||
t.Fatal("Post state does not match expected")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var exitPrefix = "tests/operations/voluntary_exit/"
|
||||
|
||||
func TestVoluntaryExitMinimal(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(exitPrefix + "voluntary_exit_mainnet.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runVoluntaryExitTest(t, filepath)
|
||||
}
|
||||
|
||||
func TestVoluntaryExitMainnet(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(exitPrefix + "voluntary_exit_mainnet.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runVoluntaryExitTest(t, filepath)
|
||||
}
|
||||
@@ -1,6 +1,3 @@
|
||||
// Package blocks contains block processing libraries. These libraries
|
||||
// process and verify block specific messages such as PoW receipt root,
|
||||
// RANDAO, validator deposits, exits and slashing proofs.
|
||||
package blocks
|
||||
|
||||
import (
|
||||
@@ -13,18 +10,9 @@ import (
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "core/blocks")
|
||||
|
||||
// IsValidBlock ensures that the block is compliant with the block processing validity conditions.
|
||||
// Spec:
|
||||
// For a beacon chain block, block, to be processed by a node, the following conditions must be met:
|
||||
// The parent block with root block.parent_root has been processed and accepted.
|
||||
// The node has processed its state up to slot, block.slot - 1.
|
||||
// The Ethereum 1.0 block pointed to by the state.processed_pow_receipt_root has been processed and accepted.
|
||||
// The node's local clock time is greater than or equal to state.genesis_time + block.slot * SECONDS_PER_SLOT.
|
||||
func IsValidBlock(
|
||||
ctx context.Context,
|
||||
state *pb.BeaconState,
|
||||
@@ -35,13 +23,13 @@ func IsValidBlock(
|
||||
|
||||
// Pre-Processing Condition 1:
|
||||
// Check that the parent Block has been processed and saved.
|
||||
parentRoot := bytesutil.ToBytes32(block.ParentRootHash32)
|
||||
parentRoot := bytesutil.ToBytes32(block.ParentRoot)
|
||||
parentBlock := HasBlock(parentRoot)
|
||||
if !parentBlock {
|
||||
return fmt.Errorf("unprocessed parent block as it is not saved in the db: %#x", parentRoot)
|
||||
}
|
||||
|
||||
h := common.BytesToHash(state.LatestEth1Data.BlockHash32)
|
||||
h := common.BytesToHash(state.Eth1Data.BlockHash)
|
||||
powBlock, err := GetPOWBlock(ctx, h)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to retrieve POW chain reference block: %v", err)
|
||||
@@ -51,14 +39,14 @@ func IsValidBlock(
|
||||
// The block pointed to by the state in state.processed_pow_receipt_root has
|
||||
// been processed in the ETH 1.0 chain.
|
||||
if powBlock == nil {
|
||||
return fmt.Errorf("proof-of-Work chain reference in state does not exist: %#x", state.LatestEth1Data.BlockHash32)
|
||||
return fmt.Errorf("proof-of-Work chain reference in state does not exist: %#x", state.Eth1Data.BlockHash)
|
||||
}
|
||||
|
||||
// Pre-Processing Condition 4:
|
||||
// The node's local time is greater than or equal to
|
||||
// state.genesis_time + (block.slot-GENESIS_SLOT)* SECONDS_PER_SLOT.
|
||||
if !IsSlotValid(block.Slot, genesisTime) {
|
||||
return fmt.Errorf("slot of block is too high: %d", block.Slot-params.BeaconConfig().GenesisSlot)
|
||||
return fmt.Errorf("slot of block is too high: %d", block.Slot)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -66,15 +54,10 @@ func IsValidBlock(
|
||||
|
||||
// IsSlotValid compares the slot to the system clock to determine if the block is valid.
|
||||
func IsSlotValid(slot uint64, genesisTime time.Time) bool {
|
||||
secondsPerSlot := time.Duration((slot-params.BeaconConfig().GenesisSlot)*params.BeaconConfig().SecondsPerSlot) * time.Second
|
||||
secondsPerSlot := time.Duration((slot)*params.BeaconConfig().SecondsPerSlot) * time.Second
|
||||
validTimeThreshold := genesisTime.Add(secondsPerSlot)
|
||||
now := clock.Now()
|
||||
isValid := now.After(validTimeThreshold)
|
||||
if !isValid {
|
||||
log.WithFields(logrus.Fields{
|
||||
"localTime": now,
|
||||
"genesisPlusSlotTime": validTimeThreshold,
|
||||
}).Info("Waiting for slot to be valid")
|
||||
}
|
||||
|
||||
return isValid
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
gethTypes "github.com/ethereum/go-ethereum/core/types"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@@ -43,10 +42,10 @@ func TestIsValidBlock_NoParent(t *testing.T) {
|
||||
db := &mockDB{}
|
||||
powClient := &mockPOWClient{}
|
||||
|
||||
beaconState.Slot = params.BeaconConfig().GenesisSlot + 3
|
||||
beaconState.Slot = 3
|
||||
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 4,
|
||||
Slot: 4,
|
||||
}
|
||||
|
||||
genesisTime := time.Unix(0, 0)
|
||||
@@ -67,20 +66,20 @@ func TestIsValidBlock_InvalidSlot(t *testing.T) {
|
||||
db := &mockDB{}
|
||||
powClient := &mockPOWClient{}
|
||||
|
||||
beaconState.Slot = params.BeaconConfig().GenesisSlot + 3
|
||||
beaconState.Slot = 3
|
||||
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 4,
|
||||
Slot: 4,
|
||||
}
|
||||
|
||||
genesisTime := time.Unix(0, 0)
|
||||
|
||||
block.Slot = params.BeaconConfig().GenesisSlot + 3
|
||||
block.Slot = 3
|
||||
db.hasBlock = true
|
||||
|
||||
beaconState.LatestEth1Data = &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{2},
|
||||
BlockHash32: []byte{3},
|
||||
beaconState.Eth1Data = &pb.Eth1Data{
|
||||
DepositRoot: []byte{2},
|
||||
BlockHash: []byte{3},
|
||||
}
|
||||
if err := IsValidBlock(ctx, beaconState, block,
|
||||
db.HasBlock, powClient.BlockByHash, genesisTime); err == nil {
|
||||
@@ -96,20 +95,20 @@ func TestIsValidBlock_InvalidPoWReference(t *testing.T) {
|
||||
db := &mockDB{}
|
||||
powClient := &mockPOWClient{}
|
||||
|
||||
beaconState.Slot = params.BeaconConfig().GenesisSlot + 3
|
||||
beaconState.Slot = 3
|
||||
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 4,
|
||||
Slot: 4,
|
||||
}
|
||||
|
||||
genesisTime := time.Unix(0, 0)
|
||||
|
||||
db.hasBlock = true
|
||||
block.Slot = params.BeaconConfig().GenesisSlot + 4
|
||||
block.Slot = 4
|
||||
powClient.blockExists = false
|
||||
beaconState.LatestEth1Data = &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{2},
|
||||
BlockHash32: []byte{3},
|
||||
beaconState.Eth1Data = &pb.Eth1Data{
|
||||
DepositRoot: []byte{2},
|
||||
BlockHash: []byte{3},
|
||||
}
|
||||
|
||||
if err := IsValidBlock(ctx, beaconState, block,
|
||||
@@ -129,15 +128,15 @@ func TestIsValidBlock_InvalidGenesis(t *testing.T) {
|
||||
powClient := &mockPOWClient{}
|
||||
powClient.blockExists = false
|
||||
|
||||
beaconState.Slot = params.BeaconConfig().GenesisSlot + 3
|
||||
beaconState.LatestEth1Data = &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{2},
|
||||
BlockHash32: []byte{3},
|
||||
beaconState.Slot = 3
|
||||
beaconState.Eth1Data = &pb.Eth1Data{
|
||||
DepositRoot: []byte{2},
|
||||
BlockHash: []byte{3},
|
||||
}
|
||||
|
||||
genesisTime := time.Unix(0, 0)
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 4,
|
||||
Slot: 4,
|
||||
}
|
||||
|
||||
invalidTime := time.Now().AddDate(1, 2, 3)
|
||||
@@ -159,16 +158,16 @@ func TestIsValidBlock_GoodBlock(t *testing.T) {
|
||||
powClient := &mockPOWClient{}
|
||||
powClient.blockExists = true
|
||||
|
||||
beaconState.Slot = params.BeaconConfig().GenesisSlot + 3
|
||||
beaconState.LatestEth1Data = &pb.Eth1Data{
|
||||
DepositRootHash32: []byte{2},
|
||||
BlockHash32: []byte{3},
|
||||
beaconState.Slot = 3
|
||||
beaconState.Eth1Data = &pb.Eth1Data{
|
||||
DepositRoot: []byte{2},
|
||||
BlockHash: []byte{3},
|
||||
}
|
||||
|
||||
genesisTime := time.Unix(0, 0)
|
||||
|
||||
block := &pb.BeaconBlock{
|
||||
Slot: params.BeaconConfig().GenesisSlot + 4,
|
||||
Slot: 4,
|
||||
}
|
||||
|
||||
if err := IsValidBlock(ctx, beaconState, block,
|
||||
|
||||
@@ -2,42 +2,31 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"epoch_operations.go",
|
||||
"epoch_processing.go",
|
||||
],
|
||||
srcs = ["epoch_processing.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/blocks:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/mathutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus:go_default_library",
|
||||
"@com_github_prometheus_client_golang//prometheus/promauto:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"epoch_operations_test.go",
|
||||
"epoch_processing_test.go",
|
||||
],
|
||||
srcs = ["epoch_processing_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
// Package epoch contains epoch processing libraries. These libraries
|
||||
// process new balance for the validators, justify and finalize new
|
||||
// check points, shuffle and reassign validators to different slots and
|
||||
// shards.
|
||||
package epoch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/validators"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
b "github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
)
|
||||
|
||||
// TotalBalance returns the total balance at stake of the validators
|
||||
// from the shard committee regardless of validators attested or not.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def get_total_balance(state: BeaconState, validators: List[ValidatorIndex]) -> Gwei:
|
||||
// """
|
||||
// Return the combined effective balance of an array of validators.
|
||||
// """
|
||||
// return sum([get_effective_balance(state, i) for i in validators])
|
||||
func TotalBalance(
|
||||
state *pb.BeaconState,
|
||||
activeValidatorIndices []uint64) uint64 {
|
||||
|
||||
var totalBalance uint64
|
||||
for _, index := range activeValidatorIndices {
|
||||
totalBalance += helpers.EffectiveBalance(state, index)
|
||||
}
|
||||
|
||||
return totalBalance
|
||||
}
|
||||
|
||||
// InclusionSlot returns the slot number of when the validator's
|
||||
// attestation gets included in the beacon chain.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Let inclusion_slot(state, index) =
|
||||
// a.slot_included for the attestation a where index is in
|
||||
// get_attestation_participants(state, a.data, a.participation_bitfield)
|
||||
// If multiple attestations are applicable, the attestation with
|
||||
// lowest `slot_included` is considered.
|
||||
func InclusionSlot(state *pb.BeaconState, validatorIndex uint64) (uint64, error) {
|
||||
lowestSlotIncluded := uint64(math.MaxUint64)
|
||||
for _, attestation := range state.LatestAttestations {
|
||||
participatedValidators, err := helpers.AttestationParticipants(state, attestation.Data, attestation.AggregationBitfield)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("could not get attestation participants: %v", err)
|
||||
}
|
||||
for _, index := range participatedValidators {
|
||||
if index == validatorIndex {
|
||||
if attestation.InclusionSlot < lowestSlotIncluded {
|
||||
lowestSlotIncluded = attestation.InclusionSlot
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if lowestSlotIncluded == math.MaxUint64 {
|
||||
return 0, fmt.Errorf("could not find inclusion slot for validator index %d", validatorIndex)
|
||||
}
|
||||
return lowestSlotIncluded, nil
|
||||
}
|
||||
|
||||
// AttestingValidators returns the validators of the winning root.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Let `attesting_validators(crosslink_committee)` be equal to
|
||||
// `attesting_validator_indices(crosslink_committee, winning_root(crosslink_committee))` for convenience
|
||||
func AttestingValidators(
|
||||
state *pb.BeaconState,
|
||||
shard uint64,
|
||||
currentEpochAttestations []*pb.PendingAttestation,
|
||||
prevEpochAttestations []*pb.PendingAttestation) ([]uint64, error) {
|
||||
|
||||
root, err := winningRoot(
|
||||
state,
|
||||
shard,
|
||||
currentEpochAttestations,
|
||||
prevEpochAttestations)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get winning root: %v", err)
|
||||
}
|
||||
|
||||
indices, err := validators.AttestingValidatorIndices(
|
||||
state,
|
||||
shard,
|
||||
root,
|
||||
currentEpochAttestations,
|
||||
prevEpochAttestations)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get attesting validator indices: %v", err)
|
||||
}
|
||||
|
||||
return indices, nil
|
||||
}
|
||||
|
||||
// TotalAttestingBalance returns the total balance at stake of the validators
|
||||
// attested to the winning root.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Let total_balance(crosslink_committee) =
|
||||
// sum([get_effective_balance(state, i) for i in crosslink_committee.committee])
|
||||
func TotalAttestingBalance(
|
||||
state *pb.BeaconState,
|
||||
shard uint64,
|
||||
currentEpochAttestations []*pb.PendingAttestation,
|
||||
prevEpochAttestations []*pb.PendingAttestation) (uint64, error) {
|
||||
|
||||
var totalBalance uint64
|
||||
attestedValidatorIndices, err := AttestingValidators(state, shard, currentEpochAttestations, prevEpochAttestations)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("could not get attesting validator indices: %v", err)
|
||||
}
|
||||
|
||||
for _, index := range attestedValidatorIndices {
|
||||
totalBalance += helpers.EffectiveBalance(state, index)
|
||||
}
|
||||
|
||||
return totalBalance, nil
|
||||
}
|
||||
|
||||
// SinceFinality calculates and returns how many epoch has it been since
|
||||
// a finalized slot.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// epochs_since_finality = next_epoch - state.finalized_epoch
|
||||
func SinceFinality(state *pb.BeaconState) uint64 {
|
||||
return helpers.NextEpoch(state) - state.FinalizedEpoch
|
||||
}
|
||||
|
||||
// winningRoot returns the shard block root with the most combined validator
|
||||
// effective balance. The ties broken by favoring lower shard block root values.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Let winning_root(crosslink_committee) be equal to the value of crosslink_data_root
|
||||
// such that get_total_balance(state, attesting_validator_indices(crosslink_committee, crosslink_data_root))
|
||||
// is maximized (ties broken by favoring lexicographically smallest crosslink_data_root).
|
||||
func winningRoot(
|
||||
state *pb.BeaconState,
|
||||
shard uint64,
|
||||
currentEpochAttestations []*pb.PendingAttestation,
|
||||
prevEpochAttestations []*pb.PendingAttestation) ([]byte, error) {
|
||||
|
||||
var winnerBalance uint64
|
||||
var winnerRoot []byte
|
||||
var candidateRoots [][]byte
|
||||
attestations := append(currentEpochAttestations, prevEpochAttestations...)
|
||||
|
||||
for _, attestation := range attestations {
|
||||
if attestation.Data.Shard == shard {
|
||||
candidateRoots = append(candidateRoots, attestation.Data.CrosslinkDataRootHash32)
|
||||
}
|
||||
}
|
||||
|
||||
for _, candidateRoot := range candidateRoots {
|
||||
indices, err := validators.AttestingValidatorIndices(
|
||||
state,
|
||||
shard,
|
||||
candidateRoot,
|
||||
currentEpochAttestations,
|
||||
prevEpochAttestations)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get attesting validator indices: %v", err)
|
||||
}
|
||||
|
||||
var rootBalance uint64
|
||||
for _, index := range indices {
|
||||
rootBalance += helpers.EffectiveBalance(state, index)
|
||||
}
|
||||
|
||||
if rootBalance > winnerBalance ||
|
||||
(rootBalance == winnerBalance && b.LowerThan(candidateRoot, winnerRoot)) {
|
||||
winnerBalance = rootBalance
|
||||
winnerRoot = candidateRoot
|
||||
}
|
||||
}
|
||||
return winnerRoot, nil
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
package epoch
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
func buildState(slot uint64, validatorCount uint64) *pb.BeaconState {
|
||||
validators := make([]*pb.Validator, validatorCount)
|
||||
for i := 0; i < len(validators); i++ {
|
||||
validators[i] = &pb.Validator{
|
||||
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
||||
}
|
||||
}
|
||||
validatorBalances := make([]uint64, len(validators))
|
||||
for i := 0; i < len(validatorBalances); i++ {
|
||||
validatorBalances[i] = params.BeaconConfig().MaxDepositAmount
|
||||
}
|
||||
return &pb.BeaconState{
|
||||
ValidatorRegistry: validators,
|
||||
ValidatorBalances: validatorBalances,
|
||||
Slot: slot,
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinningRoot_AccurateRoot(t *testing.T) {
|
||||
state := buildState(params.BeaconConfig().GenesisSlot, 100)
|
||||
var participationBitfield []byte
|
||||
participationBitfield = append(participationBitfield, byte(0x80))
|
||||
|
||||
// Generate 10 roots ([]byte{100}...[]byte{110})
|
||||
var attestations []*pb.PendingAttestation
|
||||
for i := 0; i < 10; i++ {
|
||||
attestation := &pb.PendingAttestation{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: params.BeaconConfig().GenesisSlot,
|
||||
CrosslinkDataRootHash32: []byte{byte(i + 100)},
|
||||
},
|
||||
AggregationBitfield: participationBitfield,
|
||||
}
|
||||
attestations = append(attestations, attestation)
|
||||
}
|
||||
|
||||
// Since all 10 roots have the balance of 64 ETHs
|
||||
// winningRoot chooses the lowest hash: []byte{100}
|
||||
winnerRoot, err := winningRoot(
|
||||
state,
|
||||
0,
|
||||
attestations,
|
||||
nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not execute winningRoot: %v", err)
|
||||
}
|
||||
if !bytes.Equal(winnerRoot, []byte{100}) {
|
||||
t.Errorf("Incorrect winner root, wanted:[100], got: %v", winnerRoot)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWinningRoot_EmptyParticipantBitfield(t *testing.T) {
|
||||
state := buildState(params.BeaconConfig().GenesisSlot, params.BeaconConfig().DepositsForChainStart)
|
||||
|
||||
attestations := []*pb.PendingAttestation{
|
||||
{Data: &pb.AttestationData{
|
||||
Slot: params.BeaconConfig().GenesisSlot,
|
||||
CrosslinkDataRootHash32: []byte{},
|
||||
},
|
||||
AggregationBitfield: []byte{},
|
||||
},
|
||||
}
|
||||
|
||||
helpers.RestartCommitteeCache()
|
||||
|
||||
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 16, 0)
|
||||
if _, err := winningRoot(state, 0, attestations, nil); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestingValidators_MatchActive(t *testing.T) {
|
||||
state := buildState(params.BeaconConfig().GenesisSlot, params.BeaconConfig().SlotsPerEpoch*2)
|
||||
|
||||
var attestations []*pb.PendingAttestation
|
||||
for i := 0; i < 10; i++ {
|
||||
attestation := &pb.PendingAttestation{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: params.BeaconConfig().GenesisSlot,
|
||||
CrosslinkDataRootHash32: []byte{byte(i + 100)},
|
||||
},
|
||||
AggregationBitfield: []byte{0xC0},
|
||||
}
|
||||
attestations = append(attestations, attestation)
|
||||
}
|
||||
|
||||
helpers.RestartCommitteeCache()
|
||||
|
||||
attestedValidators, err := AttestingValidators(
|
||||
state,
|
||||
0,
|
||||
attestations,
|
||||
nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not execute AttestingValidators: %v", err)
|
||||
}
|
||||
|
||||
// Verify the winner root is attested by validators based on shuffling.
|
||||
if !reflect.DeepEqual(attestedValidators, []uint64{123, 65}) {
|
||||
t.Errorf("Active validators don't match. Wanted:[123,65], Got: %v", attestedValidators)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestingValidators_EmptyWinningRoot(t *testing.T) {
|
||||
state := buildState(params.BeaconConfig().GenesisSlot, params.BeaconConfig().DepositsForChainStart)
|
||||
|
||||
attestation := &pb.PendingAttestation{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: params.BeaconConfig().GenesisSlot,
|
||||
CrosslinkDataRootHash32: []byte{},
|
||||
},
|
||||
AggregationBitfield: []byte{},
|
||||
}
|
||||
|
||||
helpers.RestartCommitteeCache()
|
||||
|
||||
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 16, 0)
|
||||
if _, err := AttestingValidators(state, 0, []*pb.PendingAttestation{attestation}, nil); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalAttestingBalance_CorrectBalance(t *testing.T) {
|
||||
validatorsPerCommittee := uint64(2)
|
||||
state := buildState(params.BeaconConfig().GenesisSlot, 2*params.BeaconConfig().SlotsPerEpoch)
|
||||
|
||||
// Generate 10 roots ([]byte{100}...[]byte{110})
|
||||
var attestations []*pb.PendingAttestation
|
||||
for i := 0; i < 10; i++ {
|
||||
attestation := &pb.PendingAttestation{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: params.BeaconConfig().GenesisSlot,
|
||||
CrosslinkDataRootHash32: []byte{byte(i + 100)},
|
||||
},
|
||||
// All validators attested to the above roots.
|
||||
AggregationBitfield: []byte{0xC0},
|
||||
}
|
||||
attestations = append(attestations, attestation)
|
||||
}
|
||||
|
||||
helpers.RestartCommitteeCache()
|
||||
|
||||
attestedBalance, err := TotalAttestingBalance(
|
||||
state,
|
||||
0,
|
||||
attestations,
|
||||
nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not execute totalAttestingBalance: %v", err)
|
||||
}
|
||||
|
||||
if attestedBalance != params.BeaconConfig().MaxDepositAmount*validatorsPerCommittee {
|
||||
t.Errorf("Incorrect attested balance. Wanted:64*1e9, Got: %d", attestedBalance)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalAttestingBalance_EmptyWinningRoot(t *testing.T) {
|
||||
state := buildState(params.BeaconConfig().GenesisSlot, params.BeaconConfig().DepositsForChainStart)
|
||||
|
||||
attestation := &pb.PendingAttestation{
|
||||
Data: &pb.AttestationData{
|
||||
Slot: params.BeaconConfig().GenesisSlot,
|
||||
CrosslinkDataRootHash32: []byte{},
|
||||
},
|
||||
AggregationBitfield: []byte{},
|
||||
}
|
||||
|
||||
helpers.RestartCommitteeCache()
|
||||
|
||||
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 16, 0)
|
||||
if _, err := TotalAttestingBalance(state, 0, []*pb.PendingAttestation{attestation}, nil); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalBalance_CorrectBalance(t *testing.T) {
|
||||
// Assign validators to different balances.
|
||||
state := &pb.BeaconState{
|
||||
Slot: 5,
|
||||
ValidatorBalances: []uint64{20 * 1e9, 25 * 1e9, 30 * 1e9, 30 * 1e9,
|
||||
32 * 1e9, 34 * 1e9, 50 * 1e9, 50 * 1e9},
|
||||
}
|
||||
|
||||
// 20 + 25 + 30 + 30 + 32 + 32 + 32 + 32 = 233
|
||||
totalBalance := TotalBalance(state, []uint64{0, 1, 2, 3, 4, 5, 6, 7})
|
||||
if totalBalance != 233*1e9 {
|
||||
t.Errorf("Incorrect total balance. Wanted: 233*1e9, got: %d", totalBalance)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInclusionSlot_GetsCorrectSlot(t *testing.T) {
|
||||
state := buildState(params.BeaconConfig().GenesisSlot, params.BeaconConfig().DepositsForChainStart)
|
||||
var participationBitfield []byte
|
||||
for i := 0; i < 16; i++ {
|
||||
participationBitfield = append(participationBitfield, byte(0xff))
|
||||
}
|
||||
|
||||
state.LatestAttestations = []*pb.PendingAttestation{
|
||||
{Data: &pb.AttestationData{Slot: params.BeaconConfig().GenesisSlot},
|
||||
AggregationBitfield: participationBitfield,
|
||||
InclusionSlot: 101},
|
||||
{Data: &pb.AttestationData{Slot: params.BeaconConfig().GenesisSlot},
|
||||
AggregationBitfield: participationBitfield,
|
||||
InclusionSlot: 100},
|
||||
{Data: &pb.AttestationData{Slot: params.BeaconConfig().GenesisSlot},
|
||||
AggregationBitfield: participationBitfield,
|
||||
InclusionSlot: 102},
|
||||
}
|
||||
slot, err := InclusionSlot(state, 251)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not execute InclusionSlot: %v", err)
|
||||
}
|
||||
// validator 45's attestation got included in slot 100.
|
||||
if slot != 100 {
|
||||
t.Errorf("Incorrect slot. Wanted: 100, got: %d", slot)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInclusionSlot_InvalidBitfield(t *testing.T) {
|
||||
state := buildState(params.BeaconConfig().GenesisSlot, params.BeaconConfig().DepositsForChainStart)
|
||||
|
||||
state.LatestAttestations = []*pb.PendingAttestation{
|
||||
{Data: &pb.AttestationData{Slot: params.BeaconConfig().GenesisSlot},
|
||||
AggregationBitfield: []byte{},
|
||||
InclusionSlot: 100},
|
||||
}
|
||||
|
||||
want := fmt.Sprintf("wanted participants bitfield length %d, got: %d", 16, 0)
|
||||
if _, err := InclusionSlot(state, 0); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInclusionSlot_SlotNotFound(t *testing.T) {
|
||||
state := buildState(params.BeaconConfig().GenesisSlot, params.BeaconConfig().SlotsPerEpoch)
|
||||
|
||||
badIndex := uint64(10000)
|
||||
want := fmt.Sprintf("could not find inclusion slot for validator index %d", badIndex)
|
||||
if _, err := InclusionSlot(state, badIndex); !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("Expected %s, received %v", want, err)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
39
beacon-chain/core/epoch/spectest/BUILD.bazel
Normal file
39
beacon-chain/core/epoch/spectest/BUILD.bazel
Normal file
@@ -0,0 +1,39 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["epoch_processing_test.yaml.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/epoch/spectest",
|
||||
visibility = ["//beacon-chain:__subpackages__"],
|
||||
deps = ["//proto/beacon/p2p/v1:go_default_library"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
size = "medium",
|
||||
srcs = [
|
||||
"crosslink_test.go",
|
||||
"final_updates_test.go",
|
||||
"justification_and_finalization_test.go",
|
||||
"registry_test.go",
|
||||
"slashings_test.go",
|
||||
],
|
||||
data = [
|
||||
"@eth2_spec_tests//:test_data",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
tags = [
|
||||
"spectest",
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/core/epoch:go_default_library",
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/params/spectest:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"@com_github_ghodss_yaml//:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@in_gopkg_d4l3k_messagediff_v1//:go_default_library",
|
||||
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
|
||||
],
|
||||
)
|
||||
62
beacon-chain/core/epoch/spectest/crosslink_test.go
Normal file
62
beacon-chain/core/epoch/spectest/crosslink_test.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
)
|
||||
|
||||
func runCrosslinkProcessingTests(t *testing.T, filename string) {
|
||||
file, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not load file %v", err)
|
||||
}
|
||||
|
||||
s := &EpochProcessingTest{}
|
||||
if err := yaml.Unmarshal(file, s); err != nil {
|
||||
t.Fatalf("Failed to Unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if err := spectest.SetConfig(s.Config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, tt := range s.TestCases {
|
||||
t.Run(tt.Description, func(t *testing.T) {
|
||||
|
||||
postState, err := epoch.ProcessCrosslinks(tt.Pre)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(postState, tt.Post) {
|
||||
t.Error("Did not get expected state")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const crosslinkPrefix = "tests/epoch_processing/crosslinks/"
|
||||
|
||||
func TestCrosslinksProcessingMinimal(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(crosslinkPrefix + "crosslinks_minimal.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runCrosslinkProcessingTests(t, filepath)
|
||||
}
|
||||
|
||||
func TestCrosslinksProcessingMainnet(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
filepath, err := bazel.Runfile(crosslinkPrefix + "crosslinks_mainnet.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runCrosslinkProcessingTests(t, filepath)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Code generated by yaml_to_go. DO NOT EDIT.
|
||||
package spectest
|
||||
|
||||
import pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
|
||||
type EpochProcessingTest struct {
|
||||
Title string `json:"title"`
|
||||
Summary string `json:"summary"`
|
||||
ForksTimeline string `json:"forks_timeline"`
|
||||
Forks []string `json:"forks"`
|
||||
Config string `json:"config"`
|
||||
Runner string `json:"runner"`
|
||||
Handler string `json:"handler"`
|
||||
TestCases []struct {
|
||||
Description string `json:"description"`
|
||||
Pre *pb.BeaconState `json:"pre"`
|
||||
Post *pb.BeaconState `json:"post"`
|
||||
} `json:"test_cases"`
|
||||
}
|
||||
81
beacon-chain/core/epoch/spectest/final_updates_test.go
Normal file
81
beacon-chain/core/epoch/spectest/final_updates_test.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
)
|
||||
|
||||
func runFinalUpdatesTests(t *testing.T, filename string) {
|
||||
file, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not load file %v", err)
|
||||
}
|
||||
|
||||
s := &EpochProcessingTest{}
|
||||
if err := yaml.Unmarshal(file, s); err != nil {
|
||||
t.Fatalf("Failed to Unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if err := spectest.SetConfig(s.Config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, tt := range s.TestCases[0:1] {
|
||||
t.Run(tt.Description, func(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
preState := &pb.BeaconState{}
|
||||
if err := testutil.ConvertToPb(tt.Pre, preState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var postState *pb.BeaconState
|
||||
postState, err = epoch.ProcessFinalUpdates(preState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedPostState := &pb.BeaconState{}
|
||||
if err := testutil.ConvertToPb(tt.Post, expectedPostState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expectedPostState.CurrentEpochAttestations == nil {
|
||||
expectedPostState.CurrentEpochAttestations = []*pb.PendingAttestation{}
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(postState, expectedPostState) {
|
||||
t.Error("Did not get expected state")
|
||||
diff, _ := messagediff.PrettyDiff(expectedPostState, postState)
|
||||
t.Log(diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const finalUpdatesPrefix = "tests/epoch_processing/final_updates/"
|
||||
|
||||
func TestFinalUpdatesMinimal(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(finalUpdatesPrefix + "final_updates_minimal.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runFinalUpdatesTests(t, filepath)
|
||||
}
|
||||
|
||||
func TestFinalUpdatesMainnet(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(finalUpdatesPrefix + "final_updates_mainnet.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runFinalUpdatesTests(t, filepath)
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
"gopkg.in/d4l3k/messagediff.v1"
|
||||
)
|
||||
|
||||
// This is a subset of state.ProcessEpoch. The spec test defines input data for
|
||||
// `justification_and_finalization` only.
|
||||
func processJustificationAndFinalizationWrapper(state *pb.BeaconState) (*pb.BeaconState, error) {
|
||||
helpers.ClearAllCaches()
|
||||
|
||||
// This process mutates the state, so we'll make a copy in order to print debug before/after.
|
||||
state = proto.Clone(state).(*pb.BeaconState)
|
||||
|
||||
prevEpochAtts, err := epoch.MatchAttestations(state, helpers.PrevEpoch(state))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get target atts prev epoch %d: %v",
|
||||
helpers.PrevEpoch(state), err)
|
||||
}
|
||||
currentEpochAtts, err := epoch.MatchAttestations(state, helpers.CurrentEpoch(state))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get target atts current epoch %d: %v",
|
||||
helpers.CurrentEpoch(state), err)
|
||||
}
|
||||
prevEpochAttestedBalance, err := epoch.AttestingBalance(state, prevEpochAtts.Target)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get attesting balance prev epoch: %v", err)
|
||||
}
|
||||
currentEpochAttestedBalance, err := epoch.AttestingBalance(state, currentEpochAtts.Target)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not get attesting balance current epoch: %v", err)
|
||||
}
|
||||
|
||||
state, err = epoch.ProcessJustificationAndFinalization(state, prevEpochAttestedBalance, currentEpochAttestedBalance)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not process justification: %v", err)
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func runJustificationAndFinalizationTests(t *testing.T, filename string) {
|
||||
file, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not load file %v", err)
|
||||
}
|
||||
|
||||
s := &EpochProcessingTest{}
|
||||
if err := yaml.Unmarshal(file, s); err != nil {
|
||||
t.Fatalf("Failed to Unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if err := spectest.SetConfig(s.Config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, tt := range s.TestCases {
|
||||
t.Run(tt.Description, func(t *testing.T) {
|
||||
preState := &pb.BeaconState{}
|
||||
if err := testutil.ConvertToPb(tt.Pre, preState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
postState, err := processJustificationAndFinalizationWrapper(preState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedPostState := &pb.BeaconState{}
|
||||
if err := testutil.ConvertToPb(tt.Post, expectedPostState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if postState.JustificationBits[0] != expectedPostState.JustificationBits[0] {
|
||||
t.Errorf("Justification bits mismatch. PreState.JustificationBits=%v. PostState.JustificationBits=%v. Expected=%v", preState.JustificationBits, postState.JustificationBits, expectedPostState.JustificationBits)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(postState, expectedPostState) {
|
||||
diff, _ := messagediff.PrettyDiff(postState, expectedPostState)
|
||||
t.Log(diff)
|
||||
t.Error("Did not get expected state")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const justificationAndFinalizationPrefix = "tests/epoch_processing/justification_and_finalization/"
|
||||
|
||||
func TestJustificationAndFinalizationMinimal(t *testing.T) {
|
||||
// TODO(#2891): Verify with ETH2 spec test.
|
||||
t.Skip("The input data fails preconditions for matching attestations in the state for the current epoch.")
|
||||
filepath, err := bazel.Runfile(justificationAndFinalizationPrefix + "justification_and_finalization_minimal.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runJustificationAndFinalizationTests(t, filepath)
|
||||
}
|
||||
|
||||
func TestJustificationAndFinalizationMainnet(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(justificationAndFinalizationPrefix + "justification_and_finalization_mainnet.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runJustificationAndFinalizationTests(t, filepath)
|
||||
}
|
||||
59
beacon-chain/core/epoch/spectest/registry_test.go
Normal file
59
beacon-chain/core/epoch/spectest/registry_test.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
)
|
||||
|
||||
func runRegisteryProcessingTests(t *testing.T, filename string) {
|
||||
file, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not load file %v", err)
|
||||
}
|
||||
|
||||
s := &EpochProcessingTest{}
|
||||
if err := yaml.Unmarshal(file, s); err != nil {
|
||||
t.Fatalf("Failed to Unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if err := spectest.SetConfig(s.Config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, tt := range s.TestCases {
|
||||
t.Run(tt.Description, func(t *testing.T) {
|
||||
postState, err := epoch.ProcessRegistryUpdates(tt.Pre)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(postState, tt.Post) {
|
||||
t.Error("Did not get expected state")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const registryUpdatesPrefix = "tests/epoch_processing/registry_updates/"
|
||||
|
||||
func TestRegistryProcessingMinimal(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(registryUpdatesPrefix + "registry_updates_minimal.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runRegisteryProcessingTests(t, filepath)
|
||||
}
|
||||
|
||||
func TestRegistryProcessingMainnet(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(registryUpdatesPrefix + "registry_updates_mainnet.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runRegisteryProcessingTests(t, filepath)
|
||||
}
|
||||
61
beacon-chain/core/epoch/spectest/slashings_test.go
Normal file
61
beacon-chain/core/epoch/spectest/slashings_test.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package spectest
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/epoch"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/shared/params/spectest"
|
||||
)
|
||||
|
||||
func runSlashingsTests(t *testing.T, filename string) {
|
||||
file, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not load file %v", err)
|
||||
}
|
||||
|
||||
s := &EpochProcessingTest{}
|
||||
if err := yaml.Unmarshal(file, s); err != nil {
|
||||
t.Fatalf("Failed to Unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if err := spectest.SetConfig(s.Config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, tt := range s.TestCases {
|
||||
t.Run(tt.Description, func(t *testing.T) {
|
||||
helpers.ClearAllCaches()
|
||||
postState, err := epoch.ProcessSlashings(tt.Pre)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(postState, tt.Post) {
|
||||
t.Error("Did not get expected state")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const slashingsPrefix = "tests/epoch_processing/slashings/"
|
||||
|
||||
func TestSlashingsMinimal(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(slashingsPrefix + "slashings_minimal.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runSlashingsTests(t, filepath)
|
||||
}
|
||||
|
||||
func TestSlashingsMainnet(t *testing.T) {
|
||||
filepath, err := bazel.Runfile(slashingsPrefix + "slashings_mainnet.yaml")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
runSlashingsTests(t, filepath)
|
||||
}
|
||||
@@ -3,8 +3,11 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"attestation.go",
|
||||
"block.go",
|
||||
"cache.go",
|
||||
"committee.go",
|
||||
"deposits.go",
|
||||
"eth1data.go",
|
||||
"randao.go",
|
||||
"rewards_penalties.go",
|
||||
"slot_epoch.go",
|
||||
@@ -16,11 +19,11 @@ go_library(
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/utils:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/bitutil:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/hashutil:go_default_library",
|
||||
"//shared/mathutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@org_golang_google_grpc//codes:go_default_library",
|
||||
"@org_golang_google_grpc//status:go_default_library",
|
||||
@@ -31,8 +34,10 @@ go_test(
|
||||
name = "go_default_test",
|
||||
size = "small",
|
||||
srcs = [
|
||||
"attestation_test.go",
|
||||
"block_test.go",
|
||||
"committee_test.go",
|
||||
"deposits_test.go",
|
||||
"eth1data_test.go",
|
||||
"randao_test.go",
|
||||
"rewards_penalties_test.go",
|
||||
"slot_epoch_test.go",
|
||||
@@ -40,11 +45,13 @@ go_test(
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/cache:go_default_library",
|
||||
"//beacon-chain/internal:go_default_library",
|
||||
"//beacon-chain/utils:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@org_golang_google_grpc//codes:go_default_library",
|
||||
"@org_golang_google_grpc//status:go_default_library",
|
||||
],
|
||||
|
||||
51
beacon-chain/core/helpers/attestation.go
Normal file
51
beacon-chain/core/helpers/attestation.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrAttestationDataSlotNilState is returned when a nil state argument
|
||||
// is provided to AttestationDataSlot.
|
||||
ErrAttestationDataSlotNilState = errors.New("nil state provided for AttestationDataSlot")
|
||||
// ErrAttestationDataSlotNilData is returned when a nil attestation data
|
||||
// argument is provided to AttestationDataSlot.
|
||||
ErrAttestationDataSlotNilData = errors.New("nil data provided for AttestationDataSlot")
|
||||
)
|
||||
|
||||
// AttestationDataSlot returns current slot of AttestationData for given state
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// def get_attestation_data_slot(state: BeaconState, data: AttestationData) -> Slot:
|
||||
// """
|
||||
// Return the slot corresponding to the attestation ``data``.
|
||||
// """
|
||||
// committee_count = get_committee_count(state, data.target.epoch)
|
||||
// offset = (data.crosslink.shard + SHARD_COUNT - get_start_shard(state, data.target.epoch)) % SHARD_COUNT
|
||||
// return Slot(compute_start_slot_of_epoch(data.target.epoch) + offset // (committee_count // SLOTS_PER_EPOCH))
|
||||
func AttestationDataSlot(state *pb.BeaconState, data *pb.AttestationData) (uint64, error) {
|
||||
if state == nil {
|
||||
return 0, ErrAttestationDataSlotNilState
|
||||
}
|
||||
if data == nil {
|
||||
return 0, ErrAttestationDataSlotNilData
|
||||
}
|
||||
|
||||
committeeCount, err := CommitteeCount(state, data.Target.Epoch)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
epochStartShardNumber, err := StartShard(state, data.Target.Epoch)
|
||||
if err != nil { // This should never happen if CommitteeCount was successful
|
||||
return 0, fmt.Errorf("could not determine epoch start shard: %v", err)
|
||||
}
|
||||
offset := (data.Crosslink.Shard + params.BeaconConfig().ShardCount -
|
||||
epochStartShardNumber) % params.BeaconConfig().ShardCount
|
||||
|
||||
return StartSlot(data.Target.Epoch) + (offset / (committeeCount / params.BeaconConfig().SlotsPerEpoch)), nil
|
||||
}
|
||||
101
beacon-chain/core/helpers/attestation_test.go
Normal file
101
beacon-chain/core/helpers/attestation_test.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package helpers_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/internal"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
)
|
||||
|
||||
func TestAttestationDataSlot_OK(t *testing.T) {
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
deposits, _ := testutil.SetupInitialDeposits(t, 100, false)
|
||||
if err := db.InitializeState(context.Background(), uint64(0), deposits, nil); err != nil {
|
||||
t.Fatalf("Could not initialize beacon state to disk: %v", err)
|
||||
}
|
||||
beaconState, err := db.HeadState(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
offset := uint64(0)
|
||||
committeeCount, _ := helpers.CommitteeCount(beaconState, 0)
|
||||
expect := offset / (committeeCount / params.BeaconConfig().SlotsPerEpoch)
|
||||
attSlot, err := helpers.AttestationDataSlot(beaconState, &pb.AttestationData{
|
||||
Target: &pb.Checkpoint{Epoch: 0},
|
||||
Crosslink: &pb.Crosslink{
|
||||
Shard: 0,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if attSlot != expect {
|
||||
t.Errorf("Expected %d, received %d", expect, attSlot)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationDataSlot_ReturnsErrorWithNilState(t *testing.T) {
|
||||
s, err := helpers.AttestationDataSlot(nil /*state*/, &pb.AttestationData{
|
||||
Target: &pb.Checkpoint{Epoch: 0},
|
||||
Crosslink: &pb.Crosslink{
|
||||
Shard: 0,
|
||||
},
|
||||
})
|
||||
if err != helpers.ErrAttestationDataSlotNilState {
|
||||
t.Errorf("Expected an error, but received %v", err)
|
||||
t.Logf("attestation slot=%v", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationDataSlot_ReturnsErrorWithNilData(t *testing.T) {
|
||||
s, err := helpers.AttestationDataSlot(&pb.BeaconState{}, nil /*data*/)
|
||||
if err != helpers.ErrAttestationDataSlotNilData {
|
||||
t.Errorf("Expected an error, but received %v", err)
|
||||
t.Logf("attestation slot=%v", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationDataSlot_ReturnsErrorWithErroneousTargetEpoch(t *testing.T) {
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
deposits, _ := testutil.SetupInitialDeposits(t, 100, false)
|
||||
if err := db.InitializeState(context.Background(), uint64(0), deposits, nil); err != nil {
|
||||
t.Fatalf("Could not initialize beacon state to disk: %v", err)
|
||||
}
|
||||
beaconState, err := db.HeadState(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s, err := helpers.AttestationDataSlot(beaconState, &pb.AttestationData{
|
||||
Target: &pb.Checkpoint{Epoch: 1<<63 - 1 /* Far future epoch */},
|
||||
})
|
||||
if err == nil {
|
||||
t.Error("Expected an error, but received nil")
|
||||
t.Logf("attestation slot=%v", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAttestationDataSlot_ReturnsErrorWhenTargetEpochLessThanCurrentEpoch(t *testing.T) {
|
||||
db := internal.SetupDB(t)
|
||||
defer internal.TeardownDB(t, db)
|
||||
deposits, _ := testutil.SetupInitialDeposits(t, 100, false)
|
||||
if err := db.InitializeState(context.Background(), uint64(0), deposits, nil); err != nil {
|
||||
t.Fatalf("Could not initialize beacon state to disk: %v", err)
|
||||
}
|
||||
beaconState, err := db.HeadState(context.Background())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s, err := helpers.AttestationDataSlot(beaconState, &pb.AttestationData{
|
||||
Target: &pb.Checkpoint{Epoch: 2},
|
||||
})
|
||||
if err == nil {
|
||||
t.Error("Expected an error, but received nil")
|
||||
t.Logf("attestation slot=%v", s)
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user