process payload (#10054)

This commit is contained in:
terence tsao
2022-01-06 08:22:38 -08:00
committed by GitHub
parent d28ae62d02
commit a1a301ad5d
3 changed files with 173 additions and 0 deletions

View File

@@ -38,6 +38,7 @@ go_library(
"//crypto/bls:go_default_library",
"//crypto/hash:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//math:go_default_library",
"//network/forks:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
@@ -90,6 +91,7 @@ go_test(
"//container/trie:go_default_library",
"//crypto/bls:go_default_library",
"//encoding/bytesutil:go_default_library",
"//encoding/ssz:go_default_library",
"//proto/prysm/v1alpha1:go_default_library",
"//proto/prysm/v1alpha1/attestation:go_default_library",
"//proto/prysm/v1alpha1/attestation/aggregation:go_default_library",

View File

@@ -8,6 +8,8 @@ import (
"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"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
"github.com/prysmaticlabs/prysm/time/slots"
@@ -121,6 +123,82 @@ func ValidatePayload(st state.BeaconState, payload *ethpb.ExecutionPayload) erro
return nil
}
// ProcessPayload processes input execution payload using beacon state.
// ValidatePayloadWhenMergeCompletes validates if payload is valid versus input beacon state.
// These validation steps ONLY apply to post merge.
//
// Spec code:
// def process_execution_payload(state: BeaconState, payload: ExecutionPayload, execution_engine: ExecutionEngine) -> None:
// # Verify consistency of the parent hash with respect to the previous execution payload header
// if is_merge_complete(state):
// assert payload.parent_hash == state.latest_execution_payload_header.block_hash
// # Verify random
// assert payload.random == get_randao_mix(state, get_current_epoch(state))
// # Verify timestamp
// assert payload.timestamp == compute_timestamp_at_slot(state, state.slot)
// # Verify the execution payload is valid
// assert execution_engine.execute_payload(payload)
// # Cache execution payload header
// state.latest_execution_payload_header = ExecutionPayloadHeader(
// parent_hash=payload.parent_hash,
// FeeRecipient=payload.FeeRecipient,
// state_root=payload.state_root,
// receipt_root=payload.receipt_root,
// logs_bloom=payload.logs_bloom,
// random=payload.random,
// block_number=payload.block_number,
// gas_limit=payload.gas_limit,
// gas_used=payload.gas_used,
// timestamp=payload.timestamp,
// extra_data=payload.extra_data,
// base_fee_per_gas=payload.base_fee_per_gas,
// block_hash=payload.block_hash,
// transactions_root=hash_tree_root(payload.transactions),
// )
func ProcessPayload(st state.BeaconState, payload *ethpb.ExecutionPayload) (state.BeaconState, error) {
if err := ValidatePayloadWhenMergeCompletes(st, payload); err != nil {
return nil, err
}
if err := ValidatePayload(st, payload); err != nil {
return nil, err
}
header, err := PayloadToHeader(payload)
if err != nil {
return nil, err
}
if err := st.SetLatestExecutionPayloadHeader(header); err != nil {
return nil, err
}
return st, nil
}
// PayloadToHeader converts `payload` into execution payload header format.
func PayloadToHeader(payload *ethpb.ExecutionPayload) (*ethpb.ExecutionPayloadHeader, error) {
txRoot, err := ssz.TransactionsRoot(payload.Transactions)
if err != nil {
return nil, err
}
return &ethpb.ExecutionPayloadHeader{
ParentHash: bytesutil.SafeCopyBytes(payload.ParentHash),
FeeRecipient: bytesutil.SafeCopyBytes(payload.FeeRecipient),
StateRoot: bytesutil.SafeCopyBytes(payload.StateRoot),
ReceiptRoot: bytesutil.SafeCopyBytes(payload.ReceiptRoot),
LogsBloom: bytesutil.SafeCopyBytes(payload.LogsBloom),
Random: bytesutil.SafeCopyBytes(payload.Random),
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
}
func isEmptyPayload(p *ethpb.ExecutionPayload) bool {
if !bytes.Equal(p.ParentHash, make([]byte, fieldparams.RootLength)) {
return false

View File

@@ -9,6 +9,7 @@ import (
"github.com/prysmaticlabs/prysm/beacon-chain/core/time"
fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams"
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
"github.com/prysmaticlabs/prysm/encoding/ssz"
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
"github.com/prysmaticlabs/prysm/testing/require"
@@ -517,6 +518,98 @@ func Test_ValidatePayload(t *testing.T) {
}
}
func Test_ProcessPayload(t *testing.T) {
st, _ := util.DeterministicGenesisStateMerge(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 *ethpb.ExecutionPayload
err error
}{
{
name: "process passes",
payload: func() *ethpb.ExecutionPayload {
h := emptyPayload()
h.Random = random
h.Timestamp = uint64(ts.Unix())
return h
}(), err: nil,
},
{
name: "incorrect random",
payload: emptyPayload(),
err: errors.New("incorrect random"),
},
{
name: "incorrect timestamp",
payload: func() *ethpb.ExecutionPayload {
h := emptyPayload()
h.Random = random
h.Timestamp = 1
return h
}(),
err: errors.New("incorrect timestamp"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
st, err := blocks.ProcessPayload(st, tt.payload)
if err != nil {
require.Equal(t, tt.err.Error(), err.Error())
} else {
require.Equal(t, tt.err, err)
want, err := blocks.PayloadToHeader(tt.payload)
require.Equal(t, tt.err, err)
got, err := st.LatestExecutionPayloadHeader()
require.NoError(t, err)
require.DeepSSZEqual(t, want, got)
}
})
}
}
func Test_PayloadToHeader(t *testing.T) {
p := emptyPayload()
h, err := blocks.PayloadToHeader(p)
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.ReceiptRoot = b
p.LogsBloom = b
p.Random = 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.ReceiptRoot, make([]byte, fieldparams.RootLength))
require.DeepSSZEqual(t, h.LogsBloom, make([]byte, fieldparams.LogsBloomLength))
require.DeepSSZEqual(t, h.Random, 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 BenchmarkMergeComplete(b *testing.B) {
st, _ := util.DeterministicGenesisStateMerge(b, 1)
require.NoError(b, st.SetLatestExecutionPayloadHeader(emptyPayloadHeader()))