mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
EIP-7549: attestation pool (#14121)
* implementation * test fixes * Electra tests * remove aggregator tests * id comments and tests * make Id equal to [33]byte
This commit is contained in:
@@ -2,10 +2,14 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["attestation_utils.go"],
|
||||
srcs = [
|
||||
"attestation_utils.go",
|
||||
"id.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//consensus-types/primitives:go_default_library",
|
||||
@@ -20,7 +24,10 @@ go_library(
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["attestation_utils_test.go"],
|
||||
srcs = [
|
||||
"attestation_utils_test.go",
|
||||
"id_test.go",
|
||||
],
|
||||
deps = [
|
||||
":go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
@@ -29,6 +36,7 @@ go_test(
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//testing/util:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -12,6 +12,7 @@ go_library(
|
||||
"//crypto/bls:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/attestation/aggregation:go_default_library",
|
||||
"//runtime/version:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_prysmaticlabs_go_bitfield//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation/aggregation"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
)
|
||||
|
||||
// MaxCoverAttestationAggregation relies on Maximum Coverage greedy algorithm for aggregation.
|
||||
@@ -171,11 +172,21 @@ func aggregateAttestations(atts []ethpb.Att, keys []int, coverage *bitfield.Bitl
|
||||
}
|
||||
}
|
||||
// Put aggregated attestation at a position of the first selected attestation.
|
||||
atts[targetIdx] = ðpb.Attestation{
|
||||
// Append size byte, which will be unnecessary on switch to Bitlist64.
|
||||
AggregationBits: coverage.ToBitlist(),
|
||||
Data: data,
|
||||
Signature: aggregateSignatures(signs).Marshal(),
|
||||
if atts[0].Version() == version.Phase0 {
|
||||
atts[targetIdx] = ðpb.Attestation{
|
||||
// Append size byte, which will be unnecessary on switch to Bitlist64.
|
||||
AggregationBits: coverage.ToBitlist(),
|
||||
Data: data,
|
||||
Signature: aggregateSignatures(signs).Marshal(),
|
||||
}
|
||||
} else {
|
||||
atts[targetIdx] = ðpb.AttestationElectra{
|
||||
// Append size byte, which will be unnecessary on switch to Bitlist64.
|
||||
AggregationBits: coverage.ToBitlist(),
|
||||
CommitteeBits: atts[0].CommitteeBitsVal().Bytes(),
|
||||
Data: data,
|
||||
Signature: aggregateSignatures(signs).Marshal(),
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
71
proto/prysm/v1alpha1/attestation/id.go
Normal file
71
proto/prysm/v1alpha1/attestation/id.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package attestation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/runtime/version"
|
||||
)
|
||||
|
||||
// IdSource represents the part of attestation that will be used to generate the Id.
|
||||
type IdSource uint8
|
||||
|
||||
const (
|
||||
// Full generates the Id from the whole attestation.
|
||||
Full IdSource = iota
|
||||
// Data generates the Id from the tuple (slot, committee index, beacon block root, source, target).
|
||||
Data
|
||||
)
|
||||
|
||||
// Id represents an attestation ID. Its uniqueness depends on the IdSource provided when constructing the Id.
|
||||
type Id [33]byte
|
||||
|
||||
// NewId --
|
||||
func NewId(att ethpb.Att, source IdSource) (Id, error) {
|
||||
if err := helpers.ValidateNilAttestation(att); err != nil {
|
||||
return Id{}, err
|
||||
}
|
||||
if att.Version() < 0 || att.Version() > 255 {
|
||||
return Id{}, errors.New("attestation version must be between 0 and 255")
|
||||
}
|
||||
|
||||
var id Id
|
||||
id[0] = byte(att.Version())
|
||||
|
||||
switch source {
|
||||
case Full:
|
||||
h, err := att.HashTreeRoot()
|
||||
if err != nil {
|
||||
return Id{}, err
|
||||
}
|
||||
copy(id[1:], h[:])
|
||||
return id, nil
|
||||
case Data:
|
||||
data := att.GetData()
|
||||
if att.Version() >= version.Electra {
|
||||
committeeIndices := att.CommitteeBitsVal().BitIndices()
|
||||
if len(committeeIndices) != 1 {
|
||||
return Id{}, fmt.Errorf("%d committee bits are set instead of 1", len(committeeIndices))
|
||||
}
|
||||
dataCopy := ethpb.CopyAttestationData(att.GetData())
|
||||
dataCopy.CommitteeIndex = primitives.CommitteeIndex(committeeIndices[0])
|
||||
data = dataCopy
|
||||
}
|
||||
h, err := data.HashTreeRoot()
|
||||
if err != nil {
|
||||
return Id{}, err
|
||||
}
|
||||
copy(id[1:], h[:])
|
||||
return id, nil
|
||||
default:
|
||||
return Id{}, errors.New("invalid source requested")
|
||||
}
|
||||
}
|
||||
|
||||
// String --
|
||||
func (id Id) String() string {
|
||||
return string(id[:])
|
||||
}
|
||||
63
proto/prysm/v1alpha1/attestation/id_test.go
Normal file
63
proto/prysm/v1alpha1/attestation/id_test.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package attestation_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1/attestation"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func TestNewId(t *testing.T) {
|
||||
t.Run("full source", func(t *testing.T) {
|
||||
att := util.HydrateAttestation(ðpb.Attestation{})
|
||||
_, err := attestation.NewId(att, attestation.Full)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("data source Phase 0", func(t *testing.T) {
|
||||
att := util.HydrateAttestation(ðpb.Attestation{})
|
||||
_, err := attestation.NewId(att, attestation.Data)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("data source Electra", func(t *testing.T) {
|
||||
cb := primitives.NewAttestationCommitteeBits()
|
||||
cb.SetBitAt(0, true)
|
||||
att := util.HydrateAttestationElectra(ðpb.AttestationElectra{CommitteeBits: cb})
|
||||
_, err := attestation.NewId(att, attestation.Data)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
t.Run("ID is different between versions", func(t *testing.T) {
|
||||
phase0Att := util.HydrateAttestation(ðpb.Attestation{})
|
||||
phase0Id, err := attestation.NewId(phase0Att, attestation.Data)
|
||||
require.NoError(t, err)
|
||||
cb := primitives.NewAttestationCommitteeBits()
|
||||
cb.SetBitAt(0, true) // setting committee bit 0 for Electra corresponds to attestation data's committee index 0 for Phase 0
|
||||
electraAtt := util.HydrateAttestationElectra(ðpb.AttestationElectra{CommitteeBits: cb})
|
||||
electraId, err := attestation.NewId(electraAtt, attestation.Data)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotEqual(t, phase0Id, electraId)
|
||||
})
|
||||
t.Run("invalid source", func(t *testing.T) {
|
||||
att := util.HydrateAttestation(ðpb.Attestation{})
|
||||
_, err := attestation.NewId(att, 123)
|
||||
assert.ErrorContains(t, "invalid source requested", err)
|
||||
})
|
||||
t.Run("data source Electra - 0 bits set", func(t *testing.T) {
|
||||
cb := primitives.NewAttestationCommitteeBits()
|
||||
att := util.HydrateAttestationElectra(ðpb.AttestationElectra{CommitteeBits: cb})
|
||||
_, err := attestation.NewId(att, attestation.Data)
|
||||
assert.ErrorContains(t, "0 committee bits are set", err)
|
||||
})
|
||||
t.Run("data source Electra - multiple bits set", func(t *testing.T) {
|
||||
cb := primitives.NewAttestationCommitteeBits()
|
||||
cb.SetBitAt(0, true)
|
||||
cb.SetBitAt(1, true)
|
||||
att := util.HydrateAttestationElectra(ðpb.AttestationElectra{CommitteeBits: cb})
|
||||
_, err := attestation.NewId(att, attestation.Data)
|
||||
assert.ErrorContains(t, "2 committee bits are set", err)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user