mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-11 12:10:05 +00:00
cafe0bd1f8
* fork * types * cloners * getters * remove CapellaBlind from fork * hasher * setters * spec params, config tests * generate ssz * executionPayloadHeaderCapella * proto state * BeaconStateCapella SSZ * saving state * configfork * BUILD files * fix RealPosition * fix hasher * SetLatestExecutionPayloadHeaderCapella * fix error message * reduce complexity of saveStatesEfficientInternal * add latestExecutionPayloadHeaderCapella to minimal state * halway done interface * remove withdrawal methods * merge setters * change signatures for v1 and v2 * fixing errors pt. 1 * paylod_test fixes * fix everything * remove unused func * fix tests * state_trie_test improvements * in progress... * hasher test * fix configs * simplify hashing * Revert "fix configs" This reverts commit bcae2825fcc8ba45a2b43d68ad0ab57f8eac8952. * remove capella from config test * unify locking * review * hashing * fixes Co-authored-by: terencechain <terence@prysmaticlabs.com> Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
845 lines
23 KiB
Go
845 lines
23 KiB
Go
package blocks_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
|
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/time"
|
|
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
|
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
|
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
|
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
|
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
|
"github.com/prysmaticlabs/prysm/v3/encoding/ssz"
|
|
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
|
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
|
"github.com/prysmaticlabs/prysm/v3/testing/util"
|
|
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
|
)
|
|
|
|
func Test_IsMergeComplete(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
payload interfaces.ExecutionData
|
|
want bool
|
|
}{
|
|
{
|
|
name: "empty payload header",
|
|
payload: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
return h
|
|
}(),
|
|
want: false,
|
|
},
|
|
{
|
|
name: "has parent hash",
|
|
payload: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.ParentHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "has fee recipient",
|
|
payload: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.FeeRecipient = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "has state root",
|
|
payload: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.StateRoot = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "has receipt root",
|
|
payload: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.ReceiptsRoot = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "has logs bloom",
|
|
payload: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.LogsBloom = bytesutil.PadTo([]byte{'a'}, fieldparams.LogsBloomLength)
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "has random",
|
|
payload: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.PrevRandao = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "has base fee",
|
|
payload: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.BaseFeePerGas = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "has block hash",
|
|
payload: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.BlockHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "has extra data",
|
|
payload: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.ExtraData = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "has block number",
|
|
payload: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.BlockNumber = 1
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "has gas limit",
|
|
payload: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.GasLimit = 1
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "has gas used",
|
|
payload: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.GasUsed = 1
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "has time stamp",
|
|
payload: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.Timestamp = 1
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
|
require.NoError(t, st.SetLatestExecutionPayloadHeader(tt.payload))
|
|
got, err := blocks.IsMergeTransitionComplete(st)
|
|
require.NoError(t, err)
|
|
if got != tt.want {
|
|
t.Errorf("mergeComplete() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_IsExecutionBlock(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
payload *enginev1.ExecutionPayload
|
|
want bool
|
|
}{
|
|
{
|
|
name: "empty payload",
|
|
payload: emptyPayload(),
|
|
want: false,
|
|
},
|
|
{
|
|
name: "non-empty payload",
|
|
payload: func() *enginev1.ExecutionPayload {
|
|
p := emptyPayload()
|
|
p.ParentHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return p
|
|
}(),
|
|
want: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
blk := util.NewBeaconBlockBellatrix()
|
|
blk.Block.Body.ExecutionPayload = tt.payload
|
|
wrappedBlock, err := consensusblocks.NewBeaconBlock(blk.Block)
|
|
require.NoError(t, err)
|
|
got, err := blocks.IsExecutionBlock(wrappedBlock.Body())
|
|
require.NoError(t, err)
|
|
require.Equal(t, tt.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_IsExecutionEnabled(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
payload *enginev1.ExecutionPayload
|
|
header interfaces.ExecutionData
|
|
useAltairSt bool
|
|
want bool
|
|
}{
|
|
{
|
|
name: "use older than bellatrix state",
|
|
payload: emptyPayload(),
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
return h
|
|
}(),
|
|
useAltairSt: true,
|
|
want: false,
|
|
},
|
|
{
|
|
name: "empty header, empty payload",
|
|
payload: emptyPayload(),
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
return h
|
|
}(),
|
|
want: false,
|
|
},
|
|
{
|
|
name: "non-empty header, empty payload",
|
|
payload: emptyPayload(),
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.ParentHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "empty header, non-empty payload",
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
return h
|
|
}(),
|
|
payload: func() *enginev1.ExecutionPayload {
|
|
p := emptyPayload()
|
|
p.Timestamp = 1
|
|
return p
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "non-empty header, non-empty payload",
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.ParentHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return h
|
|
}(),
|
|
payload: func() *enginev1.ExecutionPayload {
|
|
p := emptyPayload()
|
|
p.Timestamp = 1
|
|
return p
|
|
}(),
|
|
want: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
|
require.NoError(t, st.SetLatestExecutionPayloadHeader(tt.header))
|
|
blk := util.NewBeaconBlockBellatrix()
|
|
blk.Block.Body.ExecutionPayload = tt.payload
|
|
body, err := consensusblocks.NewBeaconBlockBody(blk.Block.Body)
|
|
require.NoError(t, err)
|
|
if tt.useAltairSt {
|
|
st, _ = util.DeterministicGenesisStateAltair(t, 1)
|
|
}
|
|
got, err := blocks.IsExecutionEnabled(st, body)
|
|
require.NoError(t, err)
|
|
if got != tt.want {
|
|
t.Errorf("IsExecutionEnabled() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_IsExecutionEnabledUsingHeader(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
payload *enginev1.ExecutionPayload
|
|
header interfaces.ExecutionData
|
|
want bool
|
|
}{
|
|
{
|
|
name: "empty header, empty payload",
|
|
payload: emptyPayload(),
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
return h
|
|
}(),
|
|
want: false,
|
|
},
|
|
{
|
|
name: "non-empty header, empty payload",
|
|
payload: emptyPayload(),
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.ParentHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return h
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "empty header, non-empty payload",
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
return h
|
|
}(),
|
|
payload: func() *enginev1.ExecutionPayload {
|
|
p := emptyPayload()
|
|
p.Timestamp = 1
|
|
return p
|
|
}(),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "non-empty header, non-empty payload",
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.ParentHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return h
|
|
}(),
|
|
payload: func() *enginev1.ExecutionPayload {
|
|
p := emptyPayload()
|
|
p.Timestamp = 1
|
|
return p
|
|
}(),
|
|
want: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
blk := util.NewBeaconBlockBellatrix()
|
|
blk.Block.Body.ExecutionPayload = tt.payload
|
|
body, err := consensusblocks.NewBeaconBlockBody(blk.Block.Body)
|
|
require.NoError(t, err)
|
|
got, err := blocks.IsExecutionEnabledUsingHeader(tt.header, body)
|
|
require.NoError(t, err)
|
|
if got != tt.want {
|
|
t.Errorf("IsExecutionEnabled() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_ValidatePayloadWhenMergeCompletes(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
payload *enginev1.ExecutionPayload
|
|
header interfaces.ExecutionData
|
|
err error
|
|
}{
|
|
{
|
|
name: "merge incomplete",
|
|
payload: emptyPayload(),
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
return h
|
|
}(),
|
|
err: nil,
|
|
},
|
|
{
|
|
name: "validate passes",
|
|
payload: func() *enginev1.ExecutionPayload {
|
|
p := emptyPayload()
|
|
p.ParentHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return p
|
|
}(),
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.BlockHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return h
|
|
}(),
|
|
err: nil,
|
|
},
|
|
{
|
|
name: "incorrect blockhash",
|
|
payload: func() *enginev1.ExecutionPayload {
|
|
p := emptyPayload()
|
|
p.ParentHash = bytesutil.PadTo([]byte{'a'}, fieldparams.RootLength)
|
|
return p
|
|
}(),
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.BlockHash = bytesutil.PadTo([]byte{'b'}, fieldparams.RootLength)
|
|
return h
|
|
}(),
|
|
err: blocks.ErrInvalidPayloadBlockHash,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
|
require.NoError(t, st.SetLatestExecutionPayloadHeader(tt.header))
|
|
wrappedPayload, err := consensusblocks.WrappedExecutionPayload(tt.payload)
|
|
require.NoError(t, err)
|
|
err = blocks.ValidatePayloadWhenMergeCompletes(st, wrappedPayload)
|
|
if err != nil {
|
|
require.Equal(t, tt.err.Error(), err.Error())
|
|
} else {
|
|
require.Equal(t, tt.err, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_ValidatePayload(t *testing.T) {
|
|
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
|
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
|
require.NoError(t, err)
|
|
ts, err := slots.ToTime(st.GenesisTime(), st.Slot())
|
|
require.NoError(t, err)
|
|
tests := []struct {
|
|
name string
|
|
payload *enginev1.ExecutionPayload
|
|
err error
|
|
}{
|
|
{
|
|
name: "validate passes",
|
|
payload: func() *enginev1.ExecutionPayload {
|
|
h := emptyPayload()
|
|
h.PrevRandao = random
|
|
h.Timestamp = uint64(ts.Unix())
|
|
return h
|
|
}(), err: nil,
|
|
},
|
|
{
|
|
name: "incorrect prev randao",
|
|
payload: emptyPayload(),
|
|
err: blocks.ErrInvalidPayloadPrevRandao,
|
|
},
|
|
{
|
|
name: "incorrect timestamp",
|
|
payload: func() *enginev1.ExecutionPayload {
|
|
h := emptyPayload()
|
|
h.PrevRandao = random
|
|
h.Timestamp = 1
|
|
return h
|
|
}(),
|
|
err: blocks.ErrInvalidPayloadTimeStamp,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
wrappedPayload, err := consensusblocks.WrappedExecutionPayload(tt.payload)
|
|
require.NoError(t, err)
|
|
err = blocks.ValidatePayload(st, wrappedPayload)
|
|
if err != nil {
|
|
require.Equal(t, tt.err.Error(), err.Error())
|
|
} else {
|
|
require.Equal(t, tt.err, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_ProcessPayload(t *testing.T) {
|
|
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
|
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
|
require.NoError(t, err)
|
|
ts, err := slots.ToTime(st.GenesisTime(), st.Slot())
|
|
require.NoError(t, err)
|
|
tests := []struct {
|
|
name string
|
|
payload *enginev1.ExecutionPayload
|
|
err error
|
|
}{
|
|
{
|
|
name: "process passes",
|
|
payload: func() *enginev1.ExecutionPayload {
|
|
h := emptyPayload()
|
|
h.PrevRandao = random
|
|
h.Timestamp = uint64(ts.Unix())
|
|
return h
|
|
}(), err: nil,
|
|
},
|
|
{
|
|
name: "incorrect prev randao",
|
|
payload: emptyPayload(),
|
|
err: blocks.ErrInvalidPayloadPrevRandao,
|
|
},
|
|
{
|
|
name: "incorrect timestamp",
|
|
payload: func() *enginev1.ExecutionPayload {
|
|
h := emptyPayload()
|
|
h.PrevRandao = random
|
|
h.Timestamp = 1
|
|
return h
|
|
}(),
|
|
err: blocks.ErrInvalidPayloadTimeStamp,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
wrappedPayload, err := consensusblocks.WrappedExecutionPayload(tt.payload)
|
|
require.NoError(t, err)
|
|
st, err := blocks.ProcessPayload(st, wrappedPayload)
|
|
if err != nil {
|
|
require.Equal(t, tt.err.Error(), err.Error())
|
|
} else {
|
|
require.Equal(t, tt.err, err)
|
|
want, err := consensusblocks.PayloadToHeader(wrappedPayload)
|
|
require.Equal(t, tt.err, err)
|
|
h, err := st.LatestExecutionPayloadHeader()
|
|
require.NoError(t, err)
|
|
got, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
require.DeepSSZEqual(t, want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_ProcessPayloadHeader(t *testing.T) {
|
|
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
|
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
|
require.NoError(t, err)
|
|
ts, err := slots.ToTime(st.GenesisTime(), st.Slot())
|
|
require.NoError(t, err)
|
|
tests := []struct {
|
|
name string
|
|
header interfaces.ExecutionData
|
|
err error
|
|
}{
|
|
{
|
|
name: "process passes",
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.PrevRandao = random
|
|
p.Timestamp = uint64(ts.Unix())
|
|
return h
|
|
}(), err: nil,
|
|
},
|
|
{
|
|
name: "incorrect prev randao",
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
return h
|
|
}(),
|
|
err: blocks.ErrInvalidPayloadPrevRandao,
|
|
},
|
|
{
|
|
name: "incorrect timestamp",
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.PrevRandao = random
|
|
p.Timestamp = 1
|
|
return h
|
|
}(),
|
|
err: blocks.ErrInvalidPayloadTimeStamp,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
st, err := blocks.ProcessPayloadHeader(st, tt.header)
|
|
if err != nil {
|
|
require.Equal(t, tt.err.Error(), err.Error())
|
|
} else {
|
|
require.Equal(t, tt.err, err)
|
|
want, ok := tt.header.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
h, err := st.LatestExecutionPayloadHeader()
|
|
require.NoError(t, err)
|
|
got, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
require.DeepSSZEqual(t, want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_ValidatePayloadHeader(t *testing.T) {
|
|
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
|
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
|
require.NoError(t, err)
|
|
ts, err := slots.ToTime(st.GenesisTime(), st.Slot())
|
|
require.NoError(t, err)
|
|
tests := []struct {
|
|
name string
|
|
header interfaces.ExecutionData
|
|
err error
|
|
}{
|
|
{
|
|
name: "process passes",
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.PrevRandao = random
|
|
p.Timestamp = uint64(ts.Unix())
|
|
return h
|
|
}(), err: nil,
|
|
},
|
|
{
|
|
name: "incorrect prev randao",
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
return h
|
|
}(),
|
|
err: blocks.ErrInvalidPayloadPrevRandao,
|
|
},
|
|
{
|
|
name: "incorrect timestamp",
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.PrevRandao = random
|
|
p.Timestamp = 1
|
|
return h
|
|
}(),
|
|
err: blocks.ErrInvalidPayloadTimeStamp,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err = blocks.ValidatePayloadHeader(st, tt.header)
|
|
require.Equal(t, tt.err, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_ValidatePayloadHeaderWhenMergeCompletes(t *testing.T) {
|
|
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
|
|
emptySt := st.Copy()
|
|
wrappedHeader, err := consensusblocks.WrappedExecutionPayloadHeader(&enginev1.ExecutionPayloadHeader{BlockHash: []byte{'a'}})
|
|
require.NoError(t, err)
|
|
require.NoError(t, st.SetLatestExecutionPayloadHeader(wrappedHeader))
|
|
tests := []struct {
|
|
name string
|
|
state state.BeaconState
|
|
header interfaces.ExecutionData
|
|
err error
|
|
}{
|
|
{
|
|
name: "no merge",
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
return h
|
|
}(),
|
|
state: emptySt,
|
|
err: nil,
|
|
},
|
|
{
|
|
name: "process passes",
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.ParentHash = []byte{'a'}
|
|
return h
|
|
}(),
|
|
state: st,
|
|
err: nil,
|
|
},
|
|
{
|
|
name: "invalid block hash",
|
|
header: func() interfaces.ExecutionData {
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(t, err)
|
|
p, ok := h.Proto().(*enginev1.ExecutionPayloadHeader)
|
|
require.Equal(t, true, ok)
|
|
p.ParentHash = []byte{'b'}
|
|
return h
|
|
}(),
|
|
state: st,
|
|
err: blocks.ErrInvalidPayloadBlockHash,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err = blocks.ValidatePayloadHeaderWhenMergeCompletes(tt.state, tt.header)
|
|
require.Equal(t, tt.err, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_PayloadToHeader(t *testing.T) {
|
|
p := emptyPayload()
|
|
wrappedPayload, err := consensusblocks.WrappedExecutionPayload(p)
|
|
require.NoError(t, err)
|
|
h, err := consensusblocks.PayloadToHeader(wrappedPayload)
|
|
require.NoError(t, err)
|
|
txRoot, err := ssz.TransactionsRoot(p.Transactions)
|
|
require.NoError(t, err)
|
|
require.DeepSSZEqual(t, txRoot, bytesutil.ToBytes32(h.TransactionsRoot))
|
|
|
|
// Verify copy works
|
|
b := []byte{'a'}
|
|
p.ParentHash = b
|
|
p.FeeRecipient = b
|
|
p.StateRoot = b
|
|
p.ReceiptsRoot = b
|
|
p.LogsBloom = b
|
|
p.PrevRandao = b
|
|
p.ExtraData = b
|
|
p.BaseFeePerGas = b
|
|
p.BlockHash = b
|
|
p.BlockNumber = 1
|
|
p.GasUsed = 1
|
|
p.GasLimit = 1
|
|
p.Timestamp = 1
|
|
|
|
require.DeepSSZEqual(t, h.ParentHash, make([]byte, fieldparams.RootLength))
|
|
require.DeepSSZEqual(t, h.FeeRecipient, make([]byte, fieldparams.FeeRecipientLength))
|
|
require.DeepSSZEqual(t, h.StateRoot, make([]byte, fieldparams.RootLength))
|
|
require.DeepSSZEqual(t, h.ReceiptsRoot, make([]byte, fieldparams.RootLength))
|
|
require.DeepSSZEqual(t, h.LogsBloom, make([]byte, fieldparams.LogsBloomLength))
|
|
require.DeepSSZEqual(t, h.PrevRandao, make([]byte, fieldparams.RootLength))
|
|
require.DeepSSZEqual(t, h.ExtraData, make([]byte, 0))
|
|
require.DeepSSZEqual(t, h.BaseFeePerGas, make([]byte, fieldparams.RootLength))
|
|
require.DeepSSZEqual(t, h.BlockHash, make([]byte, fieldparams.RootLength))
|
|
require.Equal(t, h.BlockNumber, uint64(0))
|
|
require.Equal(t, h.GasUsed, uint64(0))
|
|
require.Equal(t, h.GasLimit, uint64(0))
|
|
require.Equal(t, h.Timestamp, uint64(0))
|
|
}
|
|
|
|
func BenchmarkBellatrixComplete(b *testing.B) {
|
|
st, _ := util.DeterministicGenesisStateBellatrix(b, 1)
|
|
h, err := emptyPayloadHeader()
|
|
require.NoError(b, err)
|
|
require.NoError(b, st.SetLatestExecutionPayloadHeader(h))
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_, err := blocks.IsMergeTransitionComplete(st)
|
|
require.NoError(b, err)
|
|
}
|
|
}
|
|
|
|
func emptyPayloadHeader() (interfaces.ExecutionData, error) {
|
|
return consensusblocks.WrappedExecutionPayloadHeader(&enginev1.ExecutionPayloadHeader{
|
|
ParentHash: make([]byte, fieldparams.RootLength),
|
|
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
|
StateRoot: make([]byte, fieldparams.RootLength),
|
|
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
|
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
|
|
PrevRandao: make([]byte, fieldparams.RootLength),
|
|
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
|
BlockHash: make([]byte, fieldparams.RootLength),
|
|
TransactionsRoot: make([]byte, fieldparams.RootLength),
|
|
ExtraData: make([]byte, 0),
|
|
})
|
|
}
|
|
|
|
func emptyPayload() *enginev1.ExecutionPayload {
|
|
return &enginev1.ExecutionPayload{
|
|
ParentHash: make([]byte, fieldparams.RootLength),
|
|
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
|
|
StateRoot: make([]byte, fieldparams.RootLength),
|
|
ReceiptsRoot: make([]byte, fieldparams.RootLength),
|
|
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
|
|
PrevRandao: make([]byte, fieldparams.RootLength),
|
|
BaseFeePerGas: make([]byte, fieldparams.RootLength),
|
|
BlockHash: make([]byte, fieldparams.RootLength),
|
|
Transactions: make([][]byte, 0),
|
|
ExtraData: make([]byte, 0),
|
|
}
|
|
}
|