Skip to content

Commit a3a0ae8

Browse files
Merge pull request #548 from blockchainluffy/feat/agg_msg_handling
Feat: bls aggregate signature and message
2 parents 763f1c6 + 70ba4cd commit a3a0ae8

11 files changed

+1224
-64
lines changed

rolling-shutter/README-dev.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ can install them to the `bin` directory by running
1919

2020
Run `make test` to run the tests
2121

22+
For any static test data, please use `../testdata` folder.
23+
2224
## Linting
2325

2426
Run `make lint` to run `golangci-lint`. Run `make lint-changes` to run

rolling-shutter/keyperimpl/gnosis/validatorsyncer.go

Lines changed: 79 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package gnosis
22

33
import (
44
"context"
5+
"fmt"
56
"math"
67
"math/big"
78

@@ -24,8 +25,7 @@ import (
2425
)
2526

2627
const (
27-
ValidatorRegistrationMessageVersion = 0
28-
maxRequestBlockRange = 10_000
28+
maxRequestBlockRange = 10_000
2929
)
3030

3131
type ValidatorSyncer struct {
@@ -150,61 +150,83 @@ func (v *ValidatorSyncer) filterEvents(
150150
Uint("log-index", event.Raw.Index).
151151
Logger()
152152

153-
msg := new(validatorregistry.RegistrationMessage)
153+
msg := new(validatorregistry.AggregateRegistrationMessage)
154154
err := msg.Unmarshal(event.Message)
155155
if err != nil {
156156
evLog.Warn().
157157
Err(err).
158158
Msg("failed to unmarshal registration message")
159159
continue
160160
}
161-
evLog = evLog.With().Uint64("validator-index", msg.ValidatorIndex).Logger()
162161

163162
if !checkStaticRegistrationMessageFields(msg, v.ChainID, event.Raw.Address, evLog) {
164163
continue
165164
}
166165

167-
latestNonce, err := db.GetValidatorRegistrationNonceBefore(ctx, database.GetValidatorRegistrationNonceBeforeParams{
168-
ValidatorIndex: int64(msg.ValidatorIndex),
169-
BlockNumber: int64(event.Raw.BlockNumber),
170-
TxIndex: int64(event.Raw.TxIndex),
171-
LogIndex: int64(event.Raw.Index),
172-
})
173-
if err != nil && err != pgx.ErrNoRows {
174-
return nil, errors.Wrapf(err, "failed to query latest nonce for validator %d", msg.ValidatorIndex)
175-
}
176-
if err == pgx.ErrNoRows {
177-
latestNonce = -1
178-
}
179-
if msg.Nonce > math.MaxInt64 || int64(msg.Nonce) <= latestNonce {
180-
evLog.Warn().
181-
Uint64("nonce", msg.Nonce).
182-
Int64("latest-nonce", latestNonce).
183-
Msg("ignoring registration message with invalid nonce")
184-
continue
185-
}
166+
pubKeys := make([]*blst.P1Affine, 0)
167+
for _, validatorIndex := range msg.ValidatorIndices() {
168+
evLog = evLog.With().Int64("validator-index", validatorIndex).Logger()
169+
latestNonce, err := db.GetValidatorRegistrationNonceBefore(ctx, database.GetValidatorRegistrationNonceBeforeParams{
170+
ValidatorIndex: validatorIndex,
171+
BlockNumber: int64(event.Raw.BlockNumber),
172+
TxIndex: int64(event.Raw.TxIndex),
173+
LogIndex: int64(event.Raw.Index),
174+
})
175+
if err != nil && err != pgx.ErrNoRows {
176+
return nil, errors.Wrapf(err, "failed to query latest nonce for validator %d", msg.ValidatorIndex)
177+
}
178+
if err == pgx.ErrNoRows {
179+
latestNonce = -1
180+
}
186181

187-
validator, err := v.BeaconAPIClient.GetValidatorByIndex(ctx, "head", msg.ValidatorIndex)
188-
if err != nil {
189-
return nil, errors.Wrapf(err, "failed to get validator %d", msg.ValidatorIndex)
190-
}
191-
if validator == nil {
192-
evLog.Warn().Msg("ignoring registration message for unknown validator")
193-
continue
194-
}
195-
pubkey, err := validator.Data.Validator.GetPubkey()
196-
if err != nil {
197-
return nil, errors.Wrapf(err, "failed to get pubkey of validator %d", msg.ValidatorIndex)
182+
if msg.Nonce > math.MaxInt32 || int64(msg.Nonce) <= latestNonce {
183+
evLog.Warn().
184+
Uint32("nonce", msg.Nonce).
185+
Int64("latest-nonce", latestNonce).
186+
Msg("ignoring registration message with invalid nonce")
187+
continue
188+
}
189+
190+
validator, err := v.BeaconAPIClient.GetValidatorByIndex(ctx, "head", uint64(validatorIndex))
191+
if err != nil {
192+
return nil, errors.Wrapf(err, "failed to get validator %d", msg.ValidatorIndex)
193+
}
194+
if validator == nil {
195+
evLog.Warn().Msg("ignoring registration message for unknown validator")
196+
continue
197+
}
198+
pubkey, err := validator.Data.Validator.GetPubkey()
199+
if err != nil {
200+
return nil, errors.Wrapf(err, "failed to get pubkey of validator %d", msg.ValidatorIndex)
201+
}
202+
pubKeys = append(pubKeys, pubkey)
198203
}
204+
199205
sig := new(blst.P2Affine).Uncompress(event.Signature)
200206
if sig == nil {
201207
evLog.Warn().Msg("ignoring registration message with undecodable signature")
202208
continue
203209
}
204-
validSignature := validatorregistry.VerifySignature(sig, pubkey, msg)
205-
if !validSignature {
206-
evLog.Warn().Msg("ignoring registration message with invalid signature")
207-
continue
210+
211+
if msg.Version == validatorregistry.LegacyValidatorRegistrationMessageVersion {
212+
msg := new(validatorregistry.LegacyRegistrationMessage)
213+
err := msg.Unmarshal(event.Message)
214+
if err != nil {
215+
evLog.Warn().
216+
Err(err).
217+
Msg("failed to unmarshal registration message")
218+
continue
219+
}
220+
if validSignature := validatorregistry.VerifySignature(sig, pubKeys[0], msg); !validSignature {
221+
evLog.Warn().Msg("ignoring registration message with invalid signature")
222+
continue
223+
}
224+
} else {
225+
validSignature := validatorregistry.VerifyAggregateSignature(sig, pubKeys, msg)
226+
if !validSignature {
227+
evLog.Warn().Msg("ignoring registration message with invalid signature")
228+
continue
229+
}
208230
}
209231

210232
filteredEvents = append(filteredEvents, event)
@@ -215,37 +237,41 @@ func (v *ValidatorSyncer) filterEvents(
215237
func (v *ValidatorSyncer) insertEvents(ctx context.Context, tx pgx.Tx, events []*validatorRegistryBindings.ValidatorregistryUpdated) error {
216238
db := database.New(tx)
217239
for _, event := range events {
218-
msg := new(validatorregistry.RegistrationMessage)
240+
msg := new(validatorregistry.AggregateRegistrationMessage)
219241
err := msg.Unmarshal(event.Message)
220242
if err != nil {
221243
return errors.Wrap(err, "failed to unmarshal registration message")
222244
}
223-
err = db.InsertValidatorRegistration(ctx, database.InsertValidatorRegistrationParams{
224-
BlockNumber: int64(event.Raw.BlockNumber),
225-
BlockHash: event.Raw.BlockHash.Bytes(),
226-
TxIndex: int64(event.Raw.TxIndex),
227-
LogIndex: int64(event.Raw.Index),
228-
ValidatorIndex: int64(msg.ValidatorIndex),
229-
Nonce: int64(msg.Nonce),
230-
IsRegistration: msg.IsRegistration,
231-
})
232-
if err != nil {
233-
return errors.Wrap(err, "failed to insert validator registration into db")
245+
for _, validatorIndex := range msg.ValidatorIndices() {
246+
err = db.InsertValidatorRegistration(ctx, database.InsertValidatorRegistrationParams{
247+
BlockNumber: int64(event.Raw.BlockNumber),
248+
BlockHash: event.Raw.BlockHash.Bytes(),
249+
TxIndex: int64(event.Raw.TxIndex),
250+
LogIndex: int64(event.Raw.Index),
251+
ValidatorIndex: validatorIndex,
252+
Nonce: int64(msg.Nonce),
253+
IsRegistration: msg.IsRegistration,
254+
})
255+
if err != nil {
256+
return errors.Wrap(err, "failed to insert validator registration into db")
257+
}
234258
}
235259
}
236260
return nil
237261
}
238262

239263
func checkStaticRegistrationMessageFields(
240-
msg *validatorregistry.RegistrationMessage,
264+
msg *validatorregistry.AggregateRegistrationMessage,
241265
chainID uint64,
242266
validatorRegistryAddress common.Address,
243267
logger zerolog.Logger,
244268
) bool {
245-
if msg.Version != ValidatorRegistrationMessageVersion {
269+
if msg.Version != validatorregistry.AggregateValidatorRegistrationMessageVersion &&
270+
msg.Version != validatorregistry.LegacyValidatorRegistrationMessageVersion {
246271
logger.Warn().
247272
Uint8("version", msg.Version).
248-
Uint8("expected-version", ValidatorRegistrationMessageVersion).
273+
Str("expected-version", fmt.Sprintf("%d or %d", validatorregistry.LegacyValidatorRegistrationMessageVersion,
274+
validatorregistry.AggregateValidatorRegistrationMessageVersion)).
249275
Uint64("validator-index", msg.ValidatorIndex).
250276
Msg("ignoring registration message with invalid version")
251277
return false
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package gnosis
2+
3+
import (
4+
"context"
5+
"encoding/hex"
6+
"encoding/json"
7+
"io"
8+
"net/http"
9+
"net/http/httptest"
10+
"os"
11+
"strings"
12+
"testing"
13+
14+
"github.com/ethereum/go-ethereum/common"
15+
"github.com/ethereum/go-ethereum/core/types"
16+
validatorRegistryBindings "github.com/shutter-network/gnosh-contracts/gnoshcontracts/validatorregistry"
17+
"gotest.tools/assert"
18+
19+
"github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/gnosis/database"
20+
"github.com/shutter-network/rolling-shutter/rolling-shutter/medley/beaconapiclient"
21+
"github.com/shutter-network/rolling-shutter/rolling-shutter/medley/testsetup"
22+
)
23+
24+
func TestAggregateValidationWithData(t *testing.T) {
25+
if testing.Short() {
26+
t.Skip("skipping integration test")
27+
}
28+
ctx := context.Background()
29+
url := mockBeaconClientWithJSONData(t)
30+
cl, err := beaconapiclient.New(url)
31+
assert.NilError(t, err)
32+
dbpool, dbclose := testsetup.NewTestDBPool(ctx, t, database.Definition)
33+
t.Cleanup(dbclose)
34+
vs := ValidatorSyncer{
35+
BeaconAPIClient: cl,
36+
DBPool: dbpool,
37+
ChainID: 10200,
38+
}
39+
40+
msg := readMsg(t)
41+
42+
message, err := hex.DecodeString(msg["message"][2:])
43+
assert.NilError(t, err)
44+
45+
signature, err := hex.DecodeString(msg["signature"][2:])
46+
assert.NilError(t, err)
47+
48+
events := []*validatorRegistryBindings.ValidatorregistryUpdated{{
49+
Signature: signature,
50+
Message: message,
51+
Raw: types.Log{
52+
Address: common.HexToAddress("0xa9289A3Dd14FEBe10611119bE81E5d35eAaC3084"),
53+
},
54+
}}
55+
56+
finalEvents, err := vs.filterEvents(ctx, events)
57+
assert.NilError(t, err)
58+
59+
assert.DeepEqual(t, len(finalEvents), 1)
60+
}
61+
62+
func mockBeaconClientWithJSONData(t *testing.T) string {
63+
t.Helper()
64+
jsonFile, err := os.Open("../../../testdata/validatorInfo_0x01.json")
65+
assert.NilError(t, err)
66+
defer jsonFile.Close()
67+
68+
byteValue, _ := io.ReadAll(jsonFile)
69+
var result map[string]string
70+
err = json.Unmarshal(byteValue, &result)
71+
assert.NilError(t, err)
72+
73+
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
74+
parts := strings.Split(r.URL.Path, "/")
75+
76+
x := beaconapiclient.GetValidatorByIndexResponse{
77+
Finalized: true,
78+
Data: beaconapiclient.ValidatorData{
79+
Validator: beaconapiclient.Validator{
80+
PubkeyHex: result[parts[len(parts)-1]],
81+
},
82+
},
83+
}
84+
res, err := json.Marshal(x)
85+
assert.NilError(t, err)
86+
w.WriteHeader(http.StatusOK)
87+
_, err = w.Write(res)
88+
assert.NilError(t, err)
89+
})).URL
90+
}
91+
92+
func readMsg(t *testing.T) map[string]string {
93+
t.Helper()
94+
jsonFile, err := os.Open("../../../testdata/signedRegistrations_0x01.json")
95+
assert.NilError(t, err)
96+
defer jsonFile.Close()
97+
98+
byteValue, _ := io.ReadAll(jsonFile)
99+
var result map[string]string
100+
err = json.Unmarshal(byteValue, &result)
101+
assert.NilError(t, err)
102+
return result
103+
}

0 commit comments

Comments
 (0)