@@ -29,7 +29,16 @@ import (
29
29
p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types"
30
30
)
31
31
32
- var _ deployment.ChangeSet [DeployHomeChainConfig ] = DeployHomeChainChangeset
32
+ var (
33
+ _ deployment.ChangeSet [DeployHomeChainConfig ] = DeployHomeChainChangeset
34
+ // RemoveNodesFromCapRegChangeset is a changeset that removes nodes from the CapabilitiesRegistry contract.
35
+ // It fails validation
36
+ // - if the changeset is executed neither by CapabilitiesRegistry contract owner nor by the node operator admin.
37
+ // - if node is not already present in the CapabilitiesRegistry contract.
38
+ // - if node is part of CapabilitiesDON
39
+ // - if node is part of WorkflowDON
40
+ RemoveNodesFromCapRegChangeset = deployment .CreateChangeSet (removeNodesLogic , removeNodesPrecondition )
41
+ )
33
42
34
43
// DeployHomeChainChangeset is a separate changeset because it is a standalone deployment performed once in home chain for the entire CCIP deployment.
35
44
func DeployHomeChainChangeset (env deployment.Environment , cfg DeployHomeChainConfig ) (deployment.ChangesetOutput , error ) {
@@ -433,6 +442,7 @@ func addNodes(
433
442
lggr .Infow ("No new nodes to add" )
434
443
return nil
435
444
}
445
+ lggr .Infow ("Adding nodes" , "chain" , chain .String (), "nodes" , p2pIDsByNodeOpId )
436
446
tx , err := capReg .AddNodes (chain .DeployerKey , nodeParams )
437
447
if err != nil {
438
448
lggr .Errorw ("Failed to add nodes" , "chain" , chain .String (),
@@ -494,7 +504,7 @@ func RemoveDONs(e deployment.Environment, cfg RemoveDONsConfig) (deployment.Chan
494
504
return deployment.ChangesetOutput {}, err
495
505
}
496
506
if cfg .MCMS == nil {
497
- _ , err = homeChain . Confirm ( tx )
507
+ _ , err = deployment . ConfirmIfNoErrorWithABI ( homeChain , tx , capabilities_registry . CapabilitiesRegistryABI , err )
498
508
if err != nil {
499
509
return deployment.ChangesetOutput {}, err
500
510
}
@@ -529,3 +539,130 @@ func RemoveDONs(e deployment.Environment, cfg RemoveDONsConfig) (deployment.Chan
529
539
e .Logger .Infof ("Created proposal to remove dons" )
530
540
return deployment.ChangesetOutput {MCMSTimelockProposals : []mcmslib.TimelockProposal {* proposal }}, nil
531
541
}
542
+
543
+ type RemoveNodesConfig struct {
544
+ HomeChainSel uint64
545
+ P2PIDsToRemove [][32 ]byte
546
+ MCMSCfg * changeset.MCMSConfig
547
+ }
548
+
549
+ func removeNodesPrecondition (env deployment.Environment , c RemoveNodesConfig ) error {
550
+ state , err := changeset .LoadOnchainState (env )
551
+ if err != nil {
552
+ return err
553
+ }
554
+ if err := changeset .ValidateChain (env , state , c .HomeChainSel , c .MCMSCfg ); err != nil {
555
+ return err
556
+ }
557
+ if len (c .P2PIDsToRemove ) == 0 {
558
+ return errors .New ("p2p ids to remove must be set" )
559
+ }
560
+ for _ , p2pID := range c .P2PIDsToRemove {
561
+ if bytes .Equal (p2pID [:], make ([]byte , 32 )) {
562
+ return errors .New ("empty p2p id" )
563
+ }
564
+ }
565
+
566
+ // Cap reg must exist
567
+ if state .Chains [c .HomeChainSel ].CapabilityRegistry == nil {
568
+ return fmt .Errorf ("cap reg does not exist for home chain %d" , c .HomeChainSel )
569
+ }
570
+ capReg := state .Chains [c .HomeChainSel ].CapabilityRegistry
571
+ nodeInfos , err := capReg .GetNodes (& bind.CallOpts {
572
+ Context : env .GetContext (),
573
+ })
574
+ if err != nil {
575
+ return fmt .Errorf ("failed to get nodes from Capreg %s: %w" , capReg .Address ().String (), err )
576
+ }
577
+ capRegOwner , err := capReg .Owner (& bind.CallOpts {
578
+ Context : env .GetContext (),
579
+ })
580
+ if err != nil {
581
+ return fmt .Errorf ("failed to get owner of Capreg %s: %w" , capReg .Address ().String (), err )
582
+ }
583
+ txSender := env .Chains [c .HomeChainSel ].DeployerKey .From
584
+ if c .MCMSCfg != nil {
585
+ txSender = state .Chains [c .HomeChainSel ].Timelock .Address ()
586
+ }
587
+ existingP2PIDs := make (map [[32 ]byte ]capabilities_registry.INodeInfoProviderNodeInfo )
588
+ for _ , nodeInfo := range nodeInfos {
589
+ existingP2PIDs [nodeInfo .P2pId ] = nodeInfo
590
+ }
591
+ for _ , p2pID := range c .P2PIDsToRemove {
592
+ info , exists := existingP2PIDs [p2pID ]
593
+ if ! exists {
594
+ return fmt .Errorf ("p2p id %x does not exist in Capreg %s" , p2pID [:], capReg .Address ().String ())
595
+ }
596
+ nop , err := capReg .GetNodeOperator (nil , info .NodeOperatorId )
597
+ if err != nil {
598
+ return fmt .Errorf ("failed to get node operator %d for node %x: %w" , info .NodeOperatorId , p2pID [:], err )
599
+ }
600
+ if txSender != capRegOwner && txSender != nop .Admin {
601
+ return fmt .Errorf ("tx sender %s is not the owner %s of Capreg %s or admin %s for node %x" ,
602
+ txSender .String (), capRegOwner .String (), capReg .Address ().String (), nop .Admin .String (), p2pID [:])
603
+ }
604
+ if len (info .CapabilitiesDONIds ) > 0 {
605
+ return fmt .Errorf ("p2p id %x is part of CapabilitiesDON, cannot remove" , p2pID [:])
606
+ }
607
+ if info .WorkflowDONId != 0 {
608
+ return fmt .Errorf ("p2p id %x is part of WorkflowDON, cannot remove" , p2pID [:])
609
+ }
610
+ }
611
+
612
+ return nil
613
+ }
614
+
615
+ func removeNodesLogic (env deployment.Environment , c RemoveNodesConfig ) (deployment.ChangesetOutput , error ) {
616
+ state , err := changeset .LoadOnchainState (env )
617
+ if err != nil {
618
+ return deployment.ChangesetOutput {}, err
619
+ }
620
+ homeChainState := state .Chains [c .HomeChainSel ]
621
+ homeChain := env .Chains [c .HomeChainSel ]
622
+ txOpts := homeChain .DeployerKey
623
+ if c .MCMSCfg != nil {
624
+ txOpts = deployment .SimTransactOpts ()
625
+ }
626
+ tx , err := homeChainState .CapabilityRegistry .RemoveNodes (txOpts , c .P2PIDsToRemove )
627
+ if c .MCMSCfg == nil {
628
+ _ , err = deployment .ConfirmIfNoErrorWithABI (homeChain , tx , capabilities_registry .CapabilitiesRegistryABI , err )
629
+ if err != nil {
630
+ return deployment.ChangesetOutput {}, fmt .Errorf ("failed to remove nodes from capreg %s: %w" ,
631
+ homeChainState .CapabilityRegistry .Address ().String (), err )
632
+ }
633
+ env .Logger .Infof ("Removed nodes using deployer key tx %s" , tx .Hash ().String ())
634
+ return deployment.ChangesetOutput {}, nil
635
+ }
636
+ if err != nil {
637
+ return deployment.ChangesetOutput {}, err
638
+ }
639
+ batchOperation , err := proposalutils .BatchOperationForChain (c .HomeChainSel ,
640
+ homeChainState .CapabilityRegistry .Address ().Hex (), tx .Data (), big .NewInt (0 ),
641
+ string (changeset .CapabilitiesRegistry ), []string {})
642
+ if err != nil {
643
+ return deployment.ChangesetOutput {}, fmt .Errorf ("failed to create batch operation for home chain: %w" , err )
644
+ }
645
+
646
+ timelocks := changeset .BuildTimelockAddressPerChain (env , state )
647
+ proposerMcms := changeset .BuildProposerMcmAddressesPerChain (env , state )
648
+ inspectors := make (map [uint64 ]mcmssdk.Inspector )
649
+ inspectors [c .HomeChainSel ], err = proposalutils .McmsInspectorForChain (env , c .HomeChainSel )
650
+ if err != nil {
651
+ return deployment.ChangesetOutput {}, fmt .Errorf ("failed to get mcms inspector for chain %s: %w" , homeChain .String (), err )
652
+ }
653
+ proposal , err := proposalutils .BuildProposalFromBatchesV2 (
654
+ env ,
655
+ timelocks ,
656
+ proposerMcms ,
657
+ inspectors ,
658
+ []mcmstypes.BatchOperation {batchOperation },
659
+ "Remove Nodes from CapabilitiesRegistry" ,
660
+ c .MCMSCfg .MinDelay ,
661
+ )
662
+ if err != nil {
663
+ return deployment.ChangesetOutput {}, err
664
+ }
665
+
666
+ env .Logger .Infof ("Created proposal to remove nodes" )
667
+ return deployment.ChangesetOutput {MCMSTimelockProposals : []mcmslib.TimelockProposal {* proposal }}, nil
668
+ }
0 commit comments