prysm-pulse/beacon-chain/core/blocks/payload.go
terence tsao bfc90e9abb
Add is_merge_block helper (#10026)
* Add merge complete helper

* Update BUILD.bazel

* minimal

* Add is_merge_block helper

* rename to `IsMergeBlock`
2021-12-22 15:52:50 +00:00

141 lines
3.6 KiB
Go

package blocks
import (
"bytes"
"github.com/prysmaticlabs/prysm/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
)
// MergeComplete returns true if the transition to merge has completed.
// Meaning the header header in beacon state is not `ExecutionPayloadHeader()` (i.e. not empty).
//
// Spec code:
// def is_merge_complete(state: BeaconState) -> bool:
// return state.latest_execution_payload_header != ExecutionPayloadHeader()
func MergeComplete(st state.BeaconState) (bool, error) {
h, err := st.LatestExecutionPayloadHeader()
if err != nil {
return false, err
}
return !isEmptyHeader(h), nil
}
// IsMergeBlock returns true if the input block is the terminal merge block.
// Meaning the header header in beacon state is `ExecutionPayloadHeader()` (i.e. empty).
// And the input block has a non-empty header.
//
// Spec code:
// def is_merge_block(state: BeaconState, body: BeaconBlockBody) -> bool:
// return not is_merge_complete(state) and body.execution_payload != ExecutionPayload()
func IsMergeBlock(st state.BeaconState, blk block.BeaconBlockBody) (bool, error) {
mergeComplete, err := MergeComplete(st)
if err != nil {
return false, err
}
if mergeComplete {
return false, err
}
payload, err := blk.ExecutionPayload()
if err != nil {
return false, err
}
return !isEmptyPayload(payload), nil
}
func isEmptyPayload(p *ethpb.ExecutionPayload) bool {
if !bytes.Equal(p.ParentHash, make([]byte, fieldparams.RootLength)) {
return false
}
if !bytes.Equal(p.FeeRecipient, make([]byte, fieldparams.FeeRecipientLength)) {
return false
}
if !bytes.Equal(p.StateRoot, make([]byte, fieldparams.RootLength)) {
return false
}
if !bytes.Equal(p.ReceiptRoot, make([]byte, fieldparams.RootLength)) {
return false
}
if !bytes.Equal(p.LogsBloom, make([]byte, fieldparams.LogsBloomLength)) {
return false
}
if !bytes.Equal(p.Random, make([]byte, fieldparams.RootLength)) {
return false
}
if !bytes.Equal(p.BaseFeePerGas, make([]byte, fieldparams.RootLength)) {
return false
}
if !bytes.Equal(p.BlockHash, make([]byte, fieldparams.RootLength)) {
return false
}
if p.Transactions != nil {
return false
}
if p.ExtraData != nil {
return false
}
if p.BlockNumber != 0 {
return false
}
if p.GasLimit != 0 {
return false
}
if p.GasUsed != 0 {
return false
}
if p.Timestamp != 0 {
return false
}
return true
}
func isEmptyHeader(h *ethpb.ExecutionPayloadHeader) bool {
if !bytes.Equal(h.ParentHash, make([]byte, fieldparams.RootLength)) {
return false
}
if !bytes.Equal(h.FeeRecipient, make([]byte, fieldparams.FeeRecipientLength)) {
return false
}
if !bytes.Equal(h.StateRoot, make([]byte, fieldparams.RootLength)) {
return false
}
if !bytes.Equal(h.ReceiptRoot, make([]byte, fieldparams.RootLength)) {
return false
}
if !bytes.Equal(h.LogsBloom, make([]byte, fieldparams.LogsBloomLength)) {
return false
}
if !bytes.Equal(h.Random, make([]byte, fieldparams.RootLength)) {
return false
}
if !bytes.Equal(h.BaseFeePerGas, make([]byte, fieldparams.RootLength)) {
return false
}
if !bytes.Equal(h.BlockHash, make([]byte, fieldparams.RootLength)) {
return false
}
if !bytes.Equal(h.TransactionsRoot, make([]byte, fieldparams.RootLength)) {
return false
}
if h.ExtraData != nil {
return false
}
if h.BlockNumber != 0 {
return false
}
if h.GasLimit != 0 {
return false
}
if h.GasUsed != 0 {
return false
}
if h.Timestamp != 0 {
return false
}
return true
}