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:
Ivan Martinez 2019-11-26 13:09:57 -05:00 committed by prylabs-bulldozer[bot]
parent b88e6dc918
commit c1c48a8af5
11 changed files with 748 additions and 201 deletions

View 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"],
)

View 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
```

View File

@ -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"],
)

View File

@ -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
}

View 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 := &ethpb.BeaconBlock{}
if err := ssz.Unmarshal(blockBytes, beaconBlock); err != nil {
return nil, err
}
return beaconBlock, nil
}

View 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)
}

View File

@ -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 := &ethpb.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 := &ethpb.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 := &ethpb.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 := &ethpb.AttestationData{
Target: &ethpb.Checkpoint{
Epoch: i,
Root: params.BeaconConfig().ZeroHash[:],
},
Source: &ethpb.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 := &ethpb.Attestation{
Data: attData1,
CustodyBits: custodyBits,
Data: &ethpb.AttestationData{
Slot: bState.Slot,
Index: committeeIndex,
Target: &ethpb.Checkpoint{
Epoch: currentEpoch,
Root: params.BeaconConfig().ZeroHash[:],
},
Source: &ethpb.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 := &ethpb.AttestationData{
Target: &ethpb.Checkpoint{
Epoch: i,
Root: params.BeaconConfig().ZeroHash[:],
},
Source: &ethpb.Checkpoint{
Epoch: i,
Root: params.BeaconConfig().ZeroHash[:],
},
}
att2 := &ethpb.Attestation{
Data: attData2,
CustodyBits: custodyBits,
Data: &ethpb.AttestationData{
Slot: bState.Slot,
Index: committeeIndex,
Target: &ethpb.Checkpoint{
Epoch: currentEpoch,
Root: params.BeaconConfig().ZeroHash[:],
},
Source: &ethpb.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 := &ethpb.Attestation{
Data: &ethpb.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 := &ethpb.AttestationData{
Slot: slot,
Index: c,
BeaconBlockRoot: headRoot,
Source: bState.CurrentJustifiedCheckpoint,
Target: &ethpb.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 := &ethpb.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 := &ethpb.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
}

View File

@ -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)