mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-31 08:08:18 -05:00
Compare commits
1 Commits
simplify-p
...
payload-at
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a49546598 |
32
beacon-chain/operations/payloadattestation/BUILD.bazel
Normal file
32
beacon-chain/operations/payloadattestation/BUILD.bazel
Normal file
@@ -0,0 +1,32 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["pool.go"],
|
||||
importpath = "github.com/OffchainLabs/prysm/v7/beacon-chain/operations/payloadattestation",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//crypto/hash:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@org_golang_google_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["pool_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
],
|
||||
)
|
||||
179
beacon-chain/operations/payloadattestation/pool.go
Normal file
179
beacon-chain/operations/payloadattestation/pool.go
Normal file
@@ -0,0 +1,179 @@
|
||||
package payloadattestation
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/OffchainLabs/go-bitfield"
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/hash"
|
||||
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var errNilPayloadAttestationMessage = errors.New("nil payload attestation message")
|
||||
|
||||
// PoolManager maintains pending payload attestations.
|
||||
// This pool is used by proposers to insert payload attestations into new blocks.
|
||||
type PoolManager interface {
|
||||
// PendingPayloadAttestations returns all pending aggregated payload attestations.
|
||||
// If a slot is provided, only attestations for that slot are returned.
|
||||
PendingPayloadAttestations(slot ...primitives.Slot) []*ethpb.PayloadAttestation
|
||||
// InsertPayloadAttestation inserts or aggregates a payload attestation
|
||||
// message into the pool. The idx parameter is the PTC committee index
|
||||
// of the validator (position in the bitvector).
|
||||
InsertPayloadAttestation(msg *ethpb.PayloadAttestationMessage, idx uint64) error
|
||||
// Seen returns true if the PTC committee index has already been seen
|
||||
// for the given PayloadAttestationData.
|
||||
Seen(data *ethpb.PayloadAttestationData, idx uint64) bool
|
||||
// MarkIncluded removes the attestation matching the given data from the pool.
|
||||
MarkIncluded(att *ethpb.PayloadAttestation)
|
||||
}
|
||||
|
||||
// Pool is a concrete implementation of PoolManager.
|
||||
// Keyed by hash of PayloadAttestationData; stores aggregated PayloadAttestation.
|
||||
type Pool struct {
|
||||
lock sync.RWMutex
|
||||
pending map[[32]byte]*ethpb.PayloadAttestation
|
||||
}
|
||||
|
||||
// NewPool returns an initialized pool.
|
||||
func NewPool() *Pool {
|
||||
return &Pool{
|
||||
pending: make(map[[32]byte]*ethpb.PayloadAttestation),
|
||||
}
|
||||
}
|
||||
|
||||
// PendingPayloadAttestations returns all pending payload attestations.
|
||||
// If a slot filter is provided, only attestations for that slot are returned.
|
||||
func (p *Pool) PendingPayloadAttestations(slot ...primitives.Slot) []*ethpb.PayloadAttestation {
|
||||
p.lock.RLock()
|
||||
defer p.lock.RUnlock()
|
||||
|
||||
result := make([]*ethpb.PayloadAttestation, 0, len(p.pending))
|
||||
for _, att := range p.pending {
|
||||
if len(slot) > 0 && att.Data.Slot != slot[0] {
|
||||
continue
|
||||
}
|
||||
result = append(result, att)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// InsertPayloadAttestation inserts a payload attestation message into the pool,
|
||||
// aggregating it with any existing attestation that shares the same PayloadAttestationData.
|
||||
// The idx parameter is the PTC committee index used to set the aggregation bit.
|
||||
func (p *Pool) InsertPayloadAttestation(msg *ethpb.PayloadAttestationMessage, idx uint64) error {
|
||||
if msg == nil || msg.Data == nil {
|
||||
return errNilPayloadAttestationMessage
|
||||
}
|
||||
|
||||
key, err := dataKey(msg.Data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not compute data key")
|
||||
}
|
||||
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
existing, ok := p.pending[key]
|
||||
if !ok {
|
||||
p.pending[key] = messageToPayloadAttestation(msg, idx)
|
||||
return nil
|
||||
}
|
||||
|
||||
if existing.AggregationBits.BitAt(idx) {
|
||||
return nil
|
||||
}
|
||||
|
||||
sig, err := aggregateSigFromMessage(existing, msg)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not aggregate signatures")
|
||||
}
|
||||
existing.Signature = sig
|
||||
existing.AggregationBits.SetBitAt(idx, true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Seen returns true if the PTC committee index has already been seen
|
||||
// for the given PayloadAttestationData.
|
||||
func (p *Pool) Seen(data *ethpb.PayloadAttestationData, idx uint64) bool {
|
||||
if data == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
key, err := dataKey(data)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
p.lock.RLock()
|
||||
defer p.lock.RUnlock()
|
||||
|
||||
existing, ok := p.pending[key]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return existing.AggregationBits.BitAt(idx)
|
||||
}
|
||||
|
||||
// MarkIncluded removes the attestation with matching data from the pool.
|
||||
func (p *Pool) MarkIncluded(att *ethpb.PayloadAttestation) {
|
||||
if att == nil || att.Data == nil {
|
||||
return
|
||||
}
|
||||
|
||||
key, err := dataKey(att.Data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
delete(p.pending, key)
|
||||
}
|
||||
|
||||
// messageToPayloadAttestation creates a PayloadAttestation with a single
|
||||
// aggregated bit from the passed PayloadAttestationMessage.
|
||||
func messageToPayloadAttestation(msg *ethpb.PayloadAttestationMessage, idx uint64) *ethpb.PayloadAttestation {
|
||||
bits := bitfield.NewBitvector512()
|
||||
bits.SetBitAt(idx, true)
|
||||
data := ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: bytesutil.SafeCopyBytes(msg.Data.BeaconBlockRoot),
|
||||
Slot: msg.Data.Slot,
|
||||
PayloadPresent: msg.Data.PayloadPresent,
|
||||
BlobDataAvailable: msg.Data.BlobDataAvailable,
|
||||
}
|
||||
return ðpb.PayloadAttestation{
|
||||
AggregationBits: bits,
|
||||
Data: data,
|
||||
Signature: bytesutil.SafeCopyBytes(msg.Signature),
|
||||
}
|
||||
}
|
||||
|
||||
// aggregateSigFromMessage returns the aggregated signature by combining the
|
||||
// existing aggregated signature with the message's signature.
|
||||
func aggregateSigFromMessage(aggregated *ethpb.PayloadAttestation, message *ethpb.PayloadAttestationMessage) ([]byte, error) {
|
||||
aggSig, err := bls.SignatureFromBytesNoValidation(aggregated.Signature)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sig, err := bls.SignatureFromBytesNoValidation(message.Signature)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bls.AggregateSignatures([]bls.Signature{aggSig, sig}).Marshal(), nil
|
||||
}
|
||||
|
||||
// dataKey computes a deterministic key for PayloadAttestationData
|
||||
// by hashing its serialized form.
|
||||
func dataKey(data *ethpb.PayloadAttestationData) ([32]byte, error) {
|
||||
enc, err := proto.Marshal(data)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
return hash.Hash(enc), nil
|
||||
}
|
||||
291
beacon-chain/operations/payloadattestation/pool_test.go
Normal file
291
beacon-chain/operations/payloadattestation/pool_test.go
Normal file
@@ -0,0 +1,291 @@
|
||||
package payloadattestation
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
||||
"github.com/OffchainLabs/prysm/v7/crypto/bls"
|
||||
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/assert"
|
||||
"github.com/OffchainLabs/prysm/v7/testing/require"
|
||||
)
|
||||
|
||||
func TestPool_PendingPayloadAttestations(t *testing.T) {
|
||||
t.Run("empty pool", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
atts := pool.PendingPayloadAttestations()
|
||||
assert.Equal(t, 0, len(atts))
|
||||
})
|
||||
|
||||
t.Run("non-empty pool", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
sig := bls.NewAggregateSignature().Marshal()
|
||||
msg1 := ðpb.PayloadAttestationMessage{
|
||||
ValidatorIndex: 0,
|
||||
Data: ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Slot: 1,
|
||||
PayloadPresent: true,
|
||||
BlobDataAvailable: false,
|
||||
},
|
||||
Signature: sig,
|
||||
}
|
||||
msg2 := ðpb.PayloadAttestationMessage{
|
||||
ValidatorIndex: 1,
|
||||
Data: ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Slot: 2,
|
||||
PayloadPresent: false,
|
||||
BlobDataAvailable: true,
|
||||
},
|
||||
Signature: sig,
|
||||
}
|
||||
require.NoError(t, pool.InsertPayloadAttestation(msg1, 0))
|
||||
require.NoError(t, pool.InsertPayloadAttestation(msg2, 1))
|
||||
atts := pool.PendingPayloadAttestations()
|
||||
assert.Equal(t, 2, len(atts))
|
||||
})
|
||||
|
||||
t.Run("filter by slot", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
sig := bls.NewAggregateSignature().Marshal()
|
||||
msg1 := ðpb.PayloadAttestationMessage{
|
||||
ValidatorIndex: 0,
|
||||
Data: ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Slot: 1,
|
||||
PayloadPresent: true,
|
||||
BlobDataAvailable: false,
|
||||
},
|
||||
Signature: sig,
|
||||
}
|
||||
msg2 := ðpb.PayloadAttestationMessage{
|
||||
ValidatorIndex: 1,
|
||||
Data: ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Slot: 2,
|
||||
PayloadPresent: false,
|
||||
BlobDataAvailable: true,
|
||||
},
|
||||
Signature: sig,
|
||||
}
|
||||
require.NoError(t, pool.InsertPayloadAttestation(msg1, 0))
|
||||
require.NoError(t, pool.InsertPayloadAttestation(msg2, 1))
|
||||
|
||||
atts := pool.PendingPayloadAttestations(primitives.Slot(1))
|
||||
assert.Equal(t, 1, len(atts))
|
||||
assert.Equal(t, primitives.Slot(1), atts[0].Data.Slot)
|
||||
|
||||
atts = pool.PendingPayloadAttestations(primitives.Slot(2))
|
||||
assert.Equal(t, 1, len(atts))
|
||||
assert.Equal(t, primitives.Slot(2), atts[0].Data.Slot)
|
||||
|
||||
atts = pool.PendingPayloadAttestations(primitives.Slot(99))
|
||||
assert.Equal(t, 0, len(atts))
|
||||
})
|
||||
}
|
||||
|
||||
func TestPool_InsertPayloadAttestation(t *testing.T) {
|
||||
t.Run("nil message", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
err := pool.InsertPayloadAttestation(nil, 0)
|
||||
require.ErrorContains(t, "nil payload attestation message", err)
|
||||
})
|
||||
|
||||
t.Run("nil data", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
err := pool.InsertPayloadAttestation(ðpb.PayloadAttestationMessage{}, 0)
|
||||
require.ErrorContains(t, "nil payload attestation message", err)
|
||||
})
|
||||
|
||||
t.Run("insert creates new entry with correct aggregation bit", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
sig := bls.NewAggregateSignature().Marshal()
|
||||
idx := uint64(5)
|
||||
msg := ðpb.PayloadAttestationMessage{
|
||||
ValidatorIndex: 0,
|
||||
Data: ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Slot: 1,
|
||||
PayloadPresent: true,
|
||||
BlobDataAvailable: false,
|
||||
},
|
||||
Signature: sig,
|
||||
}
|
||||
require.NoError(t, pool.InsertPayloadAttestation(msg, idx))
|
||||
atts := pool.PendingPayloadAttestations()
|
||||
require.Equal(t, 1, len(atts))
|
||||
assert.Equal(t, true, atts[0].AggregationBits.BitAt(idx))
|
||||
assert.Equal(t, false, atts[0].AggregationBits.BitAt(idx+1))
|
||||
})
|
||||
|
||||
t.Run("duplicate index is no-op", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
sig := bls.NewAggregateSignature().Marshal()
|
||||
idx := uint64(3)
|
||||
msg := ðpb.PayloadAttestationMessage{
|
||||
ValidatorIndex: 0,
|
||||
Data: ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Slot: 1,
|
||||
PayloadPresent: true,
|
||||
BlobDataAvailable: false,
|
||||
},
|
||||
Signature: sig,
|
||||
}
|
||||
require.NoError(t, pool.InsertPayloadAttestation(msg, idx))
|
||||
firstSig := bytesutil.SafeCopyBytes(pool.PendingPayloadAttestations()[0].Signature)
|
||||
|
||||
require.NoError(t, pool.InsertPayloadAttestation(msg, idx))
|
||||
atts := pool.PendingPayloadAttestations()
|
||||
require.Equal(t, 1, len(atts))
|
||||
assert.DeepEqual(t, firstSig, atts[0].Signature)
|
||||
})
|
||||
|
||||
t.Run("aggregates different indices", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
sig := bls.NewAggregateSignature().Marshal()
|
||||
root := make([]byte, 32)
|
||||
root[0] = 'r'
|
||||
data := ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: root,
|
||||
Slot: 1,
|
||||
PayloadPresent: true,
|
||||
BlobDataAvailable: false,
|
||||
}
|
||||
msg1 := ðpb.PayloadAttestationMessage{
|
||||
ValidatorIndex: 0,
|
||||
Data: data,
|
||||
Signature: sig,
|
||||
}
|
||||
msg2 := ðpb.PayloadAttestationMessage{
|
||||
ValidatorIndex: 1,
|
||||
Data: data,
|
||||
Signature: sig,
|
||||
}
|
||||
|
||||
require.NoError(t, pool.InsertPayloadAttestation(msg1, 5))
|
||||
require.NoError(t, pool.InsertPayloadAttestation(msg2, 7))
|
||||
|
||||
atts := pool.PendingPayloadAttestations()
|
||||
require.Equal(t, 1, len(atts))
|
||||
assert.Equal(t, true, atts[0].AggregationBits.BitAt(5))
|
||||
assert.Equal(t, true, atts[0].AggregationBits.BitAt(7))
|
||||
assert.Equal(t, false, atts[0].AggregationBits.BitAt(6))
|
||||
})
|
||||
|
||||
t.Run("different data creates separate entries", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
sig := bls.NewAggregateSignature().Marshal()
|
||||
msg1 := ðpb.PayloadAttestationMessage{
|
||||
ValidatorIndex: 0,
|
||||
Data: ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Slot: 1,
|
||||
PayloadPresent: true,
|
||||
BlobDataAvailable: false,
|
||||
},
|
||||
Signature: sig,
|
||||
}
|
||||
msg2 := ðpb.PayloadAttestationMessage{
|
||||
ValidatorIndex: 1,
|
||||
Data: ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Slot: 1,
|
||||
PayloadPresent: false, // different
|
||||
BlobDataAvailable: false,
|
||||
},
|
||||
Signature: sig,
|
||||
}
|
||||
require.NoError(t, pool.InsertPayloadAttestation(msg1, 0))
|
||||
require.NoError(t, pool.InsertPayloadAttestation(msg2, 1))
|
||||
atts := pool.PendingPayloadAttestations()
|
||||
assert.Equal(t, 2, len(atts))
|
||||
})
|
||||
}
|
||||
|
||||
func TestPool_Seen(t *testing.T) {
|
||||
pool := NewPool()
|
||||
sig := bls.NewAggregateSignature().Marshal()
|
||||
data := ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Slot: 1,
|
||||
PayloadPresent: true,
|
||||
BlobDataAvailable: false,
|
||||
}
|
||||
|
||||
assert.Equal(t, false, pool.Seen(data, 5))
|
||||
|
||||
msg := ðpb.PayloadAttestationMessage{
|
||||
ValidatorIndex: 0,
|
||||
Data: data,
|
||||
Signature: sig,
|
||||
}
|
||||
require.NoError(t, pool.InsertPayloadAttestation(msg, 5))
|
||||
|
||||
assert.Equal(t, true, pool.Seen(data, 5))
|
||||
assert.Equal(t, false, pool.Seen(data, 6))
|
||||
assert.Equal(t, false, pool.Seen(nil, 5))
|
||||
}
|
||||
|
||||
func TestPool_MarkIncluded(t *testing.T) {
|
||||
t.Run("mark included removes from pool", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
sig := bls.NewAggregateSignature().Marshal()
|
||||
msg := ðpb.PayloadAttestationMessage{
|
||||
ValidatorIndex: 0,
|
||||
Data: ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Slot: 1,
|
||||
PayloadPresent: true,
|
||||
BlobDataAvailable: false,
|
||||
},
|
||||
Signature: sig,
|
||||
}
|
||||
require.NoError(t, pool.InsertPayloadAttestation(msg, 0))
|
||||
assert.Equal(t, 1, len(pool.PendingPayloadAttestations()))
|
||||
|
||||
pool.MarkIncluded(ðpb.PayloadAttestation{
|
||||
Data: ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Slot: 1,
|
||||
PayloadPresent: true,
|
||||
BlobDataAvailable: false,
|
||||
},
|
||||
})
|
||||
assert.Equal(t, 0, len(pool.PendingPayloadAttestations()))
|
||||
})
|
||||
|
||||
t.Run("mark included with non-matching data does nothing", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
sig := bls.NewAggregateSignature().Marshal()
|
||||
msg := ðpb.PayloadAttestationMessage{
|
||||
ValidatorIndex: 0,
|
||||
Data: ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Slot: 1,
|
||||
PayloadPresent: true,
|
||||
BlobDataAvailable: false,
|
||||
},
|
||||
Signature: sig,
|
||||
}
|
||||
require.NoError(t, pool.InsertPayloadAttestation(msg, 0))
|
||||
|
||||
pool.MarkIncluded(ðpb.PayloadAttestation{
|
||||
Data: ðpb.PayloadAttestationData{
|
||||
BeaconBlockRoot: make([]byte, 32),
|
||||
Slot: 999,
|
||||
PayloadPresent: true,
|
||||
BlobDataAvailable: false,
|
||||
},
|
||||
})
|
||||
assert.Equal(t, 1, len(pool.PendingPayloadAttestations()))
|
||||
})
|
||||
|
||||
t.Run("mark included with nil is safe", func(t *testing.T) {
|
||||
pool := NewPool()
|
||||
pool.MarkIncluded(nil)
|
||||
pool.MarkIncluded(ðpb.PayloadAttestation{})
|
||||
})
|
||||
}
|
||||
@@ -51,7 +51,6 @@ go_library(
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
"//consensus-types/validator:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//encoding/ssz:go_default_library",
|
||||
"//monitoring/tracing/trace:go_default_library",
|
||||
"//network/httputil:go_default_library",
|
||||
"//proto/engine/v1:go_default_library",
|
||||
|
||||
@@ -55,153 +55,114 @@ func (c *beaconApiValidatorClient) beaconBlock(ctx context.Context, slot primiti
|
||||
}
|
||||
}
|
||||
|
||||
// sszBlockCodec defines SSZ unmarshalers for a fork's block and blinded block types.
|
||||
type sszBlockCodec struct {
|
||||
unmarshalBlock func([]byte) (*ethpb.GenericBeaconBlock, error)
|
||||
unmarshalBlinded func([]byte) (*ethpb.GenericBeaconBlock, error) // nil for Phase0/Altair
|
||||
}
|
||||
|
||||
type sszCodecEntry struct {
|
||||
minVersion int
|
||||
codec sszBlockCodec
|
||||
}
|
||||
|
||||
// sszCodecs is ordered descending by version so that unknown future versions
|
||||
// fall through to the latest known fork (matching the original if-cascade).
|
||||
var sszCodecs = []sszCodecEntry{
|
||||
{
|
||||
minVersion: version.Fulu,
|
||||
codec: sszBlockCodec{
|
||||
unmarshalBlock: func(data []byte) (*ethpb.GenericBeaconBlock, error) {
|
||||
block := ðpb.BeaconBlockContentsFulu{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Fulu{Fulu: block}}, nil
|
||||
},
|
||||
unmarshalBlinded: func(data []byte) (*ethpb.GenericBeaconBlock, error) {
|
||||
blindedBlock := ðpb.BlindedBeaconBlockFulu{}
|
||||
if err := blindedBlock.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_BlindedFulu{BlindedFulu: blindedBlock}, IsBlinded: true}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
minVersion: version.Electra,
|
||||
codec: sszBlockCodec{
|
||||
unmarshalBlock: func(data []byte) (*ethpb.GenericBeaconBlock, error) {
|
||||
block := ðpb.BeaconBlockContentsElectra{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Electra{Electra: block}}, nil
|
||||
},
|
||||
unmarshalBlinded: func(data []byte) (*ethpb.GenericBeaconBlock, error) {
|
||||
blindedBlock := ðpb.BlindedBeaconBlockElectra{}
|
||||
if err := blindedBlock.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_BlindedElectra{BlindedElectra: blindedBlock}, IsBlinded: true}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
minVersion: version.Deneb,
|
||||
codec: sszBlockCodec{
|
||||
unmarshalBlock: func(data []byte) (*ethpb.GenericBeaconBlock, error) {
|
||||
block := ðpb.BeaconBlockContentsDeneb{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Deneb{Deneb: block}}, nil
|
||||
},
|
||||
unmarshalBlinded: func(data []byte) (*ethpb.GenericBeaconBlock, error) {
|
||||
blindedBlock := ðpb.BlindedBeaconBlockDeneb{}
|
||||
if err := blindedBlock.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_BlindedDeneb{BlindedDeneb: blindedBlock}, IsBlinded: true}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
minVersion: version.Capella,
|
||||
codec: sszBlockCodec{
|
||||
unmarshalBlock: func(data []byte) (*ethpb.GenericBeaconBlock, error) {
|
||||
block := ðpb.BeaconBlockCapella{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Capella{Capella: block}}, nil
|
||||
},
|
||||
unmarshalBlinded: func(data []byte) (*ethpb.GenericBeaconBlock, error) {
|
||||
blindedBlock := ðpb.BlindedBeaconBlockCapella{}
|
||||
if err := blindedBlock.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_BlindedCapella{BlindedCapella: blindedBlock}, IsBlinded: true}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
minVersion: version.Bellatrix,
|
||||
codec: sszBlockCodec{
|
||||
unmarshalBlock: func(data []byte) (*ethpb.GenericBeaconBlock, error) {
|
||||
block := ðpb.BeaconBlockBellatrix{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Bellatrix{Bellatrix: block}}, nil
|
||||
},
|
||||
unmarshalBlinded: func(data []byte) (*ethpb.GenericBeaconBlock, error) {
|
||||
blindedBlock := ðpb.BlindedBeaconBlockBellatrix{}
|
||||
if err := blindedBlock.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_BlindedBellatrix{BlindedBellatrix: blindedBlock}, IsBlinded: true}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
minVersion: version.Altair,
|
||||
codec: sszBlockCodec{
|
||||
unmarshalBlock: func(data []byte) (*ethpb.GenericBeaconBlock, error) {
|
||||
block := ðpb.BeaconBlockAltair{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Altair{Altair: block}}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
minVersion: version.Phase0,
|
||||
codec: sszBlockCodec{
|
||||
unmarshalBlock: func(data []byte) (*ethpb.GenericBeaconBlock, error) {
|
||||
block := ðpb.BeaconBlock{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Phase0{Phase0: block}}, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func processBlockSSZResponse(ver int, data []byte, isBlinded bool) (*ethpb.GenericBeaconBlock, error) {
|
||||
for _, entry := range sszCodecs {
|
||||
if ver >= entry.minVersion {
|
||||
if isBlinded && entry.codec.unmarshalBlinded != nil {
|
||||
return entry.codec.unmarshalBlinded(data)
|
||||
}
|
||||
return entry.codec.unmarshalBlock(data)
|
||||
if ver >= version.Fulu {
|
||||
return processBlockSSZResponseFulu(data, isBlinded)
|
||||
}
|
||||
if ver >= version.Electra {
|
||||
return processBlockSSZResponseElectra(data, isBlinded)
|
||||
}
|
||||
if ver >= version.Deneb {
|
||||
return processBlockSSZResponseDeneb(data, isBlinded)
|
||||
}
|
||||
if ver >= version.Capella {
|
||||
return processBlockSSZResponseCapella(data, isBlinded)
|
||||
}
|
||||
if ver >= version.Bellatrix {
|
||||
return processBlockSSZResponseBellatrix(data, isBlinded)
|
||||
}
|
||||
if ver >= version.Altair {
|
||||
block := ðpb.BeaconBlockAltair{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Altair{Altair: block}}, nil
|
||||
}
|
||||
if ver >= version.Phase0 {
|
||||
block := ðpb.BeaconBlock{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Phase0{Phase0: block}}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported block version %s", version.String(ver))
|
||||
}
|
||||
|
||||
func processBlockSSZResponseFulu(data []byte, isBlinded bool) (*ethpb.GenericBeaconBlock, error) {
|
||||
if isBlinded {
|
||||
blindedBlock := ðpb.BlindedBeaconBlockFulu{}
|
||||
if err := blindedBlock.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_BlindedFulu{BlindedFulu: blindedBlock}, IsBlinded: true}, nil
|
||||
}
|
||||
block := ðpb.BeaconBlockContentsFulu{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Fulu{Fulu: block}}, nil
|
||||
}
|
||||
|
||||
func processBlockSSZResponseElectra(data []byte, isBlinded bool) (*ethpb.GenericBeaconBlock, error) {
|
||||
if isBlinded {
|
||||
blindedBlock := ðpb.BlindedBeaconBlockElectra{}
|
||||
if err := blindedBlock.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_BlindedElectra{BlindedElectra: blindedBlock}, IsBlinded: true}, nil
|
||||
}
|
||||
block := ðpb.BeaconBlockContentsElectra{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Electra{Electra: block}}, nil
|
||||
}
|
||||
|
||||
func processBlockSSZResponseDeneb(data []byte, isBlinded bool) (*ethpb.GenericBeaconBlock, error) {
|
||||
if isBlinded {
|
||||
blindedBlock := ðpb.BlindedBeaconBlockDeneb{}
|
||||
if err := blindedBlock.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_BlindedDeneb{BlindedDeneb: blindedBlock}, IsBlinded: true}, nil
|
||||
}
|
||||
block := ðpb.BeaconBlockContentsDeneb{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Deneb{Deneb: block}}, nil
|
||||
}
|
||||
|
||||
func processBlockSSZResponseCapella(data []byte, isBlinded bool) (*ethpb.GenericBeaconBlock, error) {
|
||||
if isBlinded {
|
||||
blindedBlock := ðpb.BlindedBeaconBlockCapella{}
|
||||
if err := blindedBlock.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_BlindedCapella{BlindedCapella: blindedBlock}, IsBlinded: true}, nil
|
||||
}
|
||||
block := ðpb.BeaconBlockCapella{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Capella{Capella: block}}, nil
|
||||
}
|
||||
|
||||
func processBlockSSZResponseBellatrix(data []byte, isBlinded bool) (*ethpb.GenericBeaconBlock, error) {
|
||||
if isBlinded {
|
||||
blindedBlock := ðpb.BlindedBeaconBlockBellatrix{}
|
||||
if err := blindedBlock.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_BlindedBellatrix{BlindedBellatrix: blindedBlock}, IsBlinded: true}, nil
|
||||
}
|
||||
block := ðpb.BeaconBlockBellatrix{}
|
||||
if err := block.UnmarshalSSZ(data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ðpb.GenericBeaconBlock{Block: ðpb.GenericBeaconBlock_Bellatrix{Bellatrix: block}}, nil
|
||||
}
|
||||
|
||||
func convertBlockToGeneric(decoder *json.Decoder, dest ethpb.GenericConverter, version string, isBlinded bool) (*ethpb.GenericBeaconBlock, error) {
|
||||
typeName := version
|
||||
if isBlinded {
|
||||
@@ -219,52 +180,69 @@ func convertBlockToGeneric(decoder *json.Decoder, dest ethpb.GenericConverter, v
|
||||
return genericBlock, nil
|
||||
}
|
||||
|
||||
// jsonBlockTypes defines factory functions for creating block and blinded block structs for JSON decoding.
|
||||
type jsonBlockTypes struct {
|
||||
newBlock func() ethpb.GenericConverter
|
||||
newBlinded func() ethpb.GenericConverter // nil for Phase0/Altair
|
||||
}
|
||||
|
||||
var jsonBlockFactories = map[string]jsonBlockTypes{
|
||||
version.String(version.Phase0): {
|
||||
newBlock: func() ethpb.GenericConverter { return &structs.BeaconBlock{} },
|
||||
},
|
||||
version.String(version.Altair): {
|
||||
newBlock: func() ethpb.GenericConverter { return &structs.BeaconBlockAltair{} },
|
||||
},
|
||||
version.String(version.Bellatrix): {
|
||||
newBlock: func() ethpb.GenericConverter { return &structs.BeaconBlockBellatrix{} },
|
||||
newBlinded: func() ethpb.GenericConverter { return &structs.BlindedBeaconBlockBellatrix{} },
|
||||
},
|
||||
version.String(version.Capella): {
|
||||
newBlock: func() ethpb.GenericConverter { return &structs.BeaconBlockCapella{} },
|
||||
newBlinded: func() ethpb.GenericConverter { return &structs.BlindedBeaconBlockCapella{} },
|
||||
},
|
||||
version.String(version.Deneb): {
|
||||
newBlock: func() ethpb.GenericConverter { return &structs.BeaconBlockContentsDeneb{} },
|
||||
newBlinded: func() ethpb.GenericConverter { return &structs.BlindedBeaconBlockDeneb{} },
|
||||
},
|
||||
version.String(version.Electra): {
|
||||
newBlock: func() ethpb.GenericConverter { return &structs.BeaconBlockContentsElectra{} },
|
||||
newBlinded: func() ethpb.GenericConverter { return &structs.BlindedBeaconBlockElectra{} },
|
||||
},
|
||||
version.String(version.Fulu): {
|
||||
newBlock: func() ethpb.GenericConverter { return &structs.BeaconBlockContentsFulu{} },
|
||||
newBlinded: func() ethpb.GenericConverter { return &structs.BlindedBeaconBlockFulu{} },
|
||||
},
|
||||
}
|
||||
|
||||
func processBlockJSONResponse(ver string, isBlinded bool, decoder *json.Decoder) (*ethpb.GenericBeaconBlock, error) {
|
||||
if decoder == nil {
|
||||
return nil, errors.New("no produce block json decoder found")
|
||||
}
|
||||
|
||||
factory, ok := jsonBlockFactories[ver]
|
||||
if !ok {
|
||||
switch ver {
|
||||
case version.String(version.Phase0):
|
||||
return convertBlockToGeneric(decoder, &structs.BeaconBlock{}, version.String(version.Phase0), false)
|
||||
|
||||
case version.String(version.Altair):
|
||||
return convertBlockToGeneric(decoder, &structs.BeaconBlockAltair{}, "altair", false)
|
||||
|
||||
case version.String(version.Bellatrix):
|
||||
return processBellatrixBlock(decoder, isBlinded)
|
||||
|
||||
case version.String(version.Capella):
|
||||
return processCapellaBlock(decoder, isBlinded)
|
||||
|
||||
case version.String(version.Deneb):
|
||||
return processDenebBlock(decoder, isBlinded)
|
||||
|
||||
case version.String(version.Electra):
|
||||
return processElectraBlock(decoder, isBlinded)
|
||||
|
||||
case version.String(version.Fulu):
|
||||
return processFuluBlock(decoder, isBlinded)
|
||||
|
||||
default:
|
||||
return nil, errors.Errorf("unsupported consensus version `%s`", ver)
|
||||
}
|
||||
if isBlinded && factory.newBlinded != nil {
|
||||
return convertBlockToGeneric(decoder, factory.newBlinded(), ver, true)
|
||||
}
|
||||
return convertBlockToGeneric(decoder, factory.newBlock(), ver, false)
|
||||
}
|
||||
|
||||
func processBellatrixBlock(decoder *json.Decoder, isBlinded bool) (*ethpb.GenericBeaconBlock, error) {
|
||||
if isBlinded {
|
||||
return convertBlockToGeneric(decoder, &structs.BlindedBeaconBlockBellatrix{}, "bellatrix", true)
|
||||
}
|
||||
return convertBlockToGeneric(decoder, &structs.BeaconBlockBellatrix{}, "bellatrix", false)
|
||||
}
|
||||
|
||||
func processCapellaBlock(decoder *json.Decoder, isBlinded bool) (*ethpb.GenericBeaconBlock, error) {
|
||||
if isBlinded {
|
||||
return convertBlockToGeneric(decoder, &structs.BlindedBeaconBlockCapella{}, "capella", true)
|
||||
}
|
||||
return convertBlockToGeneric(decoder, &structs.BeaconBlockCapella{}, "capella", false)
|
||||
}
|
||||
|
||||
func processDenebBlock(decoder *json.Decoder, isBlinded bool) (*ethpb.GenericBeaconBlock, error) {
|
||||
if isBlinded {
|
||||
return convertBlockToGeneric(decoder, &structs.BlindedBeaconBlockDeneb{}, "deneb", true)
|
||||
}
|
||||
return convertBlockToGeneric(decoder, &structs.BeaconBlockContentsDeneb{}, "deneb", false)
|
||||
}
|
||||
|
||||
func processElectraBlock(decoder *json.Decoder, isBlinded bool) (*ethpb.GenericBeaconBlock, error) {
|
||||
if isBlinded {
|
||||
return convertBlockToGeneric(decoder, &structs.BlindedBeaconBlockElectra{}, "electra", true)
|
||||
}
|
||||
return convertBlockToGeneric(decoder, &structs.BeaconBlockContentsElectra{}, "electra", false)
|
||||
}
|
||||
|
||||
func processFuluBlock(decoder *json.Decoder, isBlinded bool) (*ethpb.GenericBeaconBlock, error) {
|
||||
if isBlinded {
|
||||
return convertBlockToGeneric(decoder, &structs.BlindedBeaconBlockFulu{}, "fulu", true)
|
||||
}
|
||||
return convertBlockToGeneric(decoder, &structs.BeaconBlockContentsFulu{}, "fulu", false)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/OffchainLabs/prysm/v7/api/server/structs"
|
||||
"github.com/OffchainLabs/prysm/v7/encoding/ssz"
|
||||
"github.com/OffchainLabs/prysm/v7/network/httputil"
|
||||
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
||||
"github.com/pkg/errors"
|
||||
@@ -22,128 +21,34 @@ type blockProcessingResult struct {
|
||||
marshalJSON func() ([]byte, error)
|
||||
}
|
||||
|
||||
type sszMarshaler interface {
|
||||
MarshalSSZ() ([]byte, error)
|
||||
}
|
||||
|
||||
func buildBlockResult(
|
||||
versionName string,
|
||||
blinded bool,
|
||||
sszObj sszMarshaler,
|
||||
rootObj ssz.Hashable,
|
||||
jsonFn func() ([]byte, error),
|
||||
) (*blockProcessingResult, error) {
|
||||
beaconBlockRoot, err := rootObj.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to compute block root for %s beacon block", versionName)
|
||||
}
|
||||
|
||||
ssz, err := sszObj.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to serialize %s beacon block", versionName)
|
||||
}
|
||||
|
||||
return &blockProcessingResult{
|
||||
consensusVersion: versionName,
|
||||
blinded: blinded,
|
||||
beaconBlockRoot: beaconBlockRoot,
|
||||
marshalledSSZ: ssz,
|
||||
marshalJSON: jsonFn,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *beaconApiValidatorClient) proposeBeaconBlock(ctx context.Context, in *ethpb.GenericSignedBeaconBlock) (*ethpb.ProposeResponse, error) {
|
||||
var res *blockProcessingResult
|
||||
var err error
|
||||
switch blockType := in.Block.(type) {
|
||||
case *ethpb.GenericSignedBeaconBlock_Phase0:
|
||||
res, err = buildBlockResult("phase0", false, blockType.Phase0, blockType.Phase0.Block, func() ([]byte, error) {
|
||||
return json.Marshal(structs.SignedBeaconBlockPhase0FromConsensus(blockType.Phase0))
|
||||
})
|
||||
res, err = handlePhase0Block(blockType)
|
||||
case *ethpb.GenericSignedBeaconBlock_Altair:
|
||||
res, err = buildBlockResult("altair", false, blockType.Altair, blockType.Altair.Block, func() ([]byte, error) {
|
||||
return json.Marshal(structs.SignedBeaconBlockAltairFromConsensus(blockType.Altair))
|
||||
})
|
||||
res, err = handleAltairBlock(blockType)
|
||||
case *ethpb.GenericSignedBeaconBlock_Bellatrix:
|
||||
res, err = buildBlockResult("bellatrix", false, blockType.Bellatrix, blockType.Bellatrix.Block, func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockBellatrixFromConsensus(blockType.Bellatrix)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert bellatrix beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
})
|
||||
res, err = handleBellatrixBlock(blockType)
|
||||
case *ethpb.GenericSignedBeaconBlock_BlindedBellatrix:
|
||||
res, err = buildBlockResult("bellatrix", true, blockType.BlindedBellatrix, blockType.BlindedBellatrix.Block, func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockBellatrixFromConsensus(blockType.BlindedBellatrix)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert blinded bellatrix beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
})
|
||||
res, err = handleBlindedBellatrixBlock(blockType)
|
||||
case *ethpb.GenericSignedBeaconBlock_Capella:
|
||||
res, err = buildBlockResult("capella", false, blockType.Capella, blockType.Capella.Block, func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockCapellaFromConsensus(blockType.Capella)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert capella beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
})
|
||||
res, err = handleCapellaBlock(blockType)
|
||||
case *ethpb.GenericSignedBeaconBlock_BlindedCapella:
|
||||
res, err = buildBlockResult("capella", true, blockType.BlindedCapella, blockType.BlindedCapella.Block, func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockCapellaFromConsensus(blockType.BlindedCapella)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert blinded capella beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
})
|
||||
res, err = handleBlindedCapellaBlock(blockType)
|
||||
case *ethpb.GenericSignedBeaconBlock_Deneb:
|
||||
res, err = buildBlockResult("deneb", false, blockType.Deneb, blockType.Deneb.Block, func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockContentsDenebFromConsensus(blockType.Deneb)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert deneb beacon block contents")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
})
|
||||
res, err = handleDenebBlockContents(blockType)
|
||||
case *ethpb.GenericSignedBeaconBlock_BlindedDeneb:
|
||||
res, err = buildBlockResult("deneb", true, blockType.BlindedDeneb, blockType.BlindedDeneb, func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockDenebFromConsensus(blockType.BlindedDeneb)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert deneb blinded beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
})
|
||||
res, err = handleBlindedDenebBlock(blockType)
|
||||
case *ethpb.GenericSignedBeaconBlock_Electra:
|
||||
res, err = buildBlockResult("electra", false, blockType.Electra, blockType.Electra.Block, func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockContentsElectraFromConsensus(blockType.Electra)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert electra beacon block contents")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
})
|
||||
res, err = handleElectraBlockContents(blockType)
|
||||
case *ethpb.GenericSignedBeaconBlock_BlindedElectra:
|
||||
res, err = buildBlockResult("electra", true, blockType.BlindedElectra, blockType.BlindedElectra, func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockElectraFromConsensus(blockType.BlindedElectra)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert electra blinded beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
})
|
||||
res, err = handleBlindedElectraBlock(blockType)
|
||||
case *ethpb.GenericSignedBeaconBlock_Fulu:
|
||||
res, err = buildBlockResult("fulu", false, blockType.Fulu, blockType.Fulu.Block, func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockContentsFuluFromConsensus(blockType.Fulu)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert fulu beacon block contents")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
})
|
||||
res, err = handleFuluBlockContents(blockType)
|
||||
case *ethpb.GenericSignedBeaconBlock_BlindedFulu:
|
||||
res, err = buildBlockResult("fulu", true, blockType.BlindedFulu, blockType.BlindedFulu, func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockFuluFromConsensus(blockType.BlindedFulu)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert fulu blinded beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
})
|
||||
res, err = handleBlindedFuluBlock(blockType)
|
||||
default:
|
||||
return nil, errors.Errorf("unsupported block type %T", in.Block)
|
||||
}
|
||||
@@ -211,3 +116,357 @@ func (c *beaconApiValidatorClient) proposeBeaconBlock(ctx context.Context, in *e
|
||||
|
||||
return ðpb.ProposeResponse{BlockRoot: res.beaconBlockRoot[:]}, nil
|
||||
}
|
||||
|
||||
func handlePhase0Block(block *ethpb.GenericSignedBeaconBlock_Phase0) (*blockProcessingResult, error) {
|
||||
var res blockProcessingResult
|
||||
res.consensusVersion = "phase0"
|
||||
res.blinded = false
|
||||
|
||||
beaconBlockRoot, err := block.Phase0.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compute block root for phase0 beacon block")
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
// Marshal SSZ
|
||||
ssz, err := block.Phase0.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to serialize block for phase0 beacon block")
|
||||
}
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock := structs.SignedBeaconBlockPhase0FromConsensus(block.Phase0)
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func handleAltairBlock(block *ethpb.GenericSignedBeaconBlock_Altair) (*blockProcessingResult, error) {
|
||||
var res blockProcessingResult
|
||||
res.consensusVersion = "altair"
|
||||
res.blinded = false
|
||||
|
||||
beaconBlockRoot, err := block.Altair.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compute block root for altair beacon block")
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
// Marshal SSZ
|
||||
ssz, err := block.Altair.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to serialize block for altair beacon block")
|
||||
}
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock := structs.SignedBeaconBlockAltairFromConsensus(block.Altair)
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func handleBellatrixBlock(block *ethpb.GenericSignedBeaconBlock_Bellatrix) (*blockProcessingResult, error) {
|
||||
var res blockProcessingResult
|
||||
res.consensusVersion = "bellatrix"
|
||||
res.blinded = false
|
||||
|
||||
beaconBlockRoot, err := block.Bellatrix.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compute block root for bellatrix beacon block")
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
// Marshal SSZ
|
||||
ssz, err := block.Bellatrix.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to serialize block for bellatrix beacon block")
|
||||
}
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockBellatrixFromConsensus(block.Bellatrix)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert bellatrix beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func handleBlindedBellatrixBlock(block *ethpb.GenericSignedBeaconBlock_BlindedBellatrix) (*blockProcessingResult, error) {
|
||||
var res blockProcessingResult
|
||||
res.consensusVersion = "bellatrix"
|
||||
res.blinded = true
|
||||
|
||||
beaconBlockRoot, err := block.BlindedBellatrix.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compute block root for bellatrix beacon block")
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
// Marshal SSZ
|
||||
ssz, err := block.BlindedBellatrix.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to serialize block for bellatrix beacon block")
|
||||
}
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockBellatrixFromConsensus(block.BlindedBellatrix)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert blinded bellatrix beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func handleCapellaBlock(block *ethpb.GenericSignedBeaconBlock_Capella) (*blockProcessingResult, error) {
|
||||
var res blockProcessingResult
|
||||
res.consensusVersion = "capella"
|
||||
res.blinded = false
|
||||
|
||||
beaconBlockRoot, err := block.Capella.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compute block root for capella beacon block")
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
// Marshal SSZ
|
||||
ssz, err := block.Capella.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to serialize capella beacon block")
|
||||
}
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockCapellaFromConsensus(block.Capella)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert capella beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func handleBlindedCapellaBlock(block *ethpb.GenericSignedBeaconBlock_BlindedCapella) (*blockProcessingResult, error) {
|
||||
var res blockProcessingResult
|
||||
res.consensusVersion = "capella"
|
||||
res.blinded = true
|
||||
|
||||
beaconBlockRoot, err := block.BlindedCapella.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compute block root for blinded capella beacon block")
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
// Marshal SSZ
|
||||
ssz, err := block.BlindedCapella.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to serialize blinded capella beacon block")
|
||||
}
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockCapellaFromConsensus(block.BlindedCapella)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert blinded capella beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func handleDenebBlockContents(block *ethpb.GenericSignedBeaconBlock_Deneb) (*blockProcessingResult, error) {
|
||||
var res blockProcessingResult
|
||||
res.consensusVersion = "deneb"
|
||||
res.blinded = false
|
||||
|
||||
beaconBlockRoot, err := block.Deneb.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compute block root for deneb beacon block")
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
// Marshal SSZ
|
||||
ssz, err := block.Deneb.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to serialize deneb beacon block")
|
||||
}
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockContentsDenebFromConsensus(block.Deneb)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert deneb beacon block contents")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func handleBlindedDenebBlock(block *ethpb.GenericSignedBeaconBlock_BlindedDeneb) (*blockProcessingResult, error) {
|
||||
var res blockProcessingResult
|
||||
res.consensusVersion = "deneb"
|
||||
res.blinded = true
|
||||
|
||||
beaconBlockRoot, err := block.BlindedDeneb.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compute block root for deneb blinded beacon block")
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
// Marshal SSZ
|
||||
ssz, err := block.BlindedDeneb.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to serialize blinded deneb beacon block")
|
||||
}
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockDenebFromConsensus(block.BlindedDeneb)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert deneb blinded beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func handleElectraBlockContents(block *ethpb.GenericSignedBeaconBlock_Electra) (*blockProcessingResult, error) {
|
||||
var res blockProcessingResult
|
||||
res.consensusVersion = "electra"
|
||||
res.blinded = false
|
||||
|
||||
beaconBlockRoot, err := block.Electra.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compute block root for electra beacon block")
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
// Marshal SSZ
|
||||
ssz, err := block.Electra.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to serialize electra beacon block")
|
||||
}
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockContentsElectraFromConsensus(block.Electra)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert electra beacon block contents")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func handleBlindedElectraBlock(block *ethpb.GenericSignedBeaconBlock_BlindedElectra) (*blockProcessingResult, error) {
|
||||
var res blockProcessingResult
|
||||
res.consensusVersion = "electra"
|
||||
res.blinded = true
|
||||
|
||||
beaconBlockRoot, err := block.BlindedElectra.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compute block root for electra blinded beacon block")
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
// Marshal SSZ
|
||||
ssz, err := block.BlindedElectra.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to serialize blinded electra beacon block")
|
||||
}
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockElectraFromConsensus(block.BlindedElectra)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert electra blinded beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func handleFuluBlockContents(block *ethpb.GenericSignedBeaconBlock_Fulu) (*blockProcessingResult, error) {
|
||||
var res blockProcessingResult
|
||||
res.consensusVersion = "fulu"
|
||||
res.blinded = false
|
||||
|
||||
beaconBlockRoot, err := block.Fulu.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compute block root for fulu beacon block")
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
// Marshal SSZ
|
||||
ssz, err := block.Fulu.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to serialize fulu beacon block")
|
||||
}
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBeaconBlockContentsFuluFromConsensus(block.Fulu)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert fulu beacon block contents")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func handleBlindedFuluBlock(block *ethpb.GenericSignedBeaconBlock_BlindedFulu) (*blockProcessingResult, error) {
|
||||
var res blockProcessingResult
|
||||
res.consensusVersion = "fulu"
|
||||
res.blinded = true
|
||||
|
||||
beaconBlockRoot, err := block.BlindedFulu.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to compute block root for fulu blinded beacon block")
|
||||
}
|
||||
res.beaconBlockRoot = beaconBlockRoot
|
||||
|
||||
// Marshal SSZ
|
||||
ssz, err := block.BlindedFulu.MarshalSSZ()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to serialize blinded fulu beacon block")
|
||||
}
|
||||
res.marshalledSSZ = ssz
|
||||
|
||||
// Set up JSON marshalling function for fallback
|
||||
res.marshalJSON = func() ([]byte, error) {
|
||||
signedBlock, err := structs.SignedBlindedBeaconBlockFuluFromConsensus(block.BlindedFulu)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to convert fulu blinded beacon block")
|
||||
}
|
||||
return json.Marshal(signedBlock)
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user