@@ -3,6 +3,7 @@ package signer
3
3
import (
4
4
"encoding/hex"
5
5
"fmt"
6
+ "sync"
6
7
"testing"
7
8
"time"
8
9
@@ -134,6 +135,117 @@ func TestLockSameValidatorInParallel(t *testing.T) {
134
135
135
136
}
136
137
138
+ func TestManyValidatorsParallel (t * testing.T ) {
139
+ type testValidator struct {
140
+ sk []byte
141
+ pk []byte
142
+ id string
143
+ }
144
+
145
+ testValidators := []testValidator {
146
+ {
147
+ sk : _byteArray ("2c083f2c8fc923fa2bd32a70ab72b4b46247e8c1f347adc30b2f8036a355086c" ),
148
+ pk : _byteArray ("a9cf360aa15fb1d1d30ee2b578dc5884823c19661886ae8b892775ccb3bd96b7d7345569a2aa0b14e4d015c54a6a0c54" ),
149
+ id : "1" ,
150
+ },
151
+ {
152
+ sk : _byteArray ("6327b1e58c41d60dd7c3c8b9634204255707c2d12e2513c345001d8926745eea" ),
153
+ pk : _byteArray ("954eb88ed1207f891dc3c28fa6cfdf8f53bf0ed3d838f3476c0900a61314d22d4f0a300da3cd010444dd5183e35a593c" ),
154
+ id : "2" ,
155
+ },
156
+ {
157
+ sk : _byteArray ("5470813f7deef638dc531188ca89e36976d536f680e89849cd9077fd096e20bc" ),
158
+ pk : _byteArray ("a3862121db5914d7272b0b705e6e3c5336b79e316735661873566245207329c30f9a33d4fb5f5857fc6fd0a368186972" ),
159
+ id : "3" ,
160
+ },
161
+ }
162
+
163
+ attestationDataByts := _byteArray ("000000000000000000000000000000003a43a4bf26fb5947e809c1f24f7dc6857c8ac007e535d48e6e4eca2122fd776b0000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000003a43a4bf26fb5947e809c1f24f7dc6857c8ac007e535d48e6e4eca2122fd776b" )
164
+ domain := _byteArray32 ("0100000081509579e35e84020ad8751eca180b44df470332d3ad17fc6fd52459" )
165
+
166
+ // setup KeyVault
167
+ store := inmemStorage ()
168
+ options := & eth2keymanager.KeyVaultOptions {}
169
+ options .SetStorage (store )
170
+ options .SetWalletType (core .NDWallet )
171
+ vault , err := eth2keymanager .NewKeyVault (options )
172
+ require .NoError (t , err )
173
+ wallet , err := vault .Wallet ()
174
+ require .NoError (t , err )
175
+
176
+ // create accounts
177
+ protector := prot .NewNormalProtection (store )
178
+ for i := range testValidators {
179
+ k , err := core .NewHDKeyFromPrivateKey (testValidators [i ].sk , "" )
180
+ require .NoError (t , err )
181
+ require .EqualValues (t , testValidators [i ].pk , k .PublicKey ().Serialize ())
182
+
183
+ acc := wallets .NewValidatorAccount (testValidators [i ].id , k , nil , "" , vault .Context )
184
+ require .NoError (t , err )
185
+ require .EqualValues (t , testValidators [i ].pk , acc .ValidatorPublicKey ())
186
+ require .NoError (t , wallet .AddValidatorAccount (acc ))
187
+
188
+ // setup base attestation data
189
+ baseAttData := & phase0.AttestationData {}
190
+ require .NoError (t , baseAttData .UnmarshalSSZ (attestationDataByts ))
191
+ err = protector .UpdateHighestAttestation (acc .ValidatorPublicKey (), baseAttData )
192
+ require .NoError (t , err )
193
+ }
194
+
195
+ // setup signer
196
+ signer := NewSimpleSigner (wallet , protector , core .PraterNetwork )
197
+
198
+ // Sign attestation in parallel.
199
+ type validatorResult struct {
200
+ signs int
201
+ errs int
202
+ }
203
+ var validatorResults = map [string ]* validatorResult {}
204
+ var mu sync.Mutex
205
+ for _ , v := range testValidators {
206
+ validatorResults [string (v .pk )] = & validatorResult {}
207
+ }
208
+
209
+ var wg sync.WaitGroup
210
+ const goroutinesPerValidator = 10
211
+ for _ , v := range testValidators {
212
+ v := v
213
+ for i := 0 ; i < goroutinesPerValidator ; i ++ {
214
+ wg .Add (1 )
215
+ go func () {
216
+ defer wg .Done ()
217
+
218
+ // decode attestation to be signed
219
+ attData := & phase0.AttestationData {}
220
+ require .NoError (t , attData .UnmarshalSSZ (attestationDataByts ))
221
+ attData .Slot += phase0 .Slot (core .PraterNetwork .SlotsPerEpoch ())
222
+ attData .Source .Epoch ++
223
+ attData .Target .Epoch ++
224
+
225
+ _ , _ , err := signer .SignBeaconAttestation (attData , domain , v .pk )
226
+ // require.EqualValues(t, sig, actualSig)
227
+
228
+ mu .Lock ()
229
+ defer mu .Unlock ()
230
+ if err != nil {
231
+ validatorResults [string (v .pk )].errs ++
232
+ require .ErrorContains (t , err , "slashable attestation (HighestAttestationVote), not signing" )
233
+ } else {
234
+ validatorResults [string (v .pk )].signs ++
235
+ }
236
+ }()
237
+ }
238
+ }
239
+ wg .Wait ()
240
+
241
+ for pk , v := range validatorResults {
242
+ t .Logf ("pk: %x, signs: %d, errs: %d" , []byte (pk ), v .signs , v .errs )
243
+
244
+ require .Equal (t , 1 , v .signs )
245
+ require .Equal (t , goroutinesPerValidator - 1 , v .errs )
246
+ }
247
+ }
248
+
137
249
func TestAttestationSlashingSignatures (t * testing.T ) {
138
250
t .Run ("valid attestation, sign using public key" , func (t * testing.T ) {
139
251
seed , _ := hex .DecodeString ("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1fff" )
0 commit comments