@@ -13,11 +13,13 @@ import (
1313 _ "embed"
1414
1515 "github.com/ava-labs/avalanchego/ids"
16+ commonEng "github.com/ava-labs/avalanchego/snow/engine/common"
1617 "github.com/ava-labs/avalanchego/snow/engine/snowman/block"
1718 "github.com/ava-labs/avalanchego/snow/validators"
1819 "github.com/ava-labs/avalanchego/snow/validators/validatorstest"
1920 "github.com/ava-labs/avalanchego/upgrade"
2021 avagoUtils "github.com/ava-labs/avalanchego/utils"
22+ "github.com/ava-labs/avalanchego/utils/constants"
2123 "github.com/ava-labs/avalanchego/utils/crypto/bls"
2224 "github.com/ava-labs/avalanchego/utils/set"
2325 "github.com/ava-labs/avalanchego/vms/components/chain"
4547 exampleWarpABI string
4648)
4749
50+ type warpMsgFrom int
51+
52+ const (
53+ fromSubnet warpMsgFrom = iota
54+ fromPrimary
55+ )
56+
57+ type useWarpMsgSigners int
58+
59+ const (
60+ signersSubnet useWarpMsgSigners = iota
61+ signersPrimary
62+ )
63+
4864func TestSendWarpMessage (t * testing.T ) {
4965 require := require .New (t )
5066 genesis := & core.Genesis {}
@@ -404,78 +420,201 @@ func TestReceiveWarpMessage(t *testing.T) {
404420 genesis := & core.Genesis {}
405421 require .NoError (genesis .UnmarshalJSON ([]byte (genesisJSONDurango )))
406422 genesis .Config .GenesisPrecompiles = params.Precompiles {
423+ // Note that warp is enabled without RequirePrimaryNetworkSigners
424+ // by default in the genesis configuration.
407425 warp .ConfigKey : warp .NewDefaultConfig (utils .TimeToNewUint64 (upgrade .InitiallyActiveTime )),
408426 }
409427 genesisJSON , err := genesis .MarshalJSON ()
410428 require .NoError (err )
411- issuer , vm , _ , _ := GenesisVM (t , true , string (genesisJSON ), "" , "" )
429+
430+ // disable warp so we can re-enable it with RequirePrimaryNetworkSigners
431+ disableTime := upgrade .InitiallyActiveTime .Add (10 * time .Second )
432+ disableConfig := warp .NewDisableConfig (utils .TimeToNewUint64 (disableTime ))
433+
434+ // re-enable warp with RequirePrimaryNetworkSigners
435+ reEnableTime := disableTime .Add (10 * time .Second )
436+ reEnableConfig := warp .NewConfig (
437+ utils .TimeToNewUint64 (reEnableTime ),
438+ 0 , // QuorumNumerator
439+ true , // RequirePrimaryNetworkSigners
440+ )
441+
442+ upgradeConfig := params.UpgradeConfig {
443+ PrecompileUpgrades : []params.PrecompileUpgrade {
444+ {Config : disableConfig },
445+ {Config : reEnableConfig },
446+ },
447+ }
448+ upgradeBytes , err := json .Marshal (upgradeConfig )
449+ require .NoError (err )
450+
451+ issuer , vm , _ , _ := GenesisVM (t , true , string (genesisJSON ), "" , string (upgradeBytes ))
412452
413453 defer func () {
414454 require .NoError (vm .Shutdown (context .Background ()))
415455 }()
416456
417- acceptedLogsChan := make (chan []* types.Log , 10 )
418- logsSub := vm .eth .APIBackend .SubscribeAcceptedLogsEvent (acceptedLogsChan )
419- defer logsSub .Unsubscribe ()
457+ type test struct {
458+ name string
459+ sourceChainID ids.ID
460+ msgFrom warpMsgFrom
461+ useSigners useWarpMsgSigners
462+ blockTime time.Time
463+ }
420464
421- payloadData := avagoUtils .RandomBytes (100 )
465+ blockGap := 2 * time .Second // Build blocks with a gap. Blocks built too quickly will have high fees.
466+ tests := []test {
467+ {
468+ name : "subnet message should be signed by subnet without RequirePrimaryNetworkSigners" ,
469+ sourceChainID : vm .ctx .ChainID ,
470+ msgFrom : fromSubnet ,
471+ useSigners : signersSubnet ,
472+ blockTime : upgrade .InitiallyActiveTime ,
473+ },
474+ {
475+ name : "P-Chain message should be signed by subnet without RequirePrimaryNetworkSigners" ,
476+ sourceChainID : constants .PlatformChainID ,
477+ msgFrom : fromPrimary ,
478+ useSigners : signersSubnet ,
479+ blockTime : upgrade .InitiallyActiveTime .Add (blockGap ),
480+ },
481+ {
482+ name : "C-Chain message should be signed by subnet without RequirePrimaryNetworkSigners" ,
483+ sourceChainID : testCChainID ,
484+ msgFrom : fromPrimary ,
485+ useSigners : signersSubnet ,
486+ blockTime : upgrade .InitiallyActiveTime .Add (2 * blockGap ),
487+ },
488+ // Note here we disable warp and re-enable it with RequirePrimaryNetworkSigners
489+ // by using reEnableTime.
490+ {
491+ name : "subnet message should be signed by subnet with RequirePrimaryNetworkSigners (unimpacted)" ,
492+ sourceChainID : vm .ctx .ChainID ,
493+ msgFrom : fromSubnet ,
494+ useSigners : signersSubnet ,
495+ blockTime : reEnableTime ,
496+ },
497+ {
498+ name : "P-Chain message should be signed by subnet with RequirePrimaryNetworkSigners (unimpacted)" ,
499+ sourceChainID : constants .PlatformChainID ,
500+ msgFrom : fromPrimary ,
501+ useSigners : signersSubnet ,
502+ blockTime : reEnableTime .Add (blockGap ),
503+ },
504+ {
505+ name : "C-Chain message should be signed by primary with RequirePrimaryNetworkSigners (impacted)" ,
506+ sourceChainID : testCChainID ,
507+ msgFrom : fromPrimary ,
508+ useSigners : signersPrimary ,
509+ blockTime : reEnableTime .Add (2 * blockGap ),
510+ },
511+ }
512+ // Note each test corresponds to a block, the tests must be ordered by block
513+ // time and cannot, eg be run in parallel or a separate golang test.
514+ for _ , test := range tests {
515+ testReceiveWarpMessage (
516+ t , issuer , vm , test .sourceChainID , test .msgFrom , test .useSigners , test .blockTime ,
517+ )
518+ }
519+ }
422520
521+ func testReceiveWarpMessage (
522+ t * testing.T , issuer chan commonEng.Message , vm * VM ,
523+ sourceChainID ids.ID ,
524+ msgFrom warpMsgFrom , useSigners useWarpMsgSigners ,
525+ blockTime time.Time ,
526+ ) {
527+ require := require .New (t )
528+ payloadData := avagoUtils .RandomBytes (100 )
423529 addressedPayload , err := payload .NewAddressedCall (
424530 testEthAddrs [0 ].Bytes (),
425531 payloadData ,
426532 )
427533 require .NoError (err )
534+
535+ vm .ctx .SubnetID = ids .GenerateTestID ()
536+ vm .ctx .NetworkID = testNetworkID
428537 unsignedMessage , err := avalancheWarp .NewUnsignedMessage (
429538 vm .ctx .NetworkID ,
430- vm . ctx . ChainID ,
539+ sourceChainID ,
431540 addressedPayload .Bytes (),
432541 )
433542 require .NoError (err )
434543
435- nodeID1 := ids .GenerateTestNodeID ()
436- blsSecretKey1 , err := bls .NewSecretKey ()
437- require .NoError (err )
438- blsPublicKey1 := bls .PublicFromSecretKey (blsSecretKey1 )
439- blsSignature1 := bls .Sign (blsSecretKey1 , unsignedMessage .Bytes ())
544+ type signer struct {
545+ networkID ids.ID
546+ nodeID ids.NodeID
547+ secret * bls.SecretKey
548+ signature * bls.Signature
549+ weight uint64
550+ }
551+ newSigner := func (networkID ids.ID , weight uint64 ) signer {
552+ secret , err := bls .NewSecretKey ()
553+ require .NoError (err )
554+ return signer {
555+ networkID : networkID ,
556+ nodeID : ids .GenerateTestNodeID (),
557+ secret : secret ,
558+ signature : bls .Sign (secret , unsignedMessage .Bytes ()),
559+ weight : weight ,
560+ }
561+ }
440562
441- nodeID2 := ids .GenerateTestNodeID ()
442- blsSecretKey2 , err := bls .NewSecretKey ()
443- require .NoError (err )
444- blsPublicKey2 := bls .PublicFromSecretKey (blsSecretKey2 )
445- blsSignature2 := bls .Sign (blsSecretKey2 , unsignedMessage .Bytes ())
563+ primarySigners := []signer {
564+ newSigner (constants .PrimaryNetworkID , 50 ),
565+ newSigner (constants .PrimaryNetworkID , 50 ),
566+ }
567+ subnetSigners := []signer {
568+ newSigner (vm .ctx .SubnetID , 50 ),
569+ newSigner (vm .ctx .SubnetID , 50 ),
570+ }
571+ signers := subnetSigners
572+ if useSigners == signersPrimary {
573+ signers = primarySigners
574+ }
446575
447- blsAggregatedSignature , err := bls .AggregateSignatures ([]* bls.Signature {blsSignature1 , blsSignature2 })
576+ blsSignatures := make ([]* bls.Signature , len (signers ))
577+ for i := range signers {
578+ blsSignatures [i ] = signers [i ].signature
579+ }
580+ blsAggregatedSignature , err := bls .AggregateSignatures (blsSignatures )
448581 require .NoError (err )
449582
450583 minimumValidPChainHeight := uint64 (10 )
451584 getValidatorSetTestErr := errors .New ("can't get validator set test error" )
452585
453586 vm .ctx .ValidatorState = & validatorstest.State {
454587 GetSubnetIDF : func (ctx context.Context , chainID ids.ID ) (ids.ID , error ) {
455- return ids .Empty , nil
588+ if msgFrom == fromPrimary {
589+ return constants .PrimaryNetworkID , nil
590+ }
591+ return vm .ctx .SubnetID , nil
456592 },
457593 GetValidatorSetF : func (ctx context.Context , height uint64 , subnetID ids.ID ) (map [ids.NodeID ]* validators.GetValidatorOutput , error ) {
458594 if height < minimumValidPChainHeight {
459595 return nil , getValidatorSetTestErr
460596 }
461- return map [ids.NodeID ]* validators.GetValidatorOutput {
462- nodeID1 : {
463- NodeID : nodeID1 ,
464- PublicKey : blsPublicKey1 ,
465- Weight : 50 ,
466- },
467- nodeID2 : {
468- NodeID : nodeID2 ,
469- PublicKey : blsPublicKey2 ,
470- Weight : 50 ,
471- },
472- }, nil
597+ signers := subnetSigners
598+ if subnetID == constants .PrimaryNetworkID {
599+ signers = primarySigners
600+ }
601+
602+ vdrOutput := make (map [ids.NodeID ]* validators.GetValidatorOutput )
603+ for _ , s := range signers {
604+ vdrOutput [s .nodeID ] = & validators.GetValidatorOutput {
605+ NodeID : s .nodeID ,
606+ PublicKey : bls .PublicFromSecretKey (s .secret ),
607+ Weight : s .weight ,
608+ }
609+ }
610+ return vdrOutput , nil
473611 },
474612 }
475613
476614 signersBitSet := set .NewBits ()
477- signersBitSet .Add (0 )
478- signersBitSet .Add (1 )
615+ for i := range signers {
616+ signersBitSet .Add (i )
617+ }
479618
480619 warpSignature := & avalancheWarp.BitSetSignature {
481620 Signers : signersBitSet .Bytes (),
@@ -495,7 +634,7 @@ func TestReceiveWarpMessage(t *testing.T) {
495634 getVerifiedWarpMessageTx , err := types .SignTx (
496635 predicate .NewPredicateTx (
497636 vm .chainConfig .ChainID ,
498- 0 ,
637+ vm . txPool . Nonce ( testEthAddrs [ 0 ]) ,
499638 & warp .Module .Address ,
500639 1_000_000 ,
501640 big .NewInt (225 * params .GWei ),
@@ -519,12 +658,28 @@ func TestReceiveWarpMessage(t *testing.T) {
519658 validProposerCtx := & block.Context {
520659 PChainHeight : minimumValidPChainHeight ,
521660 }
522- vm .clock .Set (vm . clock . Time (). Add ( 2 * time . Second ) )
661+ vm .clock .Set (blockTime )
523662 <- issuer
524663
525664 block2 , err := vm .BuildBlockWithContext (context .Background (), validProposerCtx )
526665 require .NoError (err )
527666
667+ // Require the block was built with a successful predicate result
668+ ethBlock := block2 .(* chain.BlockWrapper ).Block .(* Block ).ethBlock
669+ headerPredicateResultsBytes , ok := predicate .GetPredicateResultBytes (ethBlock .Extra ())
670+ require .True (ok )
671+ results , err := predicate .ParseResults (headerPredicateResultsBytes )
672+ require .NoError (err )
673+
674+ // Predicate results encode the index of invalid warp messages in a bitset.
675+ // An empty bitset indicates success.
676+ txResultsBytes := results .GetResults (
677+ getVerifiedWarpMessageTx .Hash (),
678+ warp .ContractAddress ,
679+ )
680+ bitset := set .BitsFromBytes (txResultsBytes )
681+ require .Zero (bitset .Len ()) // Empty bitset indicates success
682+
528683 block2VerifyWithCtx , ok := block2 .(block.WithVerifyContext )
529684 require .True (ok )
530685 shouldVerifyWithCtx , err := block2VerifyWithCtx .ShouldVerifyWithContext (context .Background ())
@@ -548,15 +703,14 @@ func TestReceiveWarpMessage(t *testing.T) {
548703 require .NoError (block2 .Accept (context .Background ()))
549704 vm .blockChain .DrainAcceptorQueue ()
550705
551- ethBlock := block2 .(* chain.BlockWrapper ).Block .(* Block ).ethBlock
552706 verifiedMessageReceipts := vm .blockChain .GetReceiptsByHash (ethBlock .Hash ())
553707 require .Len (verifiedMessageReceipts , 1 )
554708 verifiedMessageTxReceipt := verifiedMessageReceipts [0 ]
555709 require .Equal (types .ReceiptStatusSuccessful , verifiedMessageTxReceipt .Status )
556710
557711 expectedOutput , err := warp .PackGetVerifiedWarpMessageOutput (warp.GetVerifiedWarpMessageOutput {
558712 Message : warp.WarpMessage {
559- SourceChainID : common .Hash (vm . ctx . ChainID ),
713+ SourceChainID : common .Hash (sourceChainID ),
560714 OriginSenderAddress : testEthAddrs [0 ],
561715 Payload : payloadData ,
562716 },
0 commit comments