Skip to content

Commit

Permalink
Add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
potuz committed Aug 5, 2024
1 parent 69f42d2 commit 6ed14db
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 14 deletions.
13 changes: 10 additions & 3 deletions beacon-chain/core/epbs/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,25 @@ go_library(
"//beacon-chain/state:go_default_library",
"//consensus-types/interfaces:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"@com_github_pkg_errors//:go_default_library",
],
)

go_test(
name = "go_default_test",
srcs = ["attestation_test.go"],
srcs = [
"attestation_test.go",
"execution_payload_envelope_test.go",
],
embed = [":go_default_library"],
deps = [
":go_default_library",
"//beacon-chain/core/altair:go_default_library",
"//beacon-chain/state/state-native:go_default_library",
"//config/params:go_default_library",
"//consensus-types/epbs:go_default_library",
"//proto/engine/v1:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//testing/require:go_default_library",
"//testing/util:go_default_library",
],
)
14 changes: 6 additions & 8 deletions beacon-chain/core/epbs/execution_payload_envelope.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
)

func processPayloadStateTransition(
Expand Down Expand Up @@ -44,10 +43,13 @@ func processPayloadStateTransition(
func validateAgainstHeader(
ctx context.Context,
preState state.BeaconState,
blockHeader *ethpb.BeaconBlockHeader,
envelope interfaces.ROExecutionPayloadEnvelope,
) error {
if blockHeader.StateRoot == nil || [32]byte(blockHeader.StateRoot) == [32]byte{} {
blockHeader := preState.LatestBlockHeader()
if blockHeader == nil {
return errors.New("invalid nil latest block header")
}
if len(blockHeader.StateRoot) == 0 || [32]byte(blockHeader.StateRoot) == [32]byte{} {
prevStateRoot, err := preState.HashTreeRoot(ctx)
if err != nil {
return errors.Wrap(err, "could not compute previous state root")
Expand Down Expand Up @@ -116,11 +118,7 @@ func ValidatePayloadStateTransition(
preState state.BeaconState,
envelope interfaces.ROExecutionPayloadEnvelope,
) error {
blockHeader := preState.LatestBlockHeader()
if blockHeader == nil {
return errors.New("invalid nil latest block header")
}
if err := validateAgainstHeader(ctx, preState, blockHeader, envelope); err != nil {
if err := validateAgainstHeader(ctx, preState, envelope); err != nil {
return err
}
committedHeader, err := preState.LatestExecutionPayloadHeaderEPBS()
Expand Down
105 changes: 105 additions & 0 deletions beacon-chain/core/epbs/execution_payload_envelope_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package epbs

import (
"context"
"testing"

state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
consensus_epbs "github.com/prysmaticlabs/prysm/v5/consensus-types/epbs"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v5/testing/require"
"github.com/prysmaticlabs/prysm/v5/testing/util"
)

func TestProcessPayloadStateTransition(t *testing.T) {
bh := [32]byte{'h'}
payload := &enginev1.ExecutionPayloadElectra{BlockHash: bh[:]}
p := &enginev1.ExecutionPayloadEnvelope{Payload: payload}
e, err := consensus_epbs.WrappedROExecutionPayloadEnvelope(p)
require.NoError(t, err)
stpb := &ethpb.BeaconStateEPBS{Slot: 3}
st, err := state_native.InitializeFromProtoUnsafeEpbs(stpb)
require.NoError(t, err)
ctx := context.Background()

lbh, err := st.LatestBlockHash()
require.NoError(t, err)
require.Equal(t, [32]byte{}, [32]byte(lbh))

require.NoError(t, processPayloadStateTransition(ctx, st, e))

lbh, err = st.LatestBlockHash()
require.NoError(t, err)
require.Equal(t, bh, [32]byte(lbh))

lfs, err := st.LatestFullSlot()
require.NoError(t, err)
require.Equal(t, lfs, st.Slot())
}

func Test_validateAgainstHeader(t *testing.T) {
bh := [32]byte{'h'}
payload := &enginev1.ExecutionPayloadElectra{BlockHash: bh[:]}
p := &enginev1.ExecutionPayloadEnvelope{Payload: payload}
e, err := consensus_epbs.WrappedROExecutionPayloadEnvelope(p)
require.NoError(t, err)
stpb := &ethpb.BeaconStateEPBS{Slot: 3}
st, err := state_native.InitializeFromProtoUnsafeEpbs(stpb)
require.NoError(t, err)
ctx := context.Background()
require.ErrorContains(t, "invalid nil latest block header", validateAgainstHeader(ctx, st, e))

prest, _ := util.DeterministicGenesisStateEpbs(t, 64)
require.ErrorContains(t, "attempted to wrap nil object", validateAgainstHeader(ctx, prest, e))

br := [32]byte{'r'}
p.BeaconBlockRoot = br[:]
require.ErrorContains(t, "beacon block root does not match previous header", validateAgainstHeader(ctx, prest, e))

header := prest.LatestBlockHeader()
require.NoError(t, err)
headerRoot, err := header.HashTreeRoot()
require.NoError(t, err)
p.BeaconBlockRoot = headerRoot[:]
require.NoError(t, validateAgainstHeader(ctx, prest, e))
}

func Test_validateAgainstCommittedBid(t *testing.T) {
payload := &enginev1.ExecutionPayloadElectra{}
p := &enginev1.ExecutionPayloadEnvelope{Payload: payload, BuilderIndex: 1}
e, err := consensus_epbs.WrappedROExecutionPayloadEnvelope(p)
require.NoError(t, err)
h := &enginev1.ExecutionPayloadHeaderEPBS{}
require.ErrorContains(t, "builder index does not match committed header", validateAgainstCommittedBid(h, e))

h.BuilderIndex = 1
require.ErrorContains(t, "attempted to wrap nil object", validateAgainstCommittedBid(h, e))
p.BlobKzgCommitments = make([][]byte, 6)
for i := range p.BlobKzgCommitments {
p.BlobKzgCommitments[i] = make([]byte, 48)
}
h.BlobKzgCommitmentsRoot = make([]byte, 32)
require.ErrorContains(t, "blob KZG commitments root does not match committed header", validateAgainstCommittedBid(h, e))

root, err := e.BlobKzgCommitmentsRoot()
require.NoError(t, err)
h.BlobKzgCommitmentsRoot = root[:]
require.NoError(t, validateAgainstCommittedBid(h, e))
}

func TestCheckPostStateRoot(t *testing.T) {
payload := &enginev1.ExecutionPayloadElectra{}
p := &enginev1.ExecutionPayloadEnvelope{Payload: payload, BuilderIndex: 1}
e, err := consensus_epbs.WrappedROExecutionPayloadEnvelope(p)
require.NoError(t, err)
ctx := context.Background()
st, _ := util.DeterministicGenesisStateEpbs(t, 64)
require.ErrorContains(t, "attempted to wrap nil object", checkPostStateRoot(ctx, st, e))
p.StateRoot = make([]byte, 32)
require.ErrorContains(t, "state root mismatch", checkPostStateRoot(ctx, st, e))
root, err := st.HashTreeRoot(ctx)
require.NoError(t, err)
p.StateRoot = root[:]
require.NoError(t, checkPostStateRoot(ctx, st, e))
}
6 changes: 3 additions & 3 deletions consensus-types/epbs/execution_payload_envelope.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (p executionPayloadEnvelope) BuilderIndex() (primitives.ValidatorIndex, err

// BeaconBlockRoot returns the wrapped value
func (p executionPayloadEnvelope) BeaconBlockRoot() ([field_params.RootLength]byte, error) {
if p.IsNil() {
if p.IsNil() || len(p.p.BeaconBlockRoot) == 0 {
return [field_params.RootLength]byte{}, consensus_types.ErrNilObjectWrapped
}
return [field_params.RootLength]byte(p.p.BeaconBlockRoot), nil
Expand Down Expand Up @@ -114,7 +114,7 @@ func (p executionPayloadEnvelope) PayloadWithheld() (bool, error) {

// StateRoot returns the wrapped value
func (p executionPayloadEnvelope) StateRoot() ([field_params.RootLength]byte, error) {
if p.IsNil() {
if p.IsNil() || len(p.p.StateRoot) == 0 {
return [field_params.RootLength]byte{}, consensus_types.ErrNilObjectWrapped
}
return [field_params.RootLength]byte(p.p.StateRoot), nil
Expand All @@ -137,7 +137,7 @@ func (p executionPayloadEnvelope) VersionedHashes() ([]common.Hash, error) {

// BlobKzgCommitmentsRoot returns the HTR of the KZG commitments in the payload
func (p executionPayloadEnvelope) BlobKzgCommitmentsRoot() ([field_params.RootLength]byte, error) {
if p.IsNil() {
if p.IsNil() || p.p.BlobKzgCommitments == nil {
return [field_params.RootLength]byte{}, consensus_types.ErrNilObjectWrapped
}

Expand Down
1 change: 1 addition & 0 deletions testing/util/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ go_library(
"electra.go",
"electra_block.go",
"electra_state.go",
"epbs_state.go",
"helpers.go",
"merge.go",
"state.go",
Expand Down
92 changes: 92 additions & 0 deletions testing/util/epbs_state.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package util

import (
"context"
"testing"

"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
"github.com/prysmaticlabs/prysm/v5/config/params"
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
)

// emptyGenesisStateEpbs returns an empty genesis state in ePBS format.
func emptyGenesisStateEpbs() (state.BeaconState, error) {
st := &ethpb.BeaconStateEPBS{
// Misc fields.
Slot: 0,
Fork: &ethpb.Fork{
PreviousVersion: params.BeaconConfig().BellatrixForkVersion,
CurrentVersion: params.BeaconConfig().DenebForkVersion,
Epoch: 0,
},
// Validator registry fields.
Validators: []*ethpb.Validator{},
Balances: []uint64{},
InactivityScores: []uint64{},

JustificationBits: []byte{0},
HistoricalRoots: [][]byte{},
CurrentEpochParticipation: []byte{},
PreviousEpochParticipation: []byte{},

// Eth1 data.
Eth1Data: &ethpb.Eth1Data{},
Eth1DataVotes: []*ethpb.Eth1Data{},
Eth1DepositIndex: 0,

LatestExecutionPayloadHeader: &enginev1.ExecutionPayloadHeaderEPBS{},

DepositBalanceToConsume: primitives.Gwei(0),
ExitBalanceToConsume: primitives.Gwei(0),
ConsolidationBalanceToConsume: primitives.Gwei(0),
}
return state_native.InitializeFromProtoEpbs(st)
}

// genesisBeaconStateEpbs returns the genesis beacon state.
func genesisBeaconStateEpbs(ctx context.Context, deposits []*ethpb.Deposit, genesisTime uint64, eth1Data *ethpb.Eth1Data) (state.BeaconState, error) {
st, err := emptyGenesisStateElectra()
if err != nil {
return nil, err
}

// Process initial deposits.
st, err = helpers.UpdateGenesisEth1Data(st, deposits, eth1Data)
if err != nil {
return nil, err
}

st, err = processPreGenesisDeposits(ctx, st, deposits)
if err != nil {
return nil, errors.Wrap(err, "could not process validator deposits")
}

return buildGenesisBeaconStateElectra(genesisTime, st, st.Eth1Data())
}

// DeterministicGenesisStateEpbs returns a genesis state in ePBS format made using the deterministic deposits.
func DeterministicGenesisStateEpbs(t testing.TB, numValidators uint64) (state.BeaconState, []bls.SecretKey) {
deposits, privKeys, err := DeterministicDepositsAndKeys(numValidators)
if err != nil {
t.Fatal(errors.Wrapf(err, "failed to get %d deposits", numValidators))
}
eth1Data, err := DeterministicEth1Data(len(deposits))
if err != nil {
t.Fatal(errors.Wrapf(err, "failed to get eth1data for %d deposits", numValidators))
}
beaconState, err := genesisBeaconStateElectra(context.Background(), deposits, uint64(0), eth1Data)
if err != nil {
t.Fatal(errors.Wrapf(err, "failed to get genesis beacon state of %d validators", numValidators))
}
if err := setKeysToActive(beaconState); err != nil {
t.Fatal(errors.Wrapf(err, "failed to set keys to active"))
}
resetCache()
return beaconState, privKeys
}

0 comments on commit 6ed14db

Please sign in to comment.