prysm-pulse/testing/util/state.go
james-prysm e0eee87bf4
Improve beacon chain coverage Part 1 (#11080)
* first node test

* adding in configuration flags for code coverage

* adding line to remove file on unit test

* adding new test for compressed field trie but is currently broken

* changing limit on trie

* adding new trie length coverage

* adding in test for empty copy of trie

* adding more trie tests

* adding new field trie

* adding more field trie tests

* adding clarity to chunking equation

* fixing linting

* clarifying function for limit

* updating native state settings to improve ease of future unit tests

* improving unit test

* fixing unit tests

* adding more tests and fixing linting

* adding more coverage and removing unused file

* increasing node coverage

* adding new test for checking config for booleans

* fixing db test

* fixing linting

* adding signing root test

* fixing linting

* removing accidently created beacondata

* switching not non native state

* reverting back to proto use for spec test

* reverting back to proto for some tests

* turning off native state on some tests

* switching more to proto state

* rolling back disablenativestate

* switching to native state in the state-native package for tests

* fixing linting

* fixing deepsource complaint

* fixing some tests to native state and removing some unused flag checks

* convert to native state

* fixing linting

* issues are being triggered by deleting the db this way so reverting change in hopes of changing this

* rolling back testing util

* rolling back some tests from native state

* rolling back db deletion

* test switching native state off after test runs

* fixing hasher test

* fixing altair and bellatrix hashers for native state

* Update beacon-chain/node/node_test.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update validator/rpc/auth_token_test.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* fixing imports

* adding altair proof test

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
2022-08-16 16:19:01 +00:00

281 lines
10 KiB
Go

package util
import (
"context"
"fmt"
"testing"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/prysmaticlabs/go-bitfield"
b "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/db/iface"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
v1 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v1"
v2 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v2"
v3 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v3"
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/testing/require"
)
// FillRootsNaturalOpt is meant to be used as an option when calling NewBeaconState.
// It fills state and block roots with hex representations of natural numbers starting with 0.
// Example: 16 becomes 0x00...0f.
func FillRootsNaturalOpt(state *ethpb.BeaconState) error {
roots, err := PrepareRoots(int(params.BeaconConfig().SlotsPerHistoricalRoot))
if err != nil {
return err
}
state.StateRoots = roots
state.BlockRoots = roots
return nil
}
// FillRootsNaturalOptAltair is meant to be used as an option when calling NewBeaconStateAltair.
// It fills state and block roots with hex representations of natural numbers starting with 0.
// Example: 16 becomes 0x00...0f.
func FillRootsNaturalOptAltair(state *ethpb.BeaconStateAltair) error {
roots, err := PrepareRoots(int(params.BeaconConfig().SlotsPerHistoricalRoot))
if err != nil {
return err
}
state.StateRoots = roots
state.BlockRoots = roots
return nil
}
// FillRootsNaturalOptBellatrix is meant to be used as an option when calling NewBeaconStateAltair.
// It fills state and block roots with hex representations of natural numbers starting with 0.
// Example: 16 becomes 0x00...0f.
func FillRootsNaturalOptBellatrix(state *ethpb.BeaconStateBellatrix) error {
roots, err := PrepareRoots(int(params.BeaconConfig().SlotsPerHistoricalRoot))
if err != nil {
return err
}
state.StateRoots = roots
state.BlockRoots = roots
return nil
}
type NewBeaconStateOption func(state *ethpb.BeaconState) error
// NewBeaconState creates a beacon state with minimum marshalable fields.
func NewBeaconState(options ...NewBeaconStateOption) (state.BeaconState, error) {
seed := &ethpb.BeaconState{
BlockRoots: filledByteSlice2D(uint64(params.MainnetConfig().SlotsPerHistoricalRoot), 32),
StateRoots: filledByteSlice2D(uint64(params.MainnetConfig().SlotsPerHistoricalRoot), 32),
Slashings: make([]uint64, params.MainnetConfig().EpochsPerSlashingsVector),
RandaoMixes: filledByteSlice2D(uint64(params.MainnetConfig().EpochsPerHistoricalVector), 32),
Validators: make([]*ethpb.Validator, 0),
CurrentJustifiedCheckpoint: &ethpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
Eth1Data: &ethpb.Eth1Data{
DepositRoot: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, 32),
},
Fork: &ethpb.Fork{
PreviousVersion: make([]byte, 4),
CurrentVersion: make([]byte, 4),
},
Eth1DataVotes: make([]*ethpb.Eth1Data, 0),
HistoricalRoots: make([][]byte, 0),
JustificationBits: bitfield.Bitvector4{0x0},
FinalizedCheckpoint: &ethpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
LatestBlockHeader: HydrateBeaconHeader(&ethpb.BeaconBlockHeader{}),
PreviousEpochAttestations: make([]*ethpb.PendingAttestation, 0),
CurrentEpochAttestations: make([]*ethpb.PendingAttestation, 0),
PreviousJustifiedCheckpoint: &ethpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
}
for _, opt := range options {
err := opt(seed)
if err != nil {
return nil, err
}
}
var st, err = v1.InitializeFromProtoUnsafe(seed)
if err != nil {
return nil, err
}
return st.Copy(), nil
}
// NewBeaconStateAltair creates a beacon state with minimum marshalable fields.
func NewBeaconStateAltair(options ...func(state *ethpb.BeaconStateAltair) error) (state.BeaconState, error) {
pubkeys := make([][]byte, 512)
for i := range pubkeys {
pubkeys[i] = make([]byte, 48)
}
seed := &ethpb.BeaconStateAltair{
BlockRoots: filledByteSlice2D(uint64(params.MainnetConfig().SlotsPerHistoricalRoot), 32),
StateRoots: filledByteSlice2D(uint64(params.MainnetConfig().SlotsPerHistoricalRoot), 32),
Slashings: make([]uint64, params.MainnetConfig().EpochsPerSlashingsVector),
RandaoMixes: filledByteSlice2D(uint64(params.MainnetConfig().EpochsPerHistoricalVector), 32),
Validators: make([]*ethpb.Validator, 0),
CurrentJustifiedCheckpoint: &ethpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
Eth1Data: &ethpb.Eth1Data{
DepositRoot: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, 32),
},
Fork: &ethpb.Fork{
PreviousVersion: make([]byte, 4),
CurrentVersion: make([]byte, 4),
},
Eth1DataVotes: make([]*ethpb.Eth1Data, 0),
HistoricalRoots: make([][]byte, 0),
JustificationBits: bitfield.Bitvector4{0x0},
FinalizedCheckpoint: &ethpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
LatestBlockHeader: HydrateBeaconHeader(&ethpb.BeaconBlockHeader{}),
PreviousJustifiedCheckpoint: &ethpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
PreviousEpochParticipation: make([]byte, 0),
CurrentEpochParticipation: make([]byte, 0),
CurrentSyncCommittee: &ethpb.SyncCommittee{
Pubkeys: pubkeys,
AggregatePubkey: make([]byte, 48),
},
NextSyncCommittee: &ethpb.SyncCommittee{
Pubkeys: pubkeys,
AggregatePubkey: make([]byte, 48),
},
}
for _, opt := range options {
err := opt(seed)
if err != nil {
return nil, err
}
}
var st, err = v2.InitializeFromProtoUnsafe(seed)
if err != nil {
return nil, err
}
return st.Copy(), nil
}
// NewBeaconStateBellatrix creates a beacon state with minimum marshalable fields.
func NewBeaconStateBellatrix(options ...func(state *ethpb.BeaconStateBellatrix) error) (state.BeaconState, error) {
pubkeys := make([][]byte, 512)
for i := range pubkeys {
pubkeys[i] = make([]byte, 48)
}
seed := &ethpb.BeaconStateBellatrix{
BlockRoots: filledByteSlice2D(uint64(params.MainnetConfig().SlotsPerHistoricalRoot), 32),
StateRoots: filledByteSlice2D(uint64(params.MainnetConfig().SlotsPerHistoricalRoot), 32),
Slashings: make([]uint64, params.MainnetConfig().EpochsPerSlashingsVector),
RandaoMixes: filledByteSlice2D(uint64(params.MainnetConfig().EpochsPerHistoricalVector), 32),
Validators: make([]*ethpb.Validator, 0),
CurrentJustifiedCheckpoint: &ethpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
Eth1Data: &ethpb.Eth1Data{
DepositRoot: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, 32),
},
Fork: &ethpb.Fork{
PreviousVersion: make([]byte, 4),
CurrentVersion: make([]byte, 4),
},
Eth1DataVotes: make([]*ethpb.Eth1Data, 0),
HistoricalRoots: make([][]byte, 0),
JustificationBits: bitfield.Bitvector4{0x0},
FinalizedCheckpoint: &ethpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
LatestBlockHeader: HydrateBeaconHeader(&ethpb.BeaconBlockHeader{}),
PreviousJustifiedCheckpoint: &ethpb.Checkpoint{Root: make([]byte, fieldparams.RootLength)},
PreviousEpochParticipation: make([]byte, 0),
CurrentEpochParticipation: make([]byte, 0),
CurrentSyncCommittee: &ethpb.SyncCommittee{
Pubkeys: pubkeys,
AggregatePubkey: make([]byte, 48),
},
NextSyncCommittee: &ethpb.SyncCommittee{
Pubkeys: pubkeys,
AggregatePubkey: make([]byte, 48),
},
LatestExecutionPayloadHeader: &enginev1.ExecutionPayloadHeader{
ParentHash: make([]byte, 32),
FeeRecipient: make([]byte, 20),
StateRoot: make([]byte, 32),
ReceiptsRoot: make([]byte, 32),
LogsBloom: make([]byte, 256),
PrevRandao: make([]byte, 32),
ExtraData: make([]byte, 0),
BaseFeePerGas: make([]byte, 32),
BlockHash: make([]byte, 32),
TransactionsRoot: make([]byte, 32),
},
}
for _, opt := range options {
err := opt(seed)
if err != nil {
return nil, err
}
}
var st, err = v3.InitializeFromProtoUnsafe(seed)
if err != nil {
return nil, err
}
return st.Copy(), nil
}
// SSZ will fill 2D byte slices with their respective values, so we must fill these in too for round
// trip testing.
func filledByteSlice2D(length, innerLen uint64) [][]byte {
b := make([][]byte, length)
for i := uint64(0); i < length; i++ {
b[i] = make([]byte, innerLen)
}
return b
}
// PrepareRoots returns a list of roots with hex representations of natural numbers starting with 0.
// Example: 16 becomes 0x00...0f.
func PrepareRoots(size int) ([][]byte, error) {
roots := make([][]byte, size)
for i := 0; i < size; i++ {
roots[i] = make([]byte, fieldparams.RootLength)
}
for j := 0; j < len(roots); j++ {
// Remove '0x' prefix and left-pad '0' to have 64 chars in total.
s := fmt.Sprintf("%064s", hexutil.EncodeUint64(uint64(j))[2:])
h, err := hexutil.Decode("0x" + s)
if err != nil {
return nil, err
}
roots[j] = h
}
return roots, nil
}
// DeterministicGenesisStateWithGenesisBlock creates a genesis state, saves the genesis block,
// genesis state and head block root. It returns the genesis state, genesis block's root and
// validator private keys.
func DeterministicGenesisStateWithGenesisBlock(
t *testing.T,
ctx context.Context,
db iface.HeadAccessDatabase,
numValidators uint64,
) (state.BeaconState, [32]byte, []bls.SecretKey) {
genesisState, privateKeys := DeterministicGenesisState(t, numValidators)
stateRoot, err := genesisState.HashTreeRoot(ctx)
require.NoError(t, err, "Could not hash genesis state")
genesis := b.NewGenesisBlock(stateRoot[:])
SaveBlock(t, ctx, db, genesis)
parentRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err, "Could not get signing root")
require.NoError(t, db.SaveState(ctx, genesisState, parentRoot), "Could not save genesis state")
require.NoError(t, db.SaveHeadBlockRoot(ctx, parentRoot), "Could not save genesis state")
return genesisState, parentRoot, privateKeys
}