mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 21:08:10 -05:00
Add process payload header (#10529)
* Add process payload header * Update block.go * Remove unused receivers * Use errors vars * Add some comments * Add some comments
This commit is contained in:
@@ -18,6 +18,12 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/time/slots"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidPayloadBlockHash = errors.New("invalid payload block hash")
|
||||
ErrInvalidPayloadTimeStamp = errors.New("invalid payload timestamp")
|
||||
ErrInvalidPayloadPrevRandao = errors.New("invalid payload previous randao")
|
||||
)
|
||||
|
||||
// IsMergeTransitionComplete returns true if the transition to Bellatrix has completed.
|
||||
// Meaning the payload header in beacon state is not `ExecutionPayloadHeader()` (i.e. not empty).
|
||||
//
|
||||
@@ -146,14 +152,14 @@ func ValidatePayload(st state.BeaconState, payload *enginev1.ExecutionPayload) e
|
||||
}
|
||||
|
||||
if !bytes.Equal(payload.PrevRandao, random) {
|
||||
return errors.New("incorrect prev randao")
|
||||
return ErrInvalidPayloadPrevRandao
|
||||
}
|
||||
t, err := slots.ToTime(st.GenesisTime(), st.Slot())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if payload.Timestamp != uint64(t.Unix()) {
|
||||
return errors.New("incorrect timestamp")
|
||||
return ErrInvalidPayloadTimeStamp
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -328,3 +334,62 @@ func isEmptyHeader(h *ethpb.ExecutionPayloadHeader) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ValidatePayloadHeaderWhenMergeCompletes validates the payload header when the merge completes.
|
||||
func ValidatePayloadHeaderWhenMergeCompletes(st state.BeaconState, header *ethpb.ExecutionPayloadHeader) error {
|
||||
// Skip validation if the state is not merge compatible.
|
||||
complete, err := IsMergeTransitionComplete(st)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !complete {
|
||||
return nil
|
||||
}
|
||||
// Validate current header's parent hash matches state header's block hash.
|
||||
h, err := st.LatestExecutionPayloadHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(header.ParentHash, h.BlockHash) {
|
||||
return ErrInvalidPayloadBlockHash
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidatePayloadHeader validates the payload header.
|
||||
func ValidatePayloadHeader(st state.BeaconState, header *ethpb.ExecutionPayloadHeader) error {
|
||||
// Validate header's random mix matches with state in current epoch
|
||||
random, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(header.PrevRandao, random) {
|
||||
return ErrInvalidPayloadPrevRandao
|
||||
}
|
||||
|
||||
// Validate header's timestamp matches with state in current slot.
|
||||
t, err := slots.ToTime(st.GenesisTime(), st.Slot())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if header.Timestamp != uint64(t.Unix()) {
|
||||
return ErrInvalidPayloadTimeStamp
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProcessPayloadHeader processes the payload header.
|
||||
func ProcessPayloadHeader(st state.BeaconState, header *ethpb.ExecutionPayloadHeader) (state.BeaconState, error) {
|
||||
if err := ValidatePayloadHeaderWhenMergeCompletes(st, header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := ValidatePayloadHeader(st, header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := st.SetLatestExecutionPayloadHeader(header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/encoding/ssz"
|
||||
@@ -600,7 +601,7 @@ func Test_ValidatePayload(t *testing.T) {
|
||||
{
|
||||
name: "incorrect prev randao",
|
||||
payload: emptyPayload(),
|
||||
err: errors.New("incorrect prev randao"),
|
||||
err: blocks.ErrInvalidPayloadPrevRandao,
|
||||
},
|
||||
{
|
||||
name: "incorrect timestamp",
|
||||
@@ -610,7 +611,7 @@ func Test_ValidatePayload(t *testing.T) {
|
||||
h.Timestamp = 1
|
||||
return h
|
||||
}(),
|
||||
err: errors.New("incorrect timestamp"),
|
||||
err: blocks.ErrInvalidPayloadTimeStamp,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -648,7 +649,7 @@ func Test_ProcessPayload(t *testing.T) {
|
||||
{
|
||||
name: "incorrect prev randao",
|
||||
payload: emptyPayload(),
|
||||
err: errors.New("incorrect prev randao"),
|
||||
err: blocks.ErrInvalidPayloadPrevRandao,
|
||||
},
|
||||
{
|
||||
name: "incorrect timestamp",
|
||||
@@ -658,7 +659,7 @@ func Test_ProcessPayload(t *testing.T) {
|
||||
h.Timestamp = 1
|
||||
return h
|
||||
}(),
|
||||
err: errors.New("incorrect timestamp"),
|
||||
err: blocks.ErrInvalidPayloadTimeStamp,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -678,6 +679,149 @@ func Test_ProcessPayload(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
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 *ethpb.ExecutionPayloadHeader
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "process passes",
|
||||
header: func() *ethpb.ExecutionPayloadHeader {
|
||||
h := emptyPayloadHeader()
|
||||
h.PrevRandao = random
|
||||
h.Timestamp = uint64(ts.Unix())
|
||||
return h
|
||||
}(), err: nil,
|
||||
},
|
||||
{
|
||||
name: "incorrect prev randao",
|
||||
header: emptyPayloadHeader(),
|
||||
err: blocks.ErrInvalidPayloadPrevRandao,
|
||||
},
|
||||
{
|
||||
name: "incorrect timestamp",
|
||||
header: func() *ethpb.ExecutionPayloadHeader {
|
||||
h := emptyPayloadHeader()
|
||||
h.PrevRandao = random
|
||||
h.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)
|
||||
got, err := st.LatestExecutionPayloadHeader()
|
||||
require.NoError(t, err)
|
||||
require.DeepSSZEqual(t, tt.header, 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 *ethpb.ExecutionPayloadHeader
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "process passes",
|
||||
header: func() *ethpb.ExecutionPayloadHeader {
|
||||
h := emptyPayloadHeader()
|
||||
h.PrevRandao = random
|
||||
h.Timestamp = uint64(ts.Unix())
|
||||
return h
|
||||
}(), err: nil,
|
||||
},
|
||||
{
|
||||
name: "incorrect prev randao",
|
||||
header: emptyPayloadHeader(),
|
||||
err: blocks.ErrInvalidPayloadPrevRandao,
|
||||
},
|
||||
{
|
||||
name: "incorrect timestamp",
|
||||
header: func() *ethpb.ExecutionPayloadHeader {
|
||||
h := emptyPayloadHeader()
|
||||
h.PrevRandao = random
|
||||
h.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()
|
||||
require.NoError(t, st.SetLatestExecutionPayloadHeader(ðpb.ExecutionPayloadHeader{BlockHash: []byte{'a'}}))
|
||||
tests := []struct {
|
||||
name string
|
||||
state state.BeaconState
|
||||
header *ethpb.ExecutionPayloadHeader
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "no merge",
|
||||
header: func() *ethpb.ExecutionPayloadHeader {
|
||||
h := emptyPayloadHeader()
|
||||
return h
|
||||
}(),
|
||||
state: emptySt,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "process passes",
|
||||
header: func() *ethpb.ExecutionPayloadHeader {
|
||||
h := emptyPayloadHeader()
|
||||
h.ParentHash = []byte{'a'}
|
||||
return h
|
||||
}(),
|
||||
state: st,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "invalid block hash",
|
||||
header: func() *ethpb.ExecutionPayloadHeader {
|
||||
h := emptyPayloadHeader()
|
||||
h.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()
|
||||
h, err := blocks.PayloadToHeader(p)
|
||||
|
||||
@@ -290,13 +290,24 @@ func ProcessBlockForStateRoot(
|
||||
return nil, errors.Wrap(err, "could not check if execution is enabled")
|
||||
}
|
||||
if enabled {
|
||||
payload, err := blk.Body().ExecutionPayload()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state, err = b.ProcessPayload(state, payload)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process execution payload")
|
||||
if blk.IsBlinded() {
|
||||
header, err := blk.Body().ExecutionPayloadHeader()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state, err = b.ProcessPayloadHeader(state, header)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process execution payload header")
|
||||
}
|
||||
} else {
|
||||
payload, err := blk.Body().ExecutionPayload()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state, err = b.ProcessPayload(state, payload)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process execution payload")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ type BeaconBlock interface {
|
||||
StateRoot() []byte
|
||||
Body() BeaconBlockBody
|
||||
IsNil() bool
|
||||
IsBlinded() bool
|
||||
HashTreeRoot() ([32]byte, error)
|
||||
Proto() proto.Message
|
||||
ssz.Marshaler
|
||||
|
||||
@@ -117,6 +117,10 @@ func (BeaconBlock) IsNil() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (BeaconBlock) IsBlinded() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (BeaconBlock) Proto() proto.Message {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
@@ -183,6 +183,11 @@ func (w altairBeaconBlock) IsNil() bool {
|
||||
return w.b == nil
|
||||
}
|
||||
|
||||
// IsBlinded checks if the beacon block is a blinded block.
|
||||
func (altairBeaconBlock) IsBlinded() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// HashTreeRoot returns the ssz root of the block.
|
||||
func (w altairBeaconBlock) HashTreeRoot() ([32]byte, error) {
|
||||
return w.b.HashTreeRoot()
|
||||
|
||||
@@ -159,6 +159,12 @@ func TestAltairBeaconBlock_IsNil(t *testing.T) {
|
||||
assert.Equal(t, false, wb.IsNil())
|
||||
}
|
||||
|
||||
func TestAltairBeaconBlock_IsBlinded(t *testing.T) {
|
||||
wsb, err := wrapper.WrappedBeaconBlock(ðpb.BeaconBlockAltair{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, wsb.IsNil())
|
||||
}
|
||||
|
||||
func TestAltairBeaconBlock_HashTreeRoot(t *testing.T) {
|
||||
wb, err := wrapper.WrappedAltairBeaconBlock(util.HydrateBeaconBlockAltair(ðpb.BeaconBlockAltair{}))
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -178,6 +178,11 @@ func (w bellatrixBeaconBlock) IsNil() bool {
|
||||
return w.b == nil
|
||||
}
|
||||
|
||||
// IsBlinded checks if the beacon block is a blinded block.
|
||||
func (bellatrixBeaconBlock) IsBlinded() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// HashTreeRoot returns the ssz root of the block.
|
||||
func (w bellatrixBeaconBlock) HashTreeRoot() ([32]byte, error) {
|
||||
return w.b.HashTreeRoot()
|
||||
|
||||
@@ -191,6 +191,12 @@ func TestBellatrixBeaconBlock_IsNil(t *testing.T) {
|
||||
assert.Equal(t, false, wb.IsNil())
|
||||
}
|
||||
|
||||
func TesTBellatrixBeaconBlock_IsBlinded(t *testing.T) {
|
||||
wsb, err := wrapper.WrappedBeaconBlock(ðpb.BeaconBlockBellatrix{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, wsb.IsNil())
|
||||
}
|
||||
|
||||
func TestBellatrixBeaconBlock_HashTreeRoot(t *testing.T) {
|
||||
wb, err := wrapper.WrappedBellatrixBeaconBlock(util.HydrateBeaconBlockBellatrix(ðpb.BeaconBlockBellatrix{}))
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -175,6 +175,11 @@ func (w Phase0BeaconBlock) IsNil() bool {
|
||||
return w.b == nil || w.Body().IsNil()
|
||||
}
|
||||
|
||||
// IsBlinded checks if the beacon block is a blinded block.
|
||||
func (Phase0BeaconBlock) IsBlinded() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// HashTreeRoot returns the ssz root of the block.
|
||||
func (w Phase0BeaconBlock) HashTreeRoot() ([32]byte, error) {
|
||||
return w.b.HashTreeRoot()
|
||||
|
||||
@@ -179,6 +179,11 @@ func (w blindedBeaconBlockBellatrix) IsNil() bool {
|
||||
return w.b == nil
|
||||
}
|
||||
|
||||
// IsBlinded checks if the beacon block is a blinded block.
|
||||
func (blindedBeaconBlockBellatrix) IsBlinded() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// HashTreeRoot returns the ssz root of the block.
|
||||
func (w blindedBeaconBlockBellatrix) HashTreeRoot() ([32]byte, error) {
|
||||
return w.b.HashTreeRoot()
|
||||
|
||||
@@ -202,6 +202,13 @@ func TestBellatrixBlindedBeaconBlock_IsNil(t *testing.T) {
|
||||
assert.Equal(t, false, wb.IsNil())
|
||||
}
|
||||
|
||||
func TestBellatrixBlindedBeaconBlock_IsBlinded(t *testing.T) {
|
||||
wb, err := wrapper.WrappedBeaconBlock(ðpb.BlindedBeaconBlockBellatrix{})
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, true, wb.IsBlinded())
|
||||
}
|
||||
|
||||
func TestBellatrixBlindedBeaconBlock_HashTreeRoot(t *testing.T) {
|
||||
wb, err := wrapper.WrappedBeaconBlock(util.HydrateBlindedBeaconBlockBellatrix(ðpb.BlindedBeaconBlockBellatrix{}))
|
||||
require.NoError(t, err)
|
||||
|
||||
Reference in New Issue
Block a user