Skip to content

Commit

Permalink
EIP-7549 Move committee index outside Attestation (#12233)
Browse files Browse the repository at this point in the history
https://eips.ethereum.org/EIPS/eip-7549
Part of electra implementation
#11146
  • Loading branch information
domiwei authored Oct 18, 2024
1 parent 4d6c799 commit c6bf9aa
Show file tree
Hide file tree
Showing 67 changed files with 1,203 additions and 244 deletions.
3 changes: 2 additions & 1 deletion cl/abstract/beacon_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type BeaconStateUpgradable interface {
UpgradeToBellatrix() error
UpgradeToCapella() error
UpgradeToDeneb() error
UpgradeToElectra() error
}

type BeaconStateExtension interface {
Expand All @@ -51,7 +52,7 @@ type BeaconStateExtension interface {
GetAttestationParticipationFlagIndicies(data *solid.AttestationData, inclusionDelay uint64, skipAssert bool) ([]uint8, error)
GetBeaconCommitee(slot, committeeIndex uint64) ([]uint64, error)
ComputeNextSyncCommittee() (*solid.SyncCommittee, error)
GetAttestingIndicies(attestation *solid.AttestationData, aggregationBits []byte, checkBitsLength bool) ([]uint64, error)
GetAttestingIndicies(attestation *solid.Attestation, checkBitsLength bool) ([]uint64, error)
GetValidatorChurnLimit() uint64
ValidatorIndexByPubkey(key [48]byte) (uint64, bool)
PreviousStateRoot() common.Hash
Expand Down
50 changes: 36 additions & 14 deletions cl/aggregation/pool_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package aggregation
import (
"context"
"errors"
"fmt"
"sync"
"time"

Expand Down Expand Up @@ -76,7 +77,7 @@ func (p *aggregationPoolImpl) AddAttestation(inAtt *solid.Attestation) error {
return nil
}

if utils.IsNonStrictSupersetBitlist(att.AggregationBits.Bytes(), inAtt.AggregationBits.Bytes()) {
if utils.IsOverlappingBitlist(att.AggregationBits.Bytes(), inAtt.AggregationBits.Bytes()) {
// the on bit is already set, so ignore
return ErrIsSuperset
}
Expand All @@ -94,19 +95,40 @@ func (p *aggregationPoolImpl) AddAttestation(inAtt *solid.Attestation) error {
var mergedSig [96]byte
copy(mergedSig[:], merged)

// merge aggregation bits
mergedBits := solid.NewBitList(0, 2048)
aggBitsBytes := att.AggregationBits.Bytes()
inAttBitsBytes := inAtt.AggregationBits.Bytes()
for i := range aggBitsBytes {
mergedBits.Append(aggBitsBytes[i] | inAttBitsBytes[i])
}

// update attestation
p.aggregates[hashRoot] = &solid.Attestation{
AggregationBits: mergedBits,
Data: att.Data,
Signature: mergedSig,
epoch := p.ethClock.GetEpochAtSlot(att.Data.Slot)
clversion := p.ethClock.StateVersionByEpoch(epoch)
if clversion.BeforeOrEqual(clparams.DenebVersion) {
// merge aggregation bits
mergedBits, err := att.AggregationBits.Union(inAtt.AggregationBits)
if err != nil {
return err
}
// update attestation
p.aggregates[hashRoot] = &solid.Attestation{
AggregationBits: mergedBits,
Data: att.Data,
Signature: mergedSig,
}
} else {
// Electra and after case
aggrBitSize := p.beaconConfig.MaxCommitteesPerSlot * p.beaconConfig.MaxValidatorsPerCommittee
mergedAggrBits, err := att.AggregationBits.Union(inAtt.AggregationBits)
if err != nil {
return err
}
if mergedAggrBits.Cap() != int(aggrBitSize) {
return fmt.Errorf("incorrect aggregation bits size: %d", mergedAggrBits.Cap())
}
mergedCommitteeBits, err := att.CommitteeBits.Union(inAtt.CommitteeBits)
if err != nil {
return err
}
p.aggregates[hashRoot] = &solid.Attestation{
AggregationBits: mergedAggrBits,
CommitteeBits: mergedCommitteeBits,
Data: att.Data,
Signature: mergedSig,
}
}
return nil
}
Expand Down
97 changes: 91 additions & 6 deletions cl/aggregation/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ import (
"log"
"testing"

"github.com/erigontech/erigon/cl/clparams"
"github.com/erigontech/erigon/cl/cltypes/solid"
"github.com/erigontech/erigon/cl/utils/eth_clock"
"github.com/stretchr/testify/suite"
"go.uber.org/mock/gomock"
)

var (
Expand Down Expand Up @@ -78,6 +81,9 @@ var (
)

type PoolTestSuite struct {
mockEthClock *eth_clock.MockEthereumClock
mockBeaconConfig *clparams.BeaconChainConfig
ctrl *gomock.Controller
suite.Suite
}

Expand All @@ -87,16 +93,88 @@ func (t *PoolTestSuite) SetupTest() {
copy(ret, mockAggrResult[:])
return ret, nil
}
t.ctrl = gomock.NewController(t.T())
t.mockEthClock = eth_clock.NewMockEthereumClock(t.ctrl)
t.mockBeaconConfig = &clparams.BeaconChainConfig{
MaxCommitteesPerSlot: 64,
MaxValidatorsPerCommittee: 2048,
}
}

func (t *PoolTestSuite) TearDownTest() {
t.ctrl.Finish()
}

func (t *PoolTestSuite) TestAddAttestationElectra() {
cBits1 := solid.NewBitVector(64)
cBits1.SetBitAt(0, true)
cBits2 := solid.NewBitVector(64)
cBits2.SetBitAt(10, true)
expectedCommitteeBits := solid.NewBitVector(64)
expectedCommitteeBits.SetBitAt(0, true)
expectedCommitteeBits.SetBitAt(10, true)

att1 := &solid.Attestation{
AggregationBits: solid.BitlistFromBytes([]byte{0b00000001, 0, 0, 0}, 2048*64),
Data: attData1,
Signature: [96]byte{'a', 'b', 'c', 'd', 'e', 'f'},
CommitteeBits: cBits1,
}
att2 := &solid.Attestation{
AggregationBits: solid.BitlistFromBytes([]byte{0b00000000, 0b00001000, 0, 0}, 2048*64),
Data: attData1,
Signature: [96]byte{'d', 'e', 'f', 'g', 'h', 'i'},
CommitteeBits: cBits2,
}
testcases := []struct {
name string
atts []*solid.Attestation
hashRoot [32]byte
mockFunc func()
expect *solid.Attestation
}{
{
name: "electra case",
atts: []*solid.Attestation{
att1,
att2,
},
hashRoot: attData1Root,
mockFunc: func() {
t.mockEthClock.EXPECT().GetEpochAtSlot(gomock.Any()).Return(uint64(1)).Times(1)
t.mockEthClock.EXPECT().StateVersionByEpoch(gomock.Any()).Return(clparams.ElectraVersion).Times(1)
},
expect: &solid.Attestation{
AggregationBits: solid.BitlistFromBytes([]byte{0b0000001, 0b00001000, 0, 0}, 2048*64),
Data: attData1,
Signature: mockAggrResult,
CommitteeBits: expectedCommitteeBits,
},
},
}

for _, tc := range testcases {
log.Printf("test case: %s", tc.name)
if tc.mockFunc != nil {
tc.mockFunc()
}
pool := NewAggregationPool(context.Background(), t.mockBeaconConfig, nil, t.mockEthClock)
for i := range tc.atts {
pool.AddAttestation(tc.atts[i])
}
att := pool.GetAggregatationByRoot(tc.hashRoot)
//h1, _ := tc.expect.HashSSZ()
//h2, _ := att.HashSSZ()
t.Equal(tc.expect, att, tc.name)
}
}

func (t *PoolTestSuite) TestAddAttestation() {
testcases := []struct {
name string
atts []*solid.Attestation
hashRoot [32]byte
mockFunc func()
expect *solid.Attestation
}{
{
Expand Down Expand Up @@ -126,6 +204,10 @@ func (t *PoolTestSuite) TestAddAttestation() {
att1_4,
},
hashRoot: attData1Root,
mockFunc: func() {
t.mockEthClock.EXPECT().GetEpochAtSlot(gomock.Any()).Return(uint64(1)).AnyTimes()
t.mockEthClock.EXPECT().StateVersionByEpoch(gomock.Any()).Return(clparams.DenebVersion).AnyTimes()
},
expect: &solid.Attestation{
AggregationBits: solid.BitlistFromBytes([]byte{0b00100101, 0, 0, 0}, 2048),
Data: attData1,
Expand All @@ -136,14 +218,17 @@ func (t *PoolTestSuite) TestAddAttestation() {

for _, tc := range testcases {
log.Printf("test case: %s", tc.name)
pool := NewAggregationPool(context.Background(), nil, nil, nil)
for _, att := range tc.atts {
pool.AddAttestation(att)
if tc.mockFunc != nil {
tc.mockFunc()
}
pool := NewAggregationPool(context.Background(), t.mockBeaconConfig, nil, t.mockEthClock)
for i := range tc.atts {
pool.AddAttestation(tc.atts[i])
}
att := pool.GetAggregatationByRoot(tc.hashRoot)
h1, _ := tc.expect.HashSSZ()
h2, _ := att.HashSSZ()
t.Equal(h1, h2, tc.name)
//h1, _ := tc.expect.HashSSZ()
//h2, _ := att.HashSSZ()
t.Equal(tc.expect, att, tc.name)
}
}

Expand Down
10 changes: 5 additions & 5 deletions cl/antiquary/tests/tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ func LoadChain(blocks []*cltypes.SignedBeaconBlock, s *state.CachingBeaconState,
}

func GetCapellaRandom() ([]*cltypes.SignedBeaconBlock, *state.CachingBeaconState, *state.CachingBeaconState) {
block1 := cltypes.NewSignedBeaconBlock(&clparams.MainnetBeaconConfig)
block2 := cltypes.NewSignedBeaconBlock(&clparams.MainnetBeaconConfig)
block1 := cltypes.NewSignedBeaconBlock(&clparams.MainnetBeaconConfig, clparams.CapellaVersion)
block2 := cltypes.NewSignedBeaconBlock(&clparams.MainnetBeaconConfig, clparams.CapellaVersion)

// Lets do te
if err := utils.DecodeSSZSnappy(block1, capella_blocks_0_ssz_snappy, int(clparams.CapellaVersion)); err != nil {
Expand All @@ -153,8 +153,8 @@ func GetCapellaRandom() ([]*cltypes.SignedBeaconBlock, *state.CachingBeaconState
}

func GetPhase0Random() ([]*cltypes.SignedBeaconBlock, *state.CachingBeaconState, *state.CachingBeaconState) {
block1 := cltypes.NewSignedBeaconBlock(&clparams.MainnetBeaconConfig)
block2 := cltypes.NewSignedBeaconBlock(&clparams.MainnetBeaconConfig)
block1 := cltypes.NewSignedBeaconBlock(&clparams.MainnetBeaconConfig, clparams.Phase0Version)
block2 := cltypes.NewSignedBeaconBlock(&clparams.MainnetBeaconConfig, clparams.Phase0Version)

// Lets do te
if err := utils.DecodeSSZSnappy(block1, phase0_blocks_0_ssz_snappy, int(clparams.Phase0Version)); err != nil {
Expand All @@ -179,7 +179,7 @@ func GetBellatrixRandom() ([]*cltypes.SignedBeaconBlock, *state.CachingBeaconSta
ret := make([]*cltypes.SignedBeaconBlock, 0, 96)
// format for blocks is blocks_{i}.ssz_snappy where i is the index of the block, starting from 0 to 95 included.
for i := 0; i < 96; i++ {
block := cltypes.NewSignedBeaconBlock(&clparams.MainnetBeaconConfig)
block := cltypes.NewSignedBeaconBlock(&clparams.MainnetBeaconConfig, clparams.BellatrixVersion)
// Lets do te
b, err := bellatrixFS.ReadFile("test_data/bellatrix/blocks_" + strconv.Itoa(i) + ".ssz_snappy")
if err != nil {
Expand Down
Loading

0 comments on commit c6bf9aa

Please sign in to comment.