mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-25 04:47:18 +00:00
Create Benchmarks Package for State Transition (#3688)
* Begin benchmarks file for block processing * Complete block processing benchmarks * Begin epoch benchmarks * Write most of epoch benchmarks * Start config * Make cases for max conditions * Begin work on benchmarking doc * Update benchmark numbers * Complete epoch benchmarks * Minor changes * Make createFullBlock function * Clean up block benchmarks * Begin fixing merge issues * Start adding 4M benchmarks * Almost finish epoch benchmarks * Test blocks under real life conditions * More progress on benchmarks * Fixes * Fix benchmark errors * Begin fixing benchmarks * More progress on tests * Complete epoch benchmarks * More progress on block benches * Finish epoch benchmarks, get progress on block benchmarks * Undo unneeded changes * Fix * Fix block benchmarks * Complete block benchmarks * Finish block benchmarks * Complete benchmarks * Increase block benchmarks to 65536 * Fix everything * Reset configs after benchmarks * Fix logging and suggestions * Fix comments * Fix benchmarks after merge * Fix merge issues * Add sanity tests for benchmark * Make sanity check simpler * Begin fixing after merge * Add log * Remove extra line * Remove unneeded change * Finally get block benchmarks to pass * Begin fixing epoch test * Finetuning constants * Revert "Finetuning constants" This reverts commit a872790d675154e1ce213285e76fb6e08ef21d79. * Finetuning * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Add benches for helper functions * Abstract block generation to testutil * Create block generation util in testutil * Gazelle * Fix deps * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into block-util * Fix imports * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into block-util * Merge branch 'master' into block-util * Change tests to use config and fix integer division * Merge branch 'block-util' of https://github.com/0xKiwi/prysm into block-util * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into block-util * Remove logs * Fix build * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Merge branch 'master' into block-util * Add test to ensure finalization occurs * Add check for finalization * Merge branch 'block-util' of https://github.com/0xKiwi/prysm into block-util * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into block-util * Add comment for incrementing the state * Fix test * Fix test * Merge branch 'master' into block-util * Fix testutil use * Fix tests * Change var name * Merge branch 'master' into block-util * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Merge branch 'block-util' of https://github.com/0xKiwi/prysm into new-benchmarks * Begin cleaning benchmarks * Get some numbers going * Use state saved to disk * Remove cruft * Cleanup * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Fix merge arrows * Set up block util and benchmarks for 128 attestations * Use intended config for benchmark * Add more benchmark functions * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Add benchmark epoch and modify block gen config to exclude signing * Cleanup * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Begin unstaleling * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Update block gen util to v0.9 changes * Prepare benchmarks to use marshalled files * Cleanup block gen tool some more * split up into file generation and benchmarking * Remove logrus * Merge branch 'master' into new-benchmarks * Get benchmarks work, start work on process epoch benchmark * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Merge branch 'new-benchmarks' of https://github.com/0xKiwi/prysm into new-benchmarks * All benchmarks working * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Fix after merge * Cleanup * Add bazel target * Added TestBenchmarkExecuteStateTransition_WithCache * Change tests to use SSZ and begin making binary * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Merge branch 'new-benchmarks' of https://github.com/0xKiwi/prysm into new-benchmarks * bazel binary * Fully change to binary * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Create go_binary to handle benchmark files * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Gofmt * Remove genesis state from generated files * Fix tests * Gazelle * Fix tests * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Fix block util * Allow attestations to be in future for block util * Fix inclusion delay issue * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Finally fix test * Add README detailing usage and results * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Change test to run with bazel test * Fix imports * Merge branch 'master' into new-benchmarks * Accidentally removed config change * Merge branch 'new-benchmarks' of https://github.com/0xKiwi/prysm into new-benchmarks * Merge branch 'master' of https://github.com/prysmaticlabs/prysm into new-benchmarks * Move to core/state/ * Update readme * Gazelle * Remove test for cached block
This commit is contained in:
parent
b88e6dc918
commit
c1c48a8af5
28
beacon-chain/core/state/benchmarks/BUILD.bazel
Normal file
28
beacon-chain/core/state/benchmarks/BUILD.bazel
Normal file
@ -0,0 +1,28 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["benchmarks_test.go"],
|
||||
data = ["//beacon-chain/core/state/benchmarks/benchmark_files:benchmark_data"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/state:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//proto/eth/v1alpha1:go_default_library",
|
||||
"//shared/featureconfig:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
"@io_bazel_rules_go//go/tools/bazel:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
testonly = True,
|
||||
srcs = ["config.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/state/benchmarks",
|
||||
visibility = ["//beacon-chain/core/state/benchmarks:__subpackages__"],
|
||||
deps = ["//shared/params:go_default_library"],
|
||||
)
|
25
beacon-chain/core/state/benchmarks/README.md
Normal file
25
beacon-chain/core/state/benchmarks/README.md
Normal file
@ -0,0 +1,25 @@
|
||||
# Benchmarks for Prysm State Transition
|
||||
This package contains the functionality needed for benchmarking Prysms state transitions, this includes its block processing (with and without caching) and epoch processing functions. There is also a benchmark for HashTreeRoot on a large beacon state.
|
||||
|
||||
## Benchmark Configuration
|
||||
The following configs are in `config.go`:
|
||||
* `ValidatorCount`: Sets the amount of active validators to perform the benchmarks with. Default is 65536.
|
||||
* `AttestationsPerEpoch`: Sets the amount of attestations per epoch for the benchmarks to perform with, this affects the amount of attestations in a full block and the amount of attestations per epoch in the state for the `ProcessEpoch` and `HashTreeRoot` benchmark. Default is 128.
|
||||
|
||||
## Generating new SSZ files
|
||||
Due to the sheer size of the benchmarking configurations (65536 validators), the files used for benchmarking are pregenerated so there's no wasted computations on generating a genesis state with 65536 validators. This should only be needed if there is a breaking spec change and the tests fail from SSZ issues.
|
||||
|
||||
To generate new files to use for benchmarking, run the below command in the root of Prysm.
|
||||
```
|
||||
go run beacon-chain/core/state/benchmarks/benchmark_files/generate_bench_files.go
|
||||
```
|
||||
|
||||
Bazel does not allow writing to the project directory, so running with `go run` is needed.
|
||||
|
||||
## Current Results as of November 2019
|
||||
```
|
||||
BenchmarkExecuteStateTransition-4 25 35901941409 ns/op 7465058127 B/op 111046635 allocs/op
|
||||
BenchmarkExecuteStateTransition_WithCache-4 25 24352836461 ns/op 716078697 B/op 22348530 allocs/op
|
||||
BenchmarkProcessEpoch_2FullEpochs-4 5 177559078808 ns/op 12754314974 B/op 176571470 allocs/op
|
||||
BenchmarkHashTreeRoot_FullState-4 50 1321382095 ns/op 253959577 B/op 9645648 allocs/op
|
||||
```
|
@ -0,0 +1,36 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
testonly = True,
|
||||
srcs = ["generate_bench_files.go"],
|
||||
data = glob(["*.ssz"]),
|
||||
importpath = "github.com/prysmaticlabs/prysm/beacon-chain/core/state/benchmarks/benchmark_files",
|
||||
visibility = ["//beacon-chain/core/state/benchmarks:__subpackages__"],
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/state:go_default_library",
|
||||
"//beacon-chain/core/state/benchmarks:go_default_library",
|
||||
"//proto/beacon/p2p/v1:go_default_library",
|
||||
"//proto/eth/v1alpha1:go_default_library",
|
||||
"//shared/interop:go_default_library",
|
||||
"//shared/params:go_default_library",
|
||||
"//shared/testutil:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "benchmark_data",
|
||||
srcs = glob([
|
||||
"*.ssz",
|
||||
]),
|
||||
visibility = ["//beacon-chain/core/state/benchmarks:__subpackages__"],
|
||||
)
|
||||
|
||||
go_binary(
|
||||
name = "benchmark_files",
|
||||
testonly = True,
|
||||
embed = [":go_default_library"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,186 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
bench "github.com/prysmaticlabs/prysm/beacon-chain/core/state/benchmarks"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/interop"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/testutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Println("Generating genesis state")
|
||||
// Generating this for the 2 following states.
|
||||
if err := generateGenesisBeaconState(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println("Generating full block and state after 1 skipped epoch")
|
||||
if err := generateMarshalledFullStateAndBlock(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println("Generating state after 2 fully attested epochs")
|
||||
if err := generate2FullEpochState(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Removing this since its 10MB large and no longer needed.
|
||||
if err := os.Remove(bench.FilePath(bench.GenesisFileName)); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func generateGenesisBeaconState() error {
|
||||
genesisState, _, err := interop.GenerateGenesisState(0, bench.ValidatorCount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
beaconBytes, err := ssz.Marshal(genesisState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(bench.FilePath(bench.GenesisFileName), beaconBytes, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateMarshalledFullStateAndBlock() error {
|
||||
t := &testing.T{}
|
||||
bench.SetConfig()
|
||||
beaconState, err := genesisBeaconState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
privs, _, err := interop.DeterministicallyGenerateKeys(0, bench.ValidatorCount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conf := &testutil.BlockGenConfig{
|
||||
MaxAttestations: 0,
|
||||
Signatures: true,
|
||||
}
|
||||
|
||||
// Small offset for the beacon state so we dont process a block on an epoch.
|
||||
slotOffset := uint64(2)
|
||||
block := testutil.GenerateFullBlock(t, beaconState, privs, conf, params.BeaconConfig().SlotsPerEpoch+slotOffset)
|
||||
beaconState, err = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
attConfig := &testutil.BlockGenConfig{
|
||||
MaxAttestations: bench.AttestationsPerEpoch / params.BeaconConfig().SlotsPerEpoch,
|
||||
Signatures: true,
|
||||
}
|
||||
|
||||
atts := []*ethpb.Attestation{}
|
||||
for i := slotOffset + 1; i < params.BeaconConfig().SlotsPerEpoch+slotOffset; i++ {
|
||||
attsForSlot := testutil.GenerateAttestations(t, beaconState, privs, attConfig, i)
|
||||
atts = append(atts, attsForSlot...)
|
||||
}
|
||||
|
||||
block = testutil.GenerateFullBlock(t, beaconState, privs, attConfig, beaconState.Slot)
|
||||
block.Body.Attestations = append(atts, block.Body.Attestations...)
|
||||
|
||||
s, err := state.CalculateStateRoot(context.Background(), beaconState, block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
block.StateRoot = s[:]
|
||||
blockRoot, err := ssz.SigningRoot(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Temporarily incrementing the beacon state slot here since BeaconProposerIndex is a
|
||||
// function deterministic on beacon state slot.
|
||||
beaconState.Slot++
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(beaconState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
domain := helpers.Domain(beaconState.Fork, helpers.CurrentEpoch(beaconState), params.BeaconConfig().DomainBeaconProposer)
|
||||
block.Signature = privs[proposerIdx].Sign(blockRoot[:], domain).Marshal()
|
||||
beaconState.Slot--
|
||||
|
||||
beaconBytes, err := ssz.Marshal(beaconState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(bench.FilePath(bench.BState1EpochFileName), beaconBytes, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Running a single state transition to make sure the generated files aren't broken.
|
||||
_, err = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
blockBytes, err := ssz.Marshal(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(bench.FilePath(bench.FullBlockFileName), blockBytes, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func generate2FullEpochState() error {
|
||||
t := &testing.T{}
|
||||
bench.SetConfig()
|
||||
beaconState, err := genesisBeaconState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
privs, _, err := interop.DeterministicallyGenerateKeys(0, bench.ValidatorCount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
attConfig := &testutil.BlockGenConfig{
|
||||
MaxAttestations: bench.AttestationsPerEpoch / params.BeaconConfig().SlotsPerEpoch,
|
||||
Signatures: true,
|
||||
}
|
||||
|
||||
for i := uint64(0); i < params.BeaconConfig().SlotsPerEpoch*2-1; i++ {
|
||||
block := testutil.GenerateFullBlock(t, beaconState, privs, attConfig, beaconState.Slot)
|
||||
beaconState, err = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
beaconBytes, err := ssz.Marshal(beaconState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(bench.FilePath(bench.BState2EpochFileName), beaconBytes, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func genesisBeaconState() (*pb.BeaconState, error) {
|
||||
beaconBytes, err := ioutil.ReadFile(bench.FilePath(bench.GenesisFileName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
genesisState := &pb.BeaconState{}
|
||||
if err := ssz.Unmarshal(beaconBytes, genesisState); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return genesisState, nil
|
||||
}
|
193
beacon-chain/core/state/benchmarks/benchmarks_test.go
Normal file
193
beacon-chain/core/state/benchmarks/benchmarks_test.go
Normal file
@ -0,0 +1,193 @@
|
||||
package benchmarks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/state"
|
||||
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
var runAmount = 25
|
||||
|
||||
func TestBenchmarkExecuteStateTransition(t *testing.T) {
|
||||
SetConfig()
|
||||
beaconState, err := beaconState1Epoch()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block, err := fullBlock()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := state.ExecuteStateTransition(context.Background(), beaconState, block); err != nil {
|
||||
t.Fatalf("failed to process block, benchmarks will fail: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBenchmarkProcessEpoch(t *testing.T) {
|
||||
SetConfig()
|
||||
beaconState, err := beaconState2FullEpochs()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := state.ProcessEpoch(context.Background(), beaconState); err != nil {
|
||||
t.Fatalf("failed to process block, benchmarks will fail: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkExecuteStateTransition(b *testing.B) {
|
||||
SetConfig()
|
||||
beaconState, err := beaconState1Epoch()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
cleanStates := clonedStates(beaconState)
|
||||
block, err := fullBlock()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
b.N = runAmount
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := state.ExecuteStateTransition(context.Background(), cleanStates[i], block); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkExecuteStateTransition_WithCache(b *testing.B) {
|
||||
config := &featureconfig.Flags{
|
||||
EnableNewCache: true,
|
||||
EnableShuffledIndexCache: true,
|
||||
EnableBLSPubkeyCache: true,
|
||||
}
|
||||
featureconfig.Init(config)
|
||||
SetConfig()
|
||||
|
||||
beaconState, err := beaconState1Epoch()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
cleanStates := clonedStates(beaconState)
|
||||
block, err := fullBlock()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
// We have to reset slot back to last epoch to hydrate cache. Since
|
||||
// some attestations in block are from previous epoch
|
||||
currentSlot := beaconState.Slot
|
||||
beaconState.Slot -= params.BeaconConfig().SlotsPerEpoch
|
||||
if err := helpers.UpdateCommitteeCache(beaconState); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
beaconState.Slot = currentSlot
|
||||
b.N = runAmount
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := state.ExecuteStateTransition(context.Background(), cleanStates[i], block); err != nil {
|
||||
b.Fatalf("failed to process block, benchmarks will fail: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkProcessEpoch_2FullEpochs(b *testing.B) {
|
||||
SetConfig()
|
||||
beaconState, err := beaconState2FullEpochs()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
cleanStates := clonedStates(beaconState)
|
||||
|
||||
b.N = 5
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := state.ProcessEpoch(context.Background(), cleanStates[i]); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHashTreeRoot_FullState(b *testing.B) {
|
||||
beaconState, err := beaconState2FullEpochs()
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
b.N = 50
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, err := ssz.HashTreeRoot(beaconState); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func clonedStates(beaconState *pb.BeaconState) []*pb.BeaconState {
|
||||
clonedStates := make([]*pb.BeaconState, runAmount)
|
||||
for i := 0; i < runAmount; i++ {
|
||||
clonedStates[i] = proto.Clone(beaconState).(*pb.BeaconState)
|
||||
}
|
||||
return clonedStates
|
||||
}
|
||||
|
||||
func beaconState1Epoch() (*pb.BeaconState, error) {
|
||||
path, err := bazel.Runfile(BState1EpochFileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
beaconBytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
beaconState := &pb.BeaconState{}
|
||||
if err := ssz.Unmarshal(beaconBytes, beaconState); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
func beaconState2FullEpochs() (*pb.BeaconState, error) {
|
||||
path, err := bazel.Runfile(BState2EpochFileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
beaconBytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
beaconState := &pb.BeaconState{}
|
||||
if err := ssz.Unmarshal(beaconBytes, beaconState); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconState, nil
|
||||
}
|
||||
|
||||
func fullBlock() (*ethpb.BeaconBlock, error) {
|
||||
path, err := bazel.Runfile(FullBlockFileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockBytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
beaconBlock := ðpb.BeaconBlock{}
|
||||
if err := ssz.Unmarshal(blockBytes, beaconBlock); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return beaconBlock, nil
|
||||
}
|
48
beacon-chain/core/state/benchmarks/config.go
Normal file
48
beacon-chain/core/state/benchmarks/config.go
Normal file
@ -0,0 +1,48 @@
|
||||
package benchmarks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
)
|
||||
|
||||
// ValidatorCount is for declaring how many validators the benchmarks will be
|
||||
// performed with. Default is 65536 or 2M ETH staked.
|
||||
var ValidatorCount = uint64(65536)
|
||||
|
||||
// AttestationsPerEpoch represents the requested amount attestations in an epoch.
|
||||
// This affects the amount of attestations in a fully attested for block and the amount
|
||||
// of attestations in the state per epoch, so a full 2 epochs should result in twice
|
||||
// this amount of attestations in the state. Default is 128.
|
||||
var AttestationsPerEpoch = uint64(128)
|
||||
|
||||
// GenesisFileName is the generated genesis beacon state file name.
|
||||
var GenesisFileName = fmt.Sprintf("benchmark_files/bStateGenesis-%dAtts-%dVals.ssz", AttestationsPerEpoch, ValidatorCount)
|
||||
|
||||
// BState1EpochFileName is the generated beacon state after 1 skipped epoch file name.
|
||||
var BState1EpochFileName = fmt.Sprintf("benchmark_files/bState1Epoch-%dAtts-%dVals.ssz", AttestationsPerEpoch, ValidatorCount)
|
||||
|
||||
// BState2EpochFileName is the generated beacon state after 2 full epochs file name.
|
||||
var BState2EpochFileName = fmt.Sprintf("benchmark_files/bState2Epochs-%dAtts-%dVals.ssz", AttestationsPerEpoch, ValidatorCount)
|
||||
|
||||
// FullBlockFileName is the generated full block file name.
|
||||
var FullBlockFileName = fmt.Sprintf("benchmark_files/fullBlock-%dAtts-%dVals.ssz", AttestationsPerEpoch, ValidatorCount)
|
||||
|
||||
// FilePath prefixes the file path to the file names.
|
||||
func FilePath(fileName string) string {
|
||||
return fmt.Sprintf("beacon-chain/core/state/benchmarks/%s", fileName)
|
||||
}
|
||||
|
||||
// SetConfig changes the beacon config to match the requested amount of
|
||||
// attestations set to AttestationsPerEpoch.
|
||||
func SetConfig() {
|
||||
maxAtts := AttestationsPerEpoch
|
||||
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
|
||||
committeeSize := (ValidatorCount / slotsPerEpoch) / (maxAtts / slotsPerEpoch)
|
||||
c := params.BeaconConfig()
|
||||
c.PersistentCommitteePeriod = 0
|
||||
c.MinValidatorWithdrawabilityDelay = 0
|
||||
c.TargetCommitteeSize = committeeSize
|
||||
c.MaxAttestations = maxAtts
|
||||
params.OverrideBeaconConfig(c)
|
||||
}
|
@ -2,6 +2,8 @@ package testutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
@ -24,6 +26,7 @@ type BlockGenConfig struct {
|
||||
MaxAttestations uint64
|
||||
MaxDeposits uint64
|
||||
MaxVoluntaryExits uint64
|
||||
Signatures bool
|
||||
}
|
||||
|
||||
// DefaultBlockGenConfig returns the block config that utilizes the
|
||||
@ -35,6 +38,7 @@ func DefaultBlockGenConfig() *BlockGenConfig {
|
||||
MaxAttestations: params.BeaconConfig().MaxAttestations,
|
||||
MaxDeposits: params.BeaconConfig().MaxDeposits,
|
||||
MaxVoluntaryExits: params.BeaconConfig().MaxVoluntaryExits,
|
||||
Signatures: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +51,6 @@ func GenerateFullBlock(
|
||||
conf *BlockGenConfig,
|
||||
slot uint64,
|
||||
) *ethpb.BeaconBlock {
|
||||
|
||||
currentSlot := bState.Slot
|
||||
if currentSlot > slot {
|
||||
t.Fatalf("Current slot in state is larger than given slot. %d > %d", currentSlot, slot)
|
||||
@ -65,7 +68,7 @@ func GenerateFullBlock(
|
||||
|
||||
atts := []*ethpb.Attestation{}
|
||||
if conf.MaxAttestations > 0 {
|
||||
atts = generateAttestations(t, bState, privs, conf.MaxAttestations)
|
||||
atts = GenerateAttestations(t, bState, privs, conf, slot)
|
||||
}
|
||||
|
||||
newDeposits, eth1Data := []*ethpb.Deposit{}, bState.Eth1Data
|
||||
@ -89,14 +92,21 @@ func GenerateFullBlock(
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Temporarily incrementing the beacon state slot here since BeaconProposerIndex is a
|
||||
// function deterministic on beacon state slot.
|
||||
bState.Slot = slot
|
||||
reveal, err := CreateRandaoReveal(bState, helpers.CurrentEpoch(bState), privs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
if slot == currentSlot {
|
||||
slot = currentSlot + 1
|
||||
}
|
||||
|
||||
reveal := []byte{1, 2, 3, 4}
|
||||
if conf.Signatures {
|
||||
// Temporarily incrementing the beacon state slot here since BeaconProposerIndex is a
|
||||
// function deterministic on beacon state slot.
|
||||
bState.Slot = slot
|
||||
reveal, err = CreateRandaoReveal(bState, helpers.CurrentEpoch(bState), privs)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bState.Slot = currentSlot
|
||||
}
|
||||
bState.Slot = currentSlot
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
Slot: slot,
|
||||
@ -116,25 +126,24 @@ func GenerateFullBlock(
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root, err := ssz.HashTreeRoot(s)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
block.StateRoot = s[:]
|
||||
|
||||
if conf.Signatures {
|
||||
blockRoot, err := ssz.SigningRoot(block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Temporarily incrementing the beacon state slot here since BeaconProposerIndex is a
|
||||
// function deterministic on beacon state slot.
|
||||
bState.Slot = slot
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(bState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
domain := helpers.Domain(bState.Fork, helpers.CurrentEpoch(bState), params.BeaconConfig().DomainBeaconProposer)
|
||||
block.Signature = privs[proposerIdx].Sign(blockRoot[:], domain).Marshal()
|
||||
bState.Slot = currentSlot
|
||||
}
|
||||
block.StateRoot = root[:]
|
||||
blockRoot, err := ssz.SigningRoot(block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Temporarily incrementing the beacon state slot here since BeaconProposerIndex is a
|
||||
// function deterministic on beacon state slot.
|
||||
bState.Slot = slot
|
||||
proposerIdx, err := helpers.BeaconProposerIndex(bState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bState.Slot = currentSlot
|
||||
domain := helpers.Domain(bState.Fork, helpers.CurrentEpoch(bState), params.BeaconConfig().DomainBeaconProposer)
|
||||
block.Signature = privs[proposerIdx].Sign(blockRoot[:], domain).Marshal()
|
||||
|
||||
return block
|
||||
}
|
||||
@ -143,21 +152,18 @@ func generateProposerSlashings(
|
||||
t testing.TB,
|
||||
bState *pb.BeaconState,
|
||||
privs []*bls.SecretKey,
|
||||
maxSlashings uint64,
|
||||
numSlashings uint64,
|
||||
) []*ethpb.ProposerSlashing {
|
||||
currentSlot := bState.Slot
|
||||
currentEpoch := helpers.CurrentEpoch(bState)
|
||||
slotsPerEpoch := params.BeaconConfig().SlotsPerEpoch
|
||||
|
||||
validatorCount, err := helpers.ActiveValidatorCount(bState, currentEpoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
proposerSlashings := make([]*ethpb.ProposerSlashing, maxSlashings)
|
||||
for i := uint64(0); i < maxSlashings; i++ {
|
||||
proposerIndex := i + uint64(validatorCount/4)
|
||||
proposerSlashings := make([]*ethpb.ProposerSlashing, numSlashings)
|
||||
for i := uint64(0); i < numSlashings; i++ {
|
||||
proposerIndex, err := randValIndex(bState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
header1 := ðpb.BeaconBlockHeader{
|
||||
Slot: currentSlot - (i % slotsPerEpoch),
|
||||
Slot: bState.Slot,
|
||||
BodyRoot: []byte{0, 1, 0},
|
||||
}
|
||||
root, err := ssz.SigningRoot(header1)
|
||||
@ -168,7 +174,7 @@ func generateProposerSlashings(
|
||||
header1.Signature = privs[proposerIndex].Sign(root[:], domain).Marshal()
|
||||
|
||||
header2 := ðpb.BeaconBlockHeader{
|
||||
Slot: currentSlot - (i % slotsPerEpoch),
|
||||
Slot: bState.Slot,
|
||||
BodyRoot: []byte{0, 2, 0},
|
||||
}
|
||||
root, err = ssz.SigningRoot(header2)
|
||||
@ -191,31 +197,35 @@ func generateAttesterSlashings(
|
||||
t testing.TB,
|
||||
bState *pb.BeaconState,
|
||||
privs []*bls.SecretKey,
|
||||
maxSlashings uint64,
|
||||
numSlashings uint64,
|
||||
) []*ethpb.AttesterSlashing {
|
||||
attesterSlashings := make([]*ethpb.AttesterSlashing, maxSlashings)
|
||||
for i := uint64(0); i < maxSlashings; i++ {
|
||||
committee, err := helpers.BeaconCommittee(bState, i, i%params.BeaconConfig().MaxCommitteesPerSlot)
|
||||
currentEpoch := helpers.CurrentEpoch(bState)
|
||||
attesterSlashings := make([]*ethpb.AttesterSlashing, numSlashings)
|
||||
for i := uint64(0); i < numSlashings; i++ {
|
||||
committeeIndex := rand.Uint64() % params.BeaconConfig().MaxCommitteesPerSlot
|
||||
committee, err := helpers.BeaconCommittee(bState, bState.Slot, committeeIndex)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
committeeSize := uint64(len(committee))
|
||||
attData1 := ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: i,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: i + 1,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
}
|
||||
randIndex := rand.Uint64() % uint64(len(committee))
|
||||
valIndex := committee[randIndex]
|
||||
|
||||
aggregationBits := bitfield.NewBitlist(committeeSize)
|
||||
aggregationBits.SetBitAt(i, true)
|
||||
custodyBits := bitfield.NewBitlist(committeeSize)
|
||||
aggregationBits.SetBitAt(randIndex, true)
|
||||
att1 := ðpb.Attestation{
|
||||
Data: attData1,
|
||||
CustodyBits: custodyBits,
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: bState.Slot,
|
||||
Index: committeeIndex,
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: currentEpoch,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: currentEpoch + 1,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
},
|
||||
AggregationBits: aggregationBits,
|
||||
}
|
||||
dataRoot, err := ssz.HashTreeRoot(&pb.AttestationDataAndCustodyBit{
|
||||
@ -226,22 +236,22 @@ func generateAttesterSlashings(
|
||||
t.Fatal(err)
|
||||
}
|
||||
domain := helpers.Domain(bState.Fork, i, params.BeaconConfig().DomainBeaconAttester)
|
||||
sig := privs[committee[i]].Sign(dataRoot[:], domain)
|
||||
sig := privs[valIndex].Sign(dataRoot[:], domain)
|
||||
att1.Signature = bls.AggregateSignatures([]*bls.Signature{sig}).Marshal()
|
||||
|
||||
attData2 := ðpb.AttestationData{
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: i,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: i,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
}
|
||||
att2 := ðpb.Attestation{
|
||||
Data: attData2,
|
||||
CustodyBits: custodyBits,
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: bState.Slot,
|
||||
Index: committeeIndex,
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: currentEpoch,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: currentEpoch,
|
||||
Root: params.BeaconConfig().ZeroHash[:],
|
||||
},
|
||||
},
|
||||
AggregationBits: aggregationBits,
|
||||
}
|
||||
dataRoot, err = ssz.HashTreeRoot(&pb.AttestationDataAndCustodyBit{
|
||||
@ -251,7 +261,7 @@ func generateAttesterSlashings(
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sig = privs[committee[i]].Sign(dataRoot[:], domain)
|
||||
sig = privs[valIndex].Sign(dataRoot[:], domain)
|
||||
att2.Signature = bls.AggregateSignatures([]*bls.Signature{sig}).Marshal()
|
||||
|
||||
indexedAtt1, err := blocks.ConvertToIndexed(context.Background(), bState, att1)
|
||||
@ -271,95 +281,129 @@ func generateAttesterSlashings(
|
||||
return attesterSlashings
|
||||
}
|
||||
|
||||
// generateAttestations creates attestations that are entirely valid, for the current state slot.
|
||||
// This function always returns all validators participating, if maxAttestations is 1, then it will
|
||||
// return 1 attestation with all validators aggregated into it. If maxAttestations is set to 4, then
|
||||
// it will return 4 attestations for the same data with their aggregation bits split uniformly.
|
||||
func generateAttestations(
|
||||
// GenerateAttestations creates attestations that are entirely valid, for all
|
||||
// the committees of the current state slot. This function expects attestations
|
||||
// requested to be cleanly divisible by committees per slot. If there is 1 committee
|
||||
// in the slot, and maxAttestations is set to 4, then it will return 4 attestations
|
||||
// for the same data with their aggregation bits split uniformly.
|
||||
//
|
||||
// If you request 4 attestations, but there are 8 committees, you will get 4 fully aggregated attestations.
|
||||
func GenerateAttestations(
|
||||
t testing.TB,
|
||||
bState *pb.BeaconState,
|
||||
privs []*bls.SecretKey,
|
||||
maxAttestations uint64,
|
||||
conf *BlockGenConfig,
|
||||
slot uint64,
|
||||
) []*ethpb.Attestation {
|
||||
headState := proto.Clone(bState).(*pb.BeaconState)
|
||||
headState, err := state.ProcessSlots(context.Background(), headState, bState.Slot+1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
currentEpoch := helpers.CurrentEpoch(bState)
|
||||
attestations := make([]*ethpb.Attestation, maxAttestations)
|
||||
|
||||
committee, err := helpers.BeaconCommittee(bState, currentEpoch, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
headRoot, err := helpers.BlockRootAtSlot(headState, bState.Slot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
maxAttestations := conf.MaxAttestations
|
||||
currentEpoch := helpers.SlotToEpoch(slot)
|
||||
attestations := []*ethpb.Attestation{}
|
||||
generateHeadState := false
|
||||
if slot > bState.Slot {
|
||||
// Going back a slot here so there's no inclusion delay issues.
|
||||
slot--
|
||||
generateHeadState = true
|
||||
}
|
||||
|
||||
var err error
|
||||
targetRoot := make([]byte, 32)
|
||||
epochStartSlot := helpers.StartSlot(currentEpoch)
|
||||
if epochStartSlot == headState.Slot {
|
||||
targetRoot = headRoot[:]
|
||||
headRoot := make([]byte, 32)
|
||||
// Only calculate head state if its an attestation for the current slot or future slot.
|
||||
if generateHeadState || slot == bState.Slot {
|
||||
headState := proto.Clone(bState).(*pb.BeaconState)
|
||||
headState, err := state.ProcessSlots(context.Background(), headState, slot+1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
headRoot, err = helpers.BlockRootAtSlot(headState, slot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
targetRoot, err = helpers.BlockRoot(headState, currentEpoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
targetRoot, err = helpers.BlockRootAtSlot(headState, epochStartSlot)
|
||||
headRoot, err = helpers.BlockRootAtSlot(bState, slot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
committeeSize := uint64(len(committee))
|
||||
custodyBits := bitfield.NewBitlist(committeeSize)
|
||||
attestingSlot := uint64(0)
|
||||
if bState.Slot > 0 {
|
||||
attestingSlot = bState.Slot - 1
|
||||
committeesPerSlot, err := helpers.CommitteeCountAtSlot(bState, slot)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
att := ðpb.Attestation{
|
||||
Data: ðpb.AttestationData{
|
||||
Slot: attestingSlot,
|
||||
if maxAttestations < committeesPerSlot {
|
||||
t.Logf(
|
||||
"Warning: %d attestations requested is less than %d committees in current slot, not all validators will be attesting.",
|
||||
maxAttestations,
|
||||
committeesPerSlot,
|
||||
)
|
||||
} else if maxAttestations > committeesPerSlot {
|
||||
t.Logf(
|
||||
"Warning: %d attestations requested are more than %d committees in current slot, attestations will not be perfectly efficient.",
|
||||
maxAttestations,
|
||||
committeesPerSlot,
|
||||
)
|
||||
}
|
||||
|
||||
attsPerCommittee := math.Max(float64(maxAttestations/committeesPerSlot), 1)
|
||||
if math.Trunc(attsPerCommittee) != attsPerCommittee {
|
||||
t.Fatalf(
|
||||
"requested attestations %d must be easily divisible by committees in slot %d, calculated %f",
|
||||
maxAttestations,
|
||||
committeesPerSlot,
|
||||
attsPerCommittee,
|
||||
)
|
||||
}
|
||||
|
||||
domain := helpers.Domain(bState.Fork, currentEpoch, params.BeaconConfig().DomainBeaconAttester)
|
||||
for c := uint64(0); c < committeesPerSlot && c < maxAttestations; c++ {
|
||||
committee, err := helpers.BeaconCommittee(bState, slot, c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
attData := ðpb.AttestationData{
|
||||
Slot: slot,
|
||||
Index: c,
|
||||
BeaconBlockRoot: headRoot,
|
||||
Source: bState.CurrentJustifiedCheckpoint,
|
||||
Target: ðpb.Checkpoint{
|
||||
Epoch: currentEpoch,
|
||||
Root: targetRoot,
|
||||
},
|
||||
},
|
||||
CustodyBits: custodyBits,
|
||||
}
|
||||
|
||||
dataRoot, err := ssz.HashTreeRoot(&pb.AttestationDataAndCustodyBit{
|
||||
Data: att.Data,
|
||||
CustodyBit: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if maxAttestations > committeeSize {
|
||||
t.Fatalf(
|
||||
"requested %d attestations per block but there are only %d committee members",
|
||||
maxAttestations,
|
||||
len(committee),
|
||||
)
|
||||
}
|
||||
|
||||
bitsPerAtt := committeeSize / maxAttestations
|
||||
domain := helpers.Domain(bState.Fork, currentEpoch, params.BeaconConfig().DomainBeaconAttester)
|
||||
for i := uint64(0); i < committeeSize; i += bitsPerAtt {
|
||||
aggregationBits := bitfield.NewBitlist(committeeSize)
|
||||
sigs := []*bls.Signature{}
|
||||
for b := i; b < i+bitsPerAtt; b++ {
|
||||
aggregationBits.SetBitAt(b, true)
|
||||
sigs = append(sigs, privs[committee[b]].Sign(dataRoot[:], domain))
|
||||
}
|
||||
att.AggregationBits = aggregationBits
|
||||
|
||||
att.Signature = bls.AggregateSignatures(sigs).Marshal()
|
||||
attestations[i/bitsPerAtt] = att
|
||||
dataRoot, err := ssz.HashTreeRoot(&pb.AttestationDataAndCustodyBit{
|
||||
Data: attData,
|
||||
CustodyBit: false,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
committeeSize := uint64(len(committee))
|
||||
bitsPerAtt := committeeSize / uint64(attsPerCommittee)
|
||||
for i := uint64(0); i < committeeSize; i += bitsPerAtt {
|
||||
aggregationBits := bitfield.NewBitlist(committeeSize)
|
||||
custodyBits := bitfield.NewBitlist(committeeSize)
|
||||
sigs := []*bls.Signature{}
|
||||
for b := i; b < i+bitsPerAtt; b++ {
|
||||
aggregationBits.SetBitAt(b, true)
|
||||
sigs = append(sigs, privs[committee[b]].Sign(dataRoot[:], domain))
|
||||
}
|
||||
|
||||
att := ðpb.Attestation{
|
||||
Data: attData,
|
||||
AggregationBits: aggregationBits,
|
||||
CustodyBits: custodyBits,
|
||||
Signature: bls.AggregateSignatures(sigs).Marshal(),
|
||||
}
|
||||
attestations = append(attestations, att)
|
||||
}
|
||||
}
|
||||
return attestations
|
||||
}
|
||||
@ -367,13 +411,13 @@ func generateAttestations(
|
||||
func generateDepositsAndEth1Data(
|
||||
t testing.TB,
|
||||
bState *pb.BeaconState,
|
||||
maxDeposits uint64,
|
||||
numDeposits uint64,
|
||||
) (
|
||||
[]*ethpb.Deposit,
|
||||
*ethpb.Eth1Data,
|
||||
) {
|
||||
previousDepsLen := bState.Eth1DepositIndex
|
||||
currentDeposits, _, _ := SetupInitialDeposits(t, previousDepsLen+maxDeposits)
|
||||
currentDeposits, _, _ := SetupInitialDeposits(t, previousDepsLen+numDeposits)
|
||||
eth1Data := GenerateEth1Data(t, currentDeposits)
|
||||
return currentDeposits[previousDepsLen:], eth1Data
|
||||
}
|
||||
@ -382,28 +426,35 @@ func generateVoluntaryExits(
|
||||
t testing.TB,
|
||||
bState *pb.BeaconState,
|
||||
privs []*bls.SecretKey,
|
||||
maxExits uint64,
|
||||
numExits uint64,
|
||||
) []*ethpb.VoluntaryExit {
|
||||
currentEpoch := helpers.CurrentEpoch(bState)
|
||||
validatorCount, err := helpers.ActiveValidatorCount(bState, currentEpoch)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
voluntaryExits := make([]*ethpb.VoluntaryExit, maxExits)
|
||||
voluntaryExits := make([]*ethpb.VoluntaryExit, numExits)
|
||||
for i := 0; i < len(voluntaryExits); i++ {
|
||||
valIndex := float64(validatorCount)*(2.0/3.0) + float64(i)
|
||||
valIndex, err := randValIndex(bState)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
exit := ðpb.VoluntaryExit{
|
||||
Epoch: helpers.PrevEpoch(bState),
|
||||
ValidatorIndex: uint64(valIndex),
|
||||
ValidatorIndex: valIndex,
|
||||
}
|
||||
root, err := ssz.SigningRoot(exit)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
domain := helpers.Domain(bState.Fork, currentEpoch, params.BeaconConfig().DomainVoluntaryExit)
|
||||
exit.Signature = privs[uint64(valIndex)].Sign(root[:], domain).Marshal()
|
||||
exit.Signature = privs[valIndex].Sign(root[:], domain).Marshal()
|
||||
voluntaryExits[i] = exit
|
||||
}
|
||||
return voluntaryExits
|
||||
}
|
||||
|
||||
func randValIndex(bState *pb.BeaconState) (uint64, error) {
|
||||
activeCount, err := helpers.ActiveValidatorCount(bState, helpers.CurrentEpoch(bState))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return rand.Uint64() % activeCount, nil
|
||||
}
|
||||
|
@ -19,13 +19,10 @@ func TestGenerateFullBlock_PassesStateTransition(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
conf := &BlockGenConfig{
|
||||
MaxProposerSlashings: 0,
|
||||
MaxAttesterSlashings: 0,
|
||||
MaxAttestations: 0,
|
||||
MaxDeposits: 0,
|
||||
MaxVoluntaryExits: 0,
|
||||
MaxAttestations: 4,
|
||||
Signatures: true,
|
||||
}
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot+1)
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot)
|
||||
beaconState, err = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -43,13 +40,10 @@ func TestGenerateFullBlock_ThousandValidators(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
conf := &BlockGenConfig{
|
||||
MaxProposerSlashings: 0,
|
||||
MaxAttesterSlashings: 0,
|
||||
MaxAttestations: 16,
|
||||
MaxDeposits: 0,
|
||||
MaxVoluntaryExits: 0,
|
||||
MaxAttestations: 16,
|
||||
Signatures: true,
|
||||
}
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot+1)
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot)
|
||||
beaconState, err = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -61,7 +55,7 @@ func TestGenerateFullBlock_Passes4Epochs(t *testing.T) {
|
||||
// Changing to minimal config as this will process 4 epochs of blocks.
|
||||
params.OverrideBeaconConfig(params.MinimalSpecConfig())
|
||||
defer params.OverrideBeaconConfig(params.MainnetConfig())
|
||||
deposits, _, privs := SetupInitialDeposits(t, 32)
|
||||
deposits, _, privs := SetupInitialDeposits(t, 64)
|
||||
eth1Data := GenerateEth1Data(t, deposits)
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, eth1Data)
|
||||
if err != nil {
|
||||
@ -69,16 +63,13 @@ func TestGenerateFullBlock_Passes4Epochs(t *testing.T) {
|
||||
}
|
||||
|
||||
conf := &BlockGenConfig{
|
||||
MaxProposerSlashings: 0,
|
||||
MaxAttesterSlashings: 0,
|
||||
MaxAttestations: 1,
|
||||
MaxDeposits: 0,
|
||||
MaxVoluntaryExits: 0,
|
||||
MaxAttestations: 2,
|
||||
Signatures: true,
|
||||
}
|
||||
finalSlot := params.BeaconConfig().SlotsPerEpoch*4 + 3
|
||||
for i := 0; i < int(finalSlot); i++ {
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot+1)
|
||||
beaconState, err = state.ExecuteStateTransitionNoVerify(context.Background(), beaconState, block)
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot)
|
||||
beaconState, err = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -97,7 +88,9 @@ func TestGenerateFullBlock_Passes4Epochs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGenerateFullBlock_ValidProposerSlashings(t *testing.T) {
|
||||
deposits, _, privs := SetupInitialDeposits(t, 257)
|
||||
params.OverrideBeaconConfig(params.MinimalSpecConfig())
|
||||
defer params.OverrideBeaconConfig(params.MainnetConfig())
|
||||
deposits, _, privs := SetupInitialDeposits(t, 32)
|
||||
|
||||
eth1Data := GenerateEth1Data(t, deposits)
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, eth1Data)
|
||||
@ -106,10 +99,7 @@ func TestGenerateFullBlock_ValidProposerSlashings(t *testing.T) {
|
||||
}
|
||||
conf := &BlockGenConfig{
|
||||
MaxProposerSlashings: 1,
|
||||
MaxAttesterSlashings: 0,
|
||||
MaxAttestations: 0,
|
||||
MaxDeposits: 0,
|
||||
MaxVoluntaryExits: 0,
|
||||
Signatures: true,
|
||||
}
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot+1)
|
||||
beaconState, err = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
||||
@ -124,20 +114,19 @@ func TestGenerateFullBlock_ValidProposerSlashings(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGenerateFullBlock_ValidAttesterSlashings(t *testing.T) {
|
||||
deposits, _, privs := SetupInitialDeposits(t, 256)
|
||||
params.OverrideBeaconConfig(params.MinimalSpecConfig())
|
||||
defer params.OverrideBeaconConfig(params.MainnetConfig())
|
||||
deposits, _, privs := SetupInitialDeposits(t, 32)
|
||||
eth1Data := GenerateEth1Data(t, deposits)
|
||||
beaconState, err := state.GenesisBeaconState(deposits, 0, eth1Data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
conf := &BlockGenConfig{
|
||||
MaxProposerSlashings: 0,
|
||||
MaxAttesterSlashings: 1,
|
||||
MaxAttestations: 0,
|
||||
MaxDeposits: 0,
|
||||
MaxVoluntaryExits: 0,
|
||||
Signatures: true,
|
||||
}
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot+1)
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot)
|
||||
beaconState, err = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -150,6 +139,8 @@ func TestGenerateFullBlock_ValidAttesterSlashings(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGenerateFullBlock_ValidAttestations(t *testing.T) {
|
||||
params.OverrideBeaconConfig(params.MinimalSpecConfig())
|
||||
defer params.OverrideBeaconConfig(params.MainnetConfig())
|
||||
helpers.ClearAllCaches()
|
||||
deposits, _, privs := SetupInitialDeposits(t, 256)
|
||||
|
||||
@ -158,22 +149,17 @@ func TestGenerateFullBlock_ValidAttestations(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Moving the slot forward one due to ATTESTATION_INCLUSION_DELAY.
|
||||
beaconState.Slot++
|
||||
conf := &BlockGenConfig{
|
||||
MaxProposerSlashings: 0,
|
||||
MaxAttesterSlashings: 0,
|
||||
MaxAttestations: 2,
|
||||
MaxDeposits: 0,
|
||||
MaxVoluntaryExits: 0,
|
||||
MaxAttestations: 4,
|
||||
Signatures: true,
|
||||
}
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot+1)
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot)
|
||||
beaconState, err = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(beaconState.CurrentEpochAttestations) != 2 {
|
||||
t.Fatal("expected 2 attestations to be saved to the beacon state")
|
||||
if len(beaconState.CurrentEpochAttestations) != 4 {
|
||||
t.Fatal("expected 4 attestations to be saved to the beacon state")
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,13 +174,10 @@ func TestGenerateFullBlock_ValidDeposits(t *testing.T) {
|
||||
eth1Data = GenerateEth1Data(t, deposits)
|
||||
beaconState.Eth1Data = eth1Data
|
||||
conf := &BlockGenConfig{
|
||||
MaxProposerSlashings: 0,
|
||||
MaxAttesterSlashings: 0,
|
||||
MaxAttestations: 0,
|
||||
MaxDeposits: 1,
|
||||
MaxVoluntaryExits: 0,
|
||||
MaxDeposits: 1,
|
||||
Signatures: true,
|
||||
}
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot+1)
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot)
|
||||
beaconState, err = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -221,13 +204,10 @@ func TestGenerateFullBlock_ValidVoluntaryExits(t *testing.T) {
|
||||
// Moving the state 2048 epochs forward due to PERSISTENT_COMMITTEE_PERIOD.
|
||||
beaconState.Slot = 3 + params.BeaconConfig().PersistentCommitteePeriod*params.BeaconConfig().SlotsPerEpoch
|
||||
conf := &BlockGenConfig{
|
||||
MaxProposerSlashings: 0,
|
||||
MaxAttesterSlashings: 0,
|
||||
MaxAttestations: 0,
|
||||
MaxDeposits: 0,
|
||||
MaxVoluntaryExits: 1,
|
||||
MaxVoluntaryExits: 1,
|
||||
Signatures: true,
|
||||
}
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot+1)
|
||||
block := GenerateFullBlock(t, beaconState, privs, conf, beaconState.Slot)
|
||||
beaconState, err = state.ExecuteStateTransition(context.Background(), beaconState, block)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
Loading…
Reference in New Issue
Block a user