Files
prysm/consensus-types/wrapper/execution.go
Potuz 4b083c2ca9 Fix IsExecutionEnabled for blinded blocks (#11076)
* Fix IsExecutionEnabled for blinded blocks

The TransactionsRoot of a blinded block may be non-zero, anyway we do
not insert the header in the state until IsExecutionEnabled is true.
This last check was failing on blinded blocks because it was actively
checking that the root should be zero, when it needn't be.

Superseeds #11068

* fix test

* test case

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-07-19 20:45:45 +00:00

352 lines
8.6 KiB
Go

package wrapper
import (
"bytes"
"github.com/pkg/errors"
fastssz "github.com/prysmaticlabs/fastssz"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/consensus-types/interfaces"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/encoding/ssz"
enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1"
"google.golang.org/protobuf/proto"
)
// executionPayload is a convenience wrapper around a beacon block body's execution payload data structure
// This wrapper allows us to conform to a common interface so that beacon
// blocks for future forks can also be applied across Prysm without issues.
type executionPayload struct {
p *enginev1.ExecutionPayload
}
// WrappedExecutionPayload is a constructor which wraps a protobuf execution payload into an interface.
func WrappedExecutionPayload(p *enginev1.ExecutionPayload) (interfaces.ExecutionData, error) {
w := executionPayload{p: p}
if w.IsNil() {
return nil, ErrNilObjectWrapped
}
return w, nil
}
// IsNil checks if the underlying data is nil.
func (e executionPayload) IsNil() bool {
return e.p == nil
}
// MarshalSSZ --
func (e executionPayload) MarshalSSZ() ([]byte, error) {
return e.p.MarshalSSZ()
}
// MarshalSSZTo --
func (e executionPayload) MarshalSSZTo(dst []byte) ([]byte, error) {
return e.p.MarshalSSZTo(dst)
}
// SizeSSZ --
func (e executionPayload) SizeSSZ() int {
return e.p.SizeSSZ()
}
// UnmarshalSSZ --
func (e executionPayload) UnmarshalSSZ(buf []byte) error {
return e.p.UnmarshalSSZ(buf)
}
// HashTreeRoot --
func (e executionPayload) HashTreeRoot() ([32]byte, error) {
return e.p.HashTreeRoot()
}
// HashTreeRootWith --
func (e executionPayload) HashTreeRootWith(hh *fastssz.Hasher) error {
return e.p.HashTreeRootWith(hh)
}
// Proto --
func (e executionPayload) Proto() proto.Message {
return e.p
}
// ParentHash --
func (e executionPayload) ParentHash() []byte {
return e.p.ParentHash
}
// FeeRecipient --
func (e executionPayload) FeeRecipient() []byte {
return e.p.FeeRecipient
}
// StateRoot --
func (e executionPayload) StateRoot() []byte {
return e.p.StateRoot
}
// ReceiptsRoot --
func (e executionPayload) ReceiptsRoot() []byte {
return e.p.ReceiptsRoot
}
// LogsBloom --
func (e executionPayload) LogsBloom() []byte {
return e.p.LogsBloom
}
// PrevRandao --
func (e executionPayload) PrevRandao() []byte {
return e.p.PrevRandao
}
// BlockNumber --
func (e executionPayload) BlockNumber() uint64 {
return e.p.BlockNumber
}
// GasLimit --
func (e executionPayload) GasLimit() uint64 {
return e.p.GasLimit
}
// GasUsed --
func (e executionPayload) GasUsed() uint64 {
return e.p.GasUsed
}
// Timestamp --
func (e executionPayload) Timestamp() uint64 {
return e.p.Timestamp
}
// ExtraData --
func (e executionPayload) ExtraData() []byte {
return e.p.ExtraData
}
// BaseFeePerGas --
func (e executionPayload) BaseFeePerGas() []byte {
return e.p.BaseFeePerGas
}
// BlockHash --
func (e executionPayload) BlockHash() []byte {
return e.p.BlockHash
}
// Transactions --
func (e executionPayload) Transactions() ([][]byte, error) {
return e.p.Transactions, nil
}
// executionPayloadHeader is a convenience wrapper around a blinded beacon block body's execution header data structure
// This wrapper allows us to conform to a common interface so that beacon
// blocks for future forks can also be applied across Prysm without issues.
type executionPayloadHeader struct {
p *enginev1.ExecutionPayloadHeader
}
// WrappedExecutionPayloadHeader is a constructor which wraps a protobuf execution header into an interface.
func WrappedExecutionPayloadHeader(p *enginev1.ExecutionPayloadHeader) (interfaces.ExecutionData, error) {
w := executionPayloadHeader{p: p}
if w.IsNil() {
return nil, ErrNilObjectWrapped
}
return w, nil
}
// IsNil checks if the underlying data is nil.
func (e executionPayloadHeader) IsNil() bool {
return e.p == nil
}
// MarshalSSZ --
func (e executionPayloadHeader) MarshalSSZ() ([]byte, error) {
return e.p.MarshalSSZ()
}
// MarshalSSZTo --
func (e executionPayloadHeader) MarshalSSZTo(dst []byte) ([]byte, error) {
return e.p.MarshalSSZTo(dst)
}
// SizeSSZ --
func (e executionPayloadHeader) SizeSSZ() int {
return e.p.SizeSSZ()
}
// UnmarshalSSZ --
func (e executionPayloadHeader) UnmarshalSSZ(buf []byte) error {
return e.p.UnmarshalSSZ(buf)
}
// HashTreeRoot --
func (e executionPayloadHeader) HashTreeRoot() ([32]byte, error) {
return e.p.HashTreeRoot()
}
// HashTreeRootWith --
func (e executionPayloadHeader) HashTreeRootWith(hh *fastssz.Hasher) error {
return e.p.HashTreeRootWith(hh)
}
// Proto --
func (e executionPayloadHeader) Proto() proto.Message {
return e.p
}
// ParentHash --
func (e executionPayloadHeader) ParentHash() []byte {
return e.p.ParentHash
}
// FeeRecipient --
func (e executionPayloadHeader) FeeRecipient() []byte {
return e.p.FeeRecipient
}
// StateRoot --
func (e executionPayloadHeader) StateRoot() []byte {
return e.p.StateRoot
}
// ReceiptsRoot --
func (e executionPayloadHeader) ReceiptsRoot() []byte {
return e.p.ReceiptsRoot
}
// LogsBloom --
func (e executionPayloadHeader) LogsBloom() []byte {
return e.p.LogsBloom
}
// PrevRandao --
func (e executionPayloadHeader) PrevRandao() []byte {
return e.p.PrevRandao
}
// BlockNumber --
func (e executionPayloadHeader) BlockNumber() uint64 {
return e.p.BlockNumber
}
// GasLimit --
func (e executionPayloadHeader) GasLimit() uint64 {
return e.p.GasLimit
}
// GasUsed --
func (e executionPayloadHeader) GasUsed() uint64 {
return e.p.GasUsed
}
// Timestamp --
func (e executionPayloadHeader) Timestamp() uint64 {
return e.p.Timestamp
}
// ExtraData --
func (e executionPayloadHeader) ExtraData() []byte {
return e.p.ExtraData
}
// BaseFeePerGas --
func (e executionPayloadHeader) BaseFeePerGas() []byte {
return e.p.BaseFeePerGas
}
// BlockHash --
func (e executionPayloadHeader) BlockHash() []byte {
return e.p.BlockHash
}
// Transactions --
func (executionPayloadHeader) Transactions() ([][]byte, error) {
return nil, ErrUnsupportedField
}
// PayloadToHeader converts `payload` into execution payload header format.
func PayloadToHeader(payload interfaces.ExecutionData) (*enginev1.ExecutionPayloadHeader, error) {
txs, err := payload.Transactions()
if err != nil {
return nil, err
}
txRoot, err := ssz.TransactionsRoot(txs)
if err != nil {
return nil, err
}
return &enginev1.ExecutionPayloadHeader{
ParentHash: bytesutil.SafeCopyBytes(payload.ParentHash()),
FeeRecipient: bytesutil.SafeCopyBytes(payload.FeeRecipient()),
StateRoot: bytesutil.SafeCopyBytes(payload.StateRoot()),
ReceiptsRoot: bytesutil.SafeCopyBytes(payload.ReceiptsRoot()),
LogsBloom: bytesutil.SafeCopyBytes(payload.LogsBloom()),
PrevRandao: bytesutil.SafeCopyBytes(payload.PrevRandao()),
BlockNumber: payload.BlockNumber(),
GasLimit: payload.GasLimit(),
GasUsed: payload.GasUsed(),
Timestamp: payload.Timestamp(),
ExtraData: bytesutil.SafeCopyBytes(payload.ExtraData()),
BaseFeePerGas: bytesutil.SafeCopyBytes(payload.BaseFeePerGas()),
BlockHash: bytesutil.SafeCopyBytes(payload.BlockHash()),
TransactionsRoot: txRoot[:],
}, nil
}
// IsEmptyExecutionData checks if an execution data is empty underneath. If a single field has
// a non-zero value, this function will return false.
func IsEmptyExecutionData(data interfaces.ExecutionData) (bool, error) {
if !bytes.Equal(data.ParentHash(), make([]byte, fieldparams.RootLength)) {
return false, nil
}
if !bytes.Equal(data.FeeRecipient(), make([]byte, fieldparams.FeeRecipientLength)) {
return false, nil
}
if !bytes.Equal(data.StateRoot(), make([]byte, fieldparams.RootLength)) {
return false, nil
}
if !bytes.Equal(data.ReceiptsRoot(), make([]byte, fieldparams.RootLength)) {
return false, nil
}
if !bytes.Equal(data.LogsBloom(), make([]byte, fieldparams.LogsBloomLength)) {
return false, nil
}
if !bytes.Equal(data.PrevRandao(), make([]byte, fieldparams.RootLength)) {
return false, nil
}
if !bytes.Equal(data.BaseFeePerGas(), make([]byte, fieldparams.RootLength)) {
return false, nil
}
if !bytes.Equal(data.BlockHash(), make([]byte, fieldparams.RootLength)) {
return false, nil
}
txs, err := data.Transactions()
switch {
case errors.Is(err, ErrUnsupportedField):
case err != nil:
return false, err
default:
if len(txs) != 0 {
return false, nil
}
}
if len(data.ExtraData()) != 0 {
return false, nil
}
if data.BlockNumber() != 0 {
return false, nil
}
if data.GasLimit() != 0 {
return false, nil
}
if data.GasUsed() != 0 {
return false, nil
}
if data.Timestamp() != 0 {
return false, nil
}
return true, nil
}