11package aggregator
22
33import (
4+ "os"
45 "testing"
56
67 "github.com/ava-labs/avalanchego/ids"
78 "github.com/ava-labs/avalanchego/message"
9+ "github.com/ava-labs/avalanchego/subnets"
10+ "github.com/ava-labs/avalanchego/utils"
811 "github.com/ava-labs/avalanchego/utils/constants"
12+ "github.com/ava-labs/avalanchego/utils/crypto/bls"
913 "github.com/ava-labs/avalanchego/utils/logging"
14+ "github.com/ava-labs/avalanchego/utils/set"
1015 "github.com/ava-labs/avalanchego/vms/platformvm/warp"
1116 "github.com/ava-labs/awm-relayer/peers"
1217 "github.com/ava-labs/awm-relayer/peers/mocks"
1318 "github.com/ava-labs/awm-relayer/signature-aggregator/metrics"
19+ evmMsg "github.com/ava-labs/subnet-evm/plugin/evm/message"
1420 "github.com/prometheus/client_golang/prometheus"
1521 "github.com/stretchr/testify/require"
1622 "go.uber.org/mock/gomock"
23+ "go.uber.org/zap"
24+ "go.uber.org/zap/zapcore"
1725)
1826
19- var sigAggMetrics * metrics.SignatureAggregatorMetrics
20- var messageCreator message.Creator
27+ const validatorCount = 2
28+
29+ var (
30+ sigAggMetrics * metrics.SignatureAggregatorMetrics
31+ messageCreator message.Creator
32+ validatorSecretKeys []* bls.SecretKey
33+ )
2134
2235func instantiateAggregator (t * testing.T ) (
2336 * SignatureAggregator ,
@@ -39,7 +52,16 @@ func instantiateAggregator(t *testing.T) (
3952 }
4053 aggregator , err := NewSignatureAggregator (
4154 mockNetwork ,
42- logging.NoLog {},
55+ logging .NewLogger (
56+ "aggregator_test" ,
57+ logging .NewWrappedCore (
58+ logging .Debug ,
59+ os .Stdout ,
60+ zapcore .NewConsoleEncoder (
61+ zap .NewProductionEncoderConfig (),
62+ ),
63+ ),
64+ ),
4365 1024 ,
4466 sigAggMetrics ,
4567 messageCreator ,
@@ -48,6 +70,63 @@ func instantiateAggregator(t *testing.T) (
4870 return aggregator , mockNetwork
4971}
5072
73+ func makeConnectedValidators () * peers.ConnectedCanonicalValidators {
74+ var validatorSet []* warp.Validator
75+ for i := 0 ; i < validatorCount ; i ++ {
76+ secretKey , err := bls .NewSecretKey ()
77+ if err != nil {
78+ panic (err )
79+ }
80+ validatorSecretKeys = append (validatorSecretKeys , secretKey )
81+
82+ pubKey := bls .PublicFromSecretKey (secretKey )
83+
84+ nodeID , err := ids .ToNodeID (utils .RandomBytes (20 ))
85+ if err != nil {
86+ panic (err )
87+ }
88+
89+ validatorSet = append (validatorSet ,
90+ & warp.Validator {
91+ PublicKey : pubKey ,
92+ PublicKeyBytes : bls .PublicKeyToUncompressedBytes (pubKey ),
93+ Weight : 1 ,
94+ NodeIDs : []ids.NodeID {nodeID },
95+ },
96+ )
97+ }
98+
99+ nodeValidatorIndexMap := make (map [ids.NodeID ]int )
100+ for i , vdr := range validatorSet {
101+ for _ , node := range vdr .NodeIDs {
102+ nodeValidatorIndexMap [node ] = i
103+ }
104+ }
105+
106+
107+ return & peers.ConnectedCanonicalValidators {
108+ ConnectedWeight : validatorCount ,
109+ TotalValidatorWeight : validatorCount ,
110+ ValidatorSet : validatorSet ,
111+ NodeValidatorIndexMap : nodeValidatorIndexMap ,
112+ }
113+ }
114+
115+ func minimumViableAppRequest (requestID uint32 , nodeID ids.NodeID ) ids.RequestID {
116+ chainID , err := ids .ToID (utils .RandomBytes (32 ))
117+ if err != nil {
118+ panic (err )
119+ }
120+
121+ return ids.RequestID {
122+ NodeID : nodeID ,
123+ SourceChainID : chainID ,
124+ DestinationChainID : chainID ,
125+ RequestID : requestID ,
126+ Op : byte (message .AppResponseOp ),
127+ }
128+ }
129+
51130func TestCreateSignedMessageFailsWithNoValidators (t * testing.T ) {
52131 aggregator , mockNetwork := instantiateAggregator (t )
53132 msg , err := warp .NewUnsignedMessage (0 , ids .Empty , []byte {})
@@ -85,3 +164,162 @@ func TestCreateSignedMessageFailsWithoutSufficientConnectedStake(t *testing.T) {
85164 "failed to connect to a threshold of stake" ,
86165 )
87166}
167+
168+ func TestCreateSignedMessageRetriesAndFailsWithoutP2PResponses (t * testing.T ) {
169+ aggregator , mockNetwork := instantiateAggregator (t )
170+
171+ var (
172+ connectedValidators = makeConnectedValidators ()
173+ requestID = aggregator .currentRequestID .Load () + 1
174+ )
175+
176+ chainID , err := ids .ToID (utils .RandomBytes (32 ))
177+ if err != nil {
178+ panic (err )
179+ }
180+
181+ appRequest1 := ids.RequestID {
182+ NodeID : connectedValidators .ValidatorSet [1 ].NodeIDs [0 ],
183+ SourceChainID : chainID ,
184+ DestinationChainID : chainID ,
185+ RequestID : requestID ,
186+ Op : byte (message .AppResponseOp ),
187+ }
188+ appRequest2 := ids.RequestID {
189+ NodeID : connectedValidators .ValidatorSet [0 ].NodeIDs [0 ],
190+ SourceChainID : chainID ,
191+ DestinationChainID : chainID ,
192+ RequestID : requestID ,
193+ Op : byte (message .AppResponseOp ),
194+ }
195+
196+ msg , err := warp .NewUnsignedMessage (
197+ 0 ,
198+ appRequest1 .SourceChainID ,
199+ []byte {},
200+ )
201+ require .Equal (t , err , nil )
202+
203+ subnetID , err := ids .ToID (utils .RandomBytes (32 ))
204+ require .Equal (t , err , nil )
205+ mockNetwork .EXPECT ().GetSubnetID (appRequest1 .SourceChainID ).Return (
206+ subnetID ,
207+ nil ,
208+ )
209+
210+ mockNetwork .EXPECT ().ConnectToCanonicalValidators (subnetID ).Return (
211+ connectedValidators ,
212+ nil ,
213+ )
214+
215+ for i := 0 ; i < maxRelayerQueryAttempts ; i ++ {
216+ mockNetwork .EXPECT ().RegisterAppRequest (appRequest1 ).Times (1 )
217+ mockNetwork .EXPECT ().RegisterAppRequest (appRequest2 ).Times (1 )
218+ }
219+
220+ validatorCount := len (connectedValidators .ValidatorSet )
221+ mockNetwork .EXPECT ().RegisterRequestID (
222+ requestID ,
223+ validatorCount ,
224+ ).Return (
225+ make (chan message.InboundMessage , validatorCount ),
226+ ).MaxTimes (maxRelayerQueryAttempts * validatorCount )
227+
228+ mockNetwork .EXPECT ().Send (
229+ gomock .Any (),
230+ set .Of (appRequest1 .NodeID , appRequest2 .NodeID ),
231+ subnetID ,
232+ subnets .NoOpAllower ,
233+ ).MaxTimes (maxRelayerQueryAttempts )
234+
235+ _ , err = aggregator .CreateSignedMessage (msg , subnetID , 80 )
236+ require .ErrorContains (
237+ t ,
238+ err ,
239+ "failed to collect a threshold of signatures" ,
240+ )
241+ }
242+
243+ func TestCreateSignedMessageSucceeds (t * testing.T ) {
244+ aggregator , mockNetwork := instantiateAggregator (t )
245+
246+ var (
247+ connectedValidators = makeConnectedValidators ()
248+ requestID = aggregator .currentRequestID .Load () + 1
249+ )
250+
251+ chainID , err := ids .ToID (utils .RandomBytes (32 ))
252+ if err != nil {
253+ panic (err )
254+ }
255+
256+ appRequest1 := ids.RequestID {
257+ NodeID : connectedValidators .ValidatorSet [1 ].NodeIDs [0 ],
258+ SourceChainID : chainID ,
259+ DestinationChainID : chainID ,
260+ RequestID : requestID ,
261+ Op : byte (message .AppResponseOp ),
262+ }
263+ appRequest2 := ids.RequestID {
264+ NodeID : connectedValidators .ValidatorSet [0 ].NodeIDs [0 ],
265+ SourceChainID : chainID ,
266+ DestinationChainID : chainID ,
267+ RequestID : requestID ,
268+ Op : byte (message .AppResponseOp ),
269+ }
270+
271+ msg , err := warp .NewUnsignedMessage (0 , chainID , utils .RandomBytes (1234 ))
272+ require .Equal (t , err , nil )
273+
274+ subnetID , err := ids .ToID (utils .RandomBytes (32 ))
275+ require .Equal (t , err , nil )
276+ mockNetwork .EXPECT ().GetSubnetID (chainID ).Return (
277+ subnetID ,
278+ nil ,
279+ )
280+
281+ mockNetwork .EXPECT ().ConnectToCanonicalValidators (subnetID ).Return (
282+ connectedValidators ,
283+ nil ,
284+ )
285+
286+ mockNetwork .EXPECT ().RegisterAppRequest (appRequest1 ).Times (1 )
287+ mockNetwork .EXPECT ().RegisterAppRequest (appRequest2 ).Times (1 )
288+
289+ responseChan := make (chan message.InboundMessage , 2 )
290+ for i := 0 ; i < validatorCount ; i ++ {
291+ responseBytes , err := evmMsg .Codec .Marshal (
292+ 0 ,
293+ & evmMsg.SignatureResponse {
294+ Signature : [bls .SignatureLen ]byte (
295+ bls .SignatureToBytes (
296+ bls .Sign (
297+ validatorSecretKeys [i ],
298+ msg .Bytes (),
299+ ),
300+ ),
301+ ),
302+ },
303+ )
304+ require .Equal (t , err , nil )
305+ responseChan <- message .InboundAppResponse (
306+ chainID ,
307+ requestID ,
308+ responseBytes ,
309+ connectedValidators .ValidatorSet [i ].NodeIDs [0 ],
310+ )
311+ }
312+ mockNetwork .EXPECT ().RegisterRequestID (requestID , 2 ).Return (
313+ responseChan ,
314+ ).Times (1 )
315+
316+ mockNetwork .EXPECT ().Send (
317+ gomock .Any (),
318+ set .Of (appRequest2 .NodeID , appRequest1 .NodeID ),
319+ subnetID ,
320+ subnets .NoOpAllower ,
321+ ).Times (1 ).Return (set .Of (appRequest2 .NodeID , appRequest1 .NodeID ))
322+
323+ _ , err = aggregator .CreateSignedMessage (msg , subnetID , 80 )
324+ require .Equal (t , err , nil )
325+ }
0 commit comments