Skip to content

Commit a924d9d

Browse files
authored
Fix failure in block production (#13840)
- After Electra, the aggregation bits indicate the bit-maps that appear only in the committee bits, so merge them in a way similar to merge sort - Fix bugs in BitList structure - Remove the problematic SetVersion() function that leads to the empty attestation bug
1 parent 0e9a509 commit a924d9d

File tree

11 files changed

+264
-136
lines changed

11 files changed

+264
-136
lines changed

cl/aggregation/pool_impl.go

Lines changed: 36 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ package aggregation
1919
import (
2020
"context"
2121
"errors"
22-
"fmt"
2322
"sync"
2423
"time"
2524

2625
"github.com/Giulio2002/bls"
2726
"github.com/erigontech/erigon-lib/common"
27+
"github.com/erigontech/erigon-lib/log/v3"
2828
"github.com/erigontech/erigon/cl/clparams"
2929
"github.com/erigontech/erigon/cl/cltypes/solid"
3030
"github.com/erigontech/erigon/cl/phase1/core/state/lru"
@@ -44,7 +44,7 @@ type aggregationPoolImpl struct {
4444
netConfig *clparams.NetworkConfig
4545
ethClock eth_clock.EthereumClock
4646
aggregatesLock sync.RWMutex
47-
aggregates map[common.Hash]*solid.Attestation
47+
aggregates map[common.Hash]*solid.Attestation // don't need this anymore after electra upgrade
4848
// aggregationInCommittee is a cache for aggregation in committee, which is used after electra upgrade
4949
aggregatesInCommittee *lru.CacheWithTTL[keyAggrInCommittee, *solid.Attestation]
5050
}
@@ -78,68 +78,48 @@ func (p *aggregationPoolImpl) AddAttestation(inAtt *solid.Attestation) error {
7878
if err != nil {
7979
return err
8080
}
81-
p.aggregatesLock.Lock()
82-
defer p.aggregatesLock.Unlock()
83-
att, ok := p.aggregates[hashRoot]
84-
if !ok {
85-
p.aggregates[hashRoot] = inAtt.Copy()
86-
return nil
87-
}
88-
89-
if utils.IsOverlappingSSZBitlist(att.AggregationBits.Bytes(), inAtt.AggregationBits.Bytes()) {
90-
// the on bit is already set, so ignore
91-
return ErrIsSuperset
92-
}
9381

94-
// merge signature
95-
baseSig := att.Signature
96-
inSig := inAtt.Signature
97-
merged, err := blsAggregate([][]byte{baseSig[:], inSig[:]})
98-
if err != nil {
99-
return err
100-
}
101-
if len(merged) != 96 {
102-
return errors.New("merged signature is too long")
103-
}
104-
var mergedSig [96]byte
105-
copy(mergedSig[:], merged)
106-
107-
epoch := p.ethClock.GetEpochAtSlot(att.Data.Slot)
82+
epoch := p.ethClock.GetEpochAtSlot(inAtt.Data.Slot)
10883
clversion := p.ethClock.StateVersionByEpoch(epoch)
10984
if clversion.BeforeOrEqual(clparams.DenebVersion) {
110-
// merge aggregation bits
111-
mergedBits, err := att.AggregationBits.Union(inAtt.AggregationBits)
112-
if err != nil {
113-
return err
85+
p.aggregatesLock.Lock()
86+
defer p.aggregatesLock.Unlock()
87+
att, ok := p.aggregates[hashRoot]
88+
if !ok {
89+
p.aggregates[hashRoot] = inAtt.Copy()
90+
return nil
11491
}
115-
// update attestation
116-
p.aggregates[hashRoot] = &solid.Attestation{
117-
AggregationBits: mergedBits,
118-
Data: att.Data,
119-
Signature: mergedSig,
92+
93+
if utils.IsOverlappingSSZBitlist(att.AggregationBits.Bytes(), inAtt.AggregationBits.Bytes()) {
94+
// the on bit is already set, so ignore
95+
return ErrIsSuperset
12096
}
121-
} else {
122-
// Electra and after case
123-
aggrBitSize := p.beaconConfig.MaxCommitteesPerSlot * p.beaconConfig.MaxValidatorsPerCommittee
124-
mergedAggrBits, err := att.AggregationBits.Union(inAtt.AggregationBits)
97+
// merge signature
98+
baseSig := att.Signature
99+
inSig := inAtt.Signature
100+
merged, err := blsAggregate([][]byte{baseSig[:], inSig[:]})
125101
if err != nil {
126102
return err
127103
}
128-
if mergedAggrBits.Cap() != int(aggrBitSize) {
129-
return fmt.Errorf("incorrect aggregation bits size: %d", mergedAggrBits.Cap())
104+
if len(merged) != 96 {
105+
return errors.New("merged signature is too long")
130106
}
131-
mergedCommitteeBits, err := att.CommitteeBits.Union(inAtt.CommitteeBits)
107+
var mergedSig [96]byte
108+
copy(mergedSig[:], merged)
109+
110+
// merge aggregation bits
111+
mergedBits, err := att.AggregationBits.Merge(inAtt.AggregationBits)
132112
if err != nil {
133113
return err
134114
}
115+
// update attestation
135116
p.aggregates[hashRoot] = &solid.Attestation{
136-
AggregationBits: mergedAggrBits,
137-
CommitteeBits: mergedCommitteeBits,
117+
AggregationBits: mergedBits,
138118
Data: att.Data,
139119
Signature: mergedSig,
140120
}
141-
142-
// aggregate by committee
121+
} else {
122+
// Electra and after case, aggregate by committee
143123
p.aggregateByCommittee(inAtt)
144124
}
145125
return nil
@@ -166,9 +146,15 @@ func (p *aggregationPoolImpl) aggregateByCommittee(inAtt *solid.Attestation) err
166146
return nil
167147
}
168148

169-
// merge aggregation bits and signature
170-
mergedAggrBits, err := att.AggregationBits.Union(inAtt.AggregationBits)
149+
if utils.IsOverlappingSSZBitlist(att.AggregationBits.Bytes(), inAtt.AggregationBits.Bytes()) {
150+
// the on bit is already set, so ignore
151+
return ErrIsSuperset
152+
}
153+
154+
// It's fine to directly merge aggregation bits here, because the attestation is from the same committee
155+
mergedAggrBits, err := att.AggregationBits.Merge(inAtt.AggregationBits)
171156
if err != nil {
157+
log.Debug("failed to merge aggregation bits", "err", err)
172158
return err
173159
}
174160
merged, err := blsAggregate([][]byte{att.Signature[:], inAtt.Signature[:]})

cl/aggregation/pool_test.go

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,22 @@ var (
4040
},
4141
}
4242
att1_1 = &solid.Attestation{
43-
AggregationBits: solid.BitlistFromBytes([]byte{0b00000001, 0, 0, 0}, 2048),
43+
AggregationBits: solid.BitlistFromBytes([]byte{0b00000011}, 2048),
4444
Data: attData1,
4545
Signature: [96]byte{'a', 'b', 'c', 'd', 'e', 'f'},
4646
}
4747
att1_2 = &solid.Attestation{
48-
AggregationBits: solid.BitlistFromBytes([]byte{0b00000001, 0, 0, 0}, 2048),
48+
AggregationBits: solid.BitlistFromBytes([]byte{0b00000011}, 2048),
4949
Data: attData1,
5050
Signature: [96]byte{'d', 'e', 'f', 'g', 'h', 'i'},
5151
}
5252
att1_3 = &solid.Attestation{
53-
AggregationBits: solid.BitlistFromBytes([]byte{0b00000100, 0, 0, 0}, 2048),
53+
AggregationBits: solid.BitlistFromBytes([]byte{0b00001100}, 2048),
5454
Data: attData1,
5555
Signature: [96]byte{'g', 'h', 'i', 'j', 'k', 'l'},
5656
}
5757
att1_4 = &solid.Attestation{
58-
AggregationBits: solid.BitlistFromBytes([]byte{0b00100000, 0, 0, 0}, 2048),
58+
AggregationBits: solid.BitlistFromBytes([]byte{0b01100000}, 2048),
5959
Data: attData1,
6060
Signature: [96]byte{'m', 'n', 'o', 'p', 'q', 'r'},
6161
}
@@ -72,7 +72,7 @@ var (
7272
},
7373
}
7474
att2_1 = &solid.Attestation{
75-
AggregationBits: solid.BitlistFromBytes([]byte{0b00000001, 0, 0, 0}, 2048),
75+
AggregationBits: solid.BitlistFromBytes([]byte{0b00000001}, 2048),
7676
Data: attData2,
7777
Signature: [96]byte{'t', 'e', 's', 't', 'i', 'n'},
7878
}
@@ -107,21 +107,21 @@ func (t *PoolTestSuite) TearDownTest() {
107107

108108
func (t *PoolTestSuite) TestAddAttestationElectra() {
109109
cBits1 := solid.NewBitVector(64)
110-
cBits1.SetBitAt(0, true)
110+
cBits1.SetBitAt(10, true)
111111
cBits2 := solid.NewBitVector(64)
112112
cBits2.SetBitAt(10, true)
113113
expectedCommitteeBits := solid.NewBitVector(64)
114-
expectedCommitteeBits.SetBitAt(0, true)
114+
expectedCommitteeBits.SetBitAt(10, true)
115115
expectedCommitteeBits.SetBitAt(10, true)
116116

117117
att1 := &solid.Attestation{
118-
AggregationBits: solid.BitlistFromBytes([]byte{0b00000001, 0, 0, 0}, 2048*64),
118+
AggregationBits: solid.BitlistFromBytes([]byte{0b00000011}, 2048*64),
119119
Data: attData1,
120120
Signature: [96]byte{'a', 'b', 'c', 'd', 'e', 'f'},
121121
CommitteeBits: cBits1,
122122
}
123123
att2 := &solid.Attestation{
124-
AggregationBits: solid.BitlistFromBytes([]byte{0b00000000, 0b00001000, 0, 0}, 2048*64),
124+
AggregationBits: solid.BitlistFromBytes([]byte{0b00001100}, 2048*64),
125125
Data: attData1,
126126
Signature: [96]byte{'d', 'e', 'f', 'g', 'h', 'i'},
127127
CommitteeBits: cBits2,
@@ -141,11 +141,11 @@ func (t *PoolTestSuite) TestAddAttestationElectra() {
141141
},
142142
hashRoot: attData1Root,
143143
mockFunc: func() {
144-
t.mockEthClock.EXPECT().GetEpochAtSlot(gomock.Any()).Return(uint64(1)).Times(1)
145-
t.mockEthClock.EXPECT().StateVersionByEpoch(gomock.Any()).Return(clparams.ElectraVersion).Times(1)
144+
t.mockEthClock.EXPECT().GetEpochAtSlot(gomock.Any()).Return(uint64(1)).Times(2)
145+
t.mockEthClock.EXPECT().StateVersionByEpoch(gomock.Any()).Return(clparams.ElectraVersion).Times(2)
146146
},
147147
expect: &solid.Attestation{
148-
AggregationBits: solid.BitlistFromBytes([]byte{0b0000001, 0b00001000, 0, 0}, 2048*64),
148+
AggregationBits: solid.BitlistFromBytes([]byte{0b00001101}, 2048*64),
149149
Data: attData1,
150150
Signature: mockAggrResult,
151151
CommitteeBits: expectedCommitteeBits,
@@ -162,9 +162,7 @@ func (t *PoolTestSuite) TestAddAttestationElectra() {
162162
for i := range tc.atts {
163163
pool.AddAttestation(tc.atts[i])
164164
}
165-
att := pool.GetAggregatationByRoot(tc.hashRoot)
166-
//h1, _ := tc.expect.HashSSZ()
167-
//h2, _ := att.HashSSZ()
165+
att := pool.GetAggregatationByRootAndCommittee(tc.hashRoot, 10)
168166
t.Equal(tc.expect, att, tc.name)
169167
}
170168
}
@@ -184,7 +182,11 @@ func (t *PoolTestSuite) TestAddAttestation() {
184182
att2_1,
185183
},
186184
hashRoot: attData1Root,
187-
expect: att1_1,
185+
mockFunc: func() {
186+
t.mockEthClock.EXPECT().GetEpochAtSlot(gomock.Any()).Return(uint64(1)).AnyTimes()
187+
t.mockEthClock.EXPECT().StateVersionByEpoch(gomock.Any()).Return(clparams.DenebVersion).AnyTimes()
188+
},
189+
expect: att1_1,
188190
},
189191
{
190192
name: "att1_2 is a super set of att1_1. skip att1_1",
@@ -194,7 +196,11 @@ func (t *PoolTestSuite) TestAddAttestation() {
194196
att2_1, // none of its business
195197
},
196198
hashRoot: attData1Root,
197-
expect: att1_2,
199+
mockFunc: func() {
200+
t.mockEthClock.EXPECT().GetEpochAtSlot(gomock.Any()).Return(uint64(1)).AnyTimes()
201+
t.mockEthClock.EXPECT().StateVersionByEpoch(gomock.Any()).Return(clparams.DenebVersion).AnyTimes()
202+
},
203+
expect: att1_2,
198204
},
199205
{
200206
name: "merge att1_2, att1_3, att1_4",
@@ -209,7 +215,7 @@ func (t *PoolTestSuite) TestAddAttestation() {
209215
t.mockEthClock.EXPECT().StateVersionByEpoch(gomock.Any()).Return(clparams.DenebVersion).AnyTimes()
210216
},
211217
expect: &solid.Attestation{
212-
AggregationBits: solid.BitlistFromBytes([]byte{0b00100101, 0, 0, 0}, 2048),
218+
AggregationBits: solid.BitlistFromBytes([]byte{0b01100101}, 2048),
213219
Data: attData1,
214220
Signature: mockAggrResult,
215221
},
@@ -226,8 +232,6 @@ func (t *PoolTestSuite) TestAddAttestation() {
226232
pool.AddAttestation(tc.atts[i])
227233
}
228234
att := pool.GetAggregatationByRoot(tc.hashRoot)
229-
//h1, _ := tc.expect.HashSSZ()
230-
//h2, _ := att.HashSSZ()
231235
t.Equal(tc.expect, att, tc.name)
232236
}
233237
}

0 commit comments

Comments
 (0)