Skip to content

Commit

Permalink
make proper changeset; refactor to isolate code (#15070)
Browse files Browse the repository at this point in the history
  • Loading branch information
krehermann authored Nov 1, 2024
1 parent cc5ba93 commit 007cf1f
Show file tree
Hide file tree
Showing 11 changed files with 390 additions and 160 deletions.
6 changes: 6 additions & 0 deletions deployment/keystone/capability_management.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,9 @@ func AddCapabilities(lggr logger.Logger, registry *kcr.CapabilitiesRegistry, cha
}
return nil
}

// CapabilityID returns a unique id for the capability
// TODO: mv to chainlink-common? ref https://github.com/smartcontractkit/chainlink/blob/4fb06b4525f03c169c121a68defa9b13677f5f20/contracts/src/v0.8/keystone/CapabilitiesRegistry.sol#L170
func CapabilityID(c kcr.CapabilitiesRegistryCapability) string {
return fmt.Sprintf("%s@%s", c.LabelledName, c.Version)
}
82 changes: 51 additions & 31 deletions deployment/keystone/changeset/append_node_capbilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,23 @@ package changeset
import (
"fmt"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
chainsel "github.com/smartcontractkit/chain-selectors"
kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey"

"github.com/smartcontractkit/chainlink/deployment"
kslib "github.com/smartcontractkit/chainlink/deployment/keystone"
"github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal"
)

var _ deployment.ChangeSet = AppendNodeCapabilities

type AppendNodeCapabilitiesRequest struct {
Chain deployment.Chain
Registry *kcr.CapabilitiesRegistry
AddressBook deployment.AddressBook
RegistryChainSel uint64

P2pToCapabilities map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability
NopToNodes map[kcr.CapabilitiesRegistryNodeOperator][]*kslib.P2PSignerEnc
NopToNodes map[kcr.CapabilitiesRegistryNodeOperator][]*P2PSignerEnc
}

func (req *AppendNodeCapabilitiesRequest) Validate() error {
Expand All @@ -26,12 +29,18 @@ func (req *AppendNodeCapabilitiesRequest) Validate() error {
if len(req.NopToNodes) == 0 {
return fmt.Errorf("nopToNodes is empty")
}
if req.Registry == nil {
if req.AddressBook == nil {
return fmt.Errorf("registry is nil")
}
_, exists := chainsel.ChainBySelector(req.RegistryChainSel)
if !exists {
return fmt.Errorf("registry chain selector %d does not exist", req.RegistryChainSel)
}

return nil
}

/*
// AppendNodeCapabilibity adds any new capabilities to the registry, merges the new capabilities with the existing capabilities
// of the node, and updates the nodes in the registry host the union of the new and existing capabilities.
func AppendNodeCapabilities(lggr logger.Logger, req *AppendNodeCapabilitiesRequest) (deployment.ChangesetOutput, error) {
Expand All @@ -41,40 +50,51 @@ func AppendNodeCapabilities(lggr logger.Logger, req *AppendNodeCapabilitiesReque
}
return deployment.ChangesetOutput{}, nil
}
*/

func appendNodeCapabilitiesImpl(lggr logger.Logger, req *AppendNodeCapabilitiesRequest) (*kslib.UpdateNodesResponse, error) {
if err := req.Validate(); err != nil {
return nil, fmt.Errorf("failed to validate request: %w", err)
// AppendNodeCapabilibity adds any new capabilities to the registry, merges the new capabilities with the existing capabilities
// of the node, and updates the nodes in the registry host the union of the new and existing capabilities.
func AppendNodeCapabilities(env deployment.Environment, config any) (deployment.ChangesetOutput, error) {
req, ok := config.(*AppendNodeCapabilitiesRequest)
if !ok {
return deployment.ChangesetOutput{}, fmt.Errorf("invalid config type")
}
// collect all the capabilities and add them to the registry
var capabilities []kcr.CapabilitiesRegistryCapability
for _, cap := range req.P2pToCapabilities {
capabilities = append(capabilities, cap...)

cfg, err := req.convert(env)
if err != nil {
return deployment.ChangesetOutput{}, err
}
err := kslib.AddCapabilities(lggr, req.Registry, req.Chain, capabilities)
_, err = internal.AppendNodeCapabilitiesImpl(env.Logger, cfg)
if err != nil {
return nil, fmt.Errorf("failed to add capabilities: %w", err)
return deployment.ChangesetOutput{}, err
}
return deployment.ChangesetOutput{}, nil
}

// for each node, merge the new capabilities with the existing ones and update the node
capsByPeer := make(map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability)
for p2pID, caps := range req.P2pToCapabilities {
caps, err := kslib.AppendCapabilities(lggr, req.Registry, req.Chain, []p2pkey.PeerID{p2pID}, caps)
if err != nil {
return nil, fmt.Errorf("failed to append capabilities for p2p %s: %w", p2pID, err)
}
capsByPeer[p2pID] = caps[p2pID]
func (req *AppendNodeCapabilitiesRequest) convert(e deployment.Environment) (*internal.AppendNodeCapabilitiesRequest, error) {
if err := req.Validate(); err != nil {
return nil, fmt.Errorf("failed to validate UpdateNodeCapabilitiesRequest: %w", err)
}

updateNodesReq := &kslib.UpdateNodesRequest{
Chain: req.Chain,
Registry: req.Registry,
P2pToCapabilities: capsByPeer,
NopToNodes: req.NopToNodes,
registryChain, ok := e.Chains[req.RegistryChainSel]
if !ok {
return nil, fmt.Errorf("registry chain selector %d does not exist in environment", req.RegistryChainSel)
}
resp, err := kslib.UpdateNodes(lggr, updateNodesReq)
contracts, err := kslib.GetContractSets(&kslib.GetContractSetsRequest{
Chains: map[uint64]deployment.Chain{req.RegistryChainSel: registryChain},
AddressBook: req.AddressBook,
})
if err != nil {
return nil, fmt.Errorf("failed to update nodes: %w", err)
return nil, fmt.Errorf("failed to get contract sets: %w", err)
}
registry := contracts.ContractSets[req.RegistryChainSel].CapabilitiesRegistry
if registry == nil {
return nil, fmt.Errorf("capabilities registry not found for chain %d", req.RegistryChainSel)
}
return resp, nil

return &internal.AppendNodeCapabilitiesRequest{
Chain: registryChain,
Registry: registry,
P2pToCapabilities: req.P2pToCapabilities,
NopToNodes: req.NopToNodes,
}, nil
}
7 changes: 0 additions & 7 deletions deployment/keystone/changeset/helpers_test.go

This file was deleted.

69 changes: 69 additions & 0 deletions deployment/keystone/changeset/internal/append_node_capabilities.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package internal

import (
"fmt"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink/deployment"
kslib "github.com/smartcontractkit/chainlink/deployment/keystone"
kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey"
)

type AppendNodeCapabilitiesRequest struct {
Chain deployment.Chain
Registry *kcr.CapabilitiesRegistry

P2pToCapabilities map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability
NopToNodes map[kcr.CapabilitiesRegistryNodeOperator][]*P2PSignerEnc
}

func (req *AppendNodeCapabilitiesRequest) Validate() error {
if len(req.P2pToCapabilities) == 0 {
return fmt.Errorf("p2pToCapabilities is empty")
}
if len(req.NopToNodes) == 0 {
return fmt.Errorf("nopToNodes is empty")
}
if req.Registry == nil {
return fmt.Errorf("registry is nil")
}
return nil
}

func AppendNodeCapabilitiesImpl(lggr logger.Logger, req *AppendNodeCapabilitiesRequest) (*UpdateNodesResponse, error) {
if err := req.Validate(); err != nil {
return nil, fmt.Errorf("failed to validate request: %w", err)
}
// collect all the capabilities and add them to the registry
var capabilities []kcr.CapabilitiesRegistryCapability
for _, cap := range req.P2pToCapabilities {
capabilities = append(capabilities, cap...)
}
err := kslib.AddCapabilities(lggr, req.Registry, req.Chain, capabilities)
if err != nil {
return nil, fmt.Errorf("failed to add capabilities: %w", err)
}

// for each node, merge the new capabilities with the existing ones and update the node
capsByPeer := make(map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability)
for p2pID, caps := range req.P2pToCapabilities {
caps, err := AppendCapabilities(lggr, req.Registry, req.Chain, []p2pkey.PeerID{p2pID}, caps)
if err != nil {
return nil, fmt.Errorf("failed to append capabilities for p2p %s: %w", p2pID, err)
}
capsByPeer[p2pID] = caps[p2pID]
}

updateNodesReq := &UpdateNodesRequest{
Chain: req.Chain,
Registry: req.Registry,
P2pToCapabilities: capsByPeer,
NopToNodes: req.NopToNodes,
}
resp, err := UpdateNodes(lggr, updateNodesReq)
if err != nil {
return nil, fmt.Errorf("failed to update nodes: %w", err)
}
return resp, nil
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package changeset_test
package internal_test

import (
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink/deployment"
kslib "github.com/smartcontractkit/chainlink/deployment/keystone"
"github.com/smartcontractkit/chainlink/deployment/keystone/changeset"
kstest "github.com/smartcontractkit/chainlink/deployment/keystone/test"
"github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal"

kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal/test"
kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey"
)
Expand All @@ -27,9 +26,9 @@ func TestAppendNodeCapabilities(t *testing.T) {
},
},
}
nopToNodes = map[kcr.CapabilitiesRegistryNodeOperator][]*kslib.P2PSignerEnc{
testNop(t, "testNop"): []*kslib.P2PSignerEnc{
&kslib.P2PSignerEnc{
nopToNodes = map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc{
testNop(t, "testNop"): []*internal.P2PSignerEnc{
&internal.P2PSignerEnc{
Signer: [32]byte{0: 1},
P2PKey: testPeerID(t, "0x1"),
EncryptionPublicKey: [32]byte{7: 7, 13: 13},
Expand All @@ -42,7 +41,7 @@ func TestAppendNodeCapabilities(t *testing.T) {

type args struct {
lggr logger.Logger
req *changeset.AppendNodeCapabilitiesRequest
req *internal.AppendNodeCapabilitiesRequest
initialState *kstest.SetupTestRegistryRequest
}
tests := []struct {
Expand All @@ -55,7 +54,7 @@ func TestAppendNodeCapabilities(t *testing.T) {
name: "invalid request",
args: args{
lggr: lggr,
req: &changeset.AppendNodeCapabilitiesRequest{
req: &internal.AppendNodeCapabilitiesRequest{
Chain: deployment.Chain{},
},
initialState: &kstest.SetupTestRegistryRequest{},
Expand All @@ -70,7 +69,7 @@ func TestAppendNodeCapabilities(t *testing.T) {
P2pToCapabilities: initialp2pToCapabilities,
NopToNodes: nopToNodes,
},
req: &changeset.AppendNodeCapabilitiesRequest{
req: &internal.AppendNodeCapabilitiesRequest{
P2pToCapabilities: map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability{
testPeerID(t, "0x1"): []kcr.CapabilitiesRegistryCapability{
{
Expand Down Expand Up @@ -100,9 +99,9 @@ func TestAppendNodeCapabilities(t *testing.T) {
tt.args.req.Registry = setupResp.Registry
tt.args.req.Chain = setupResp.Chain

got, err := changeset.AppendNodeCapabilitiesImpl(tt.args.lggr, tt.args.req)
got, err := internal.AppendNodeCapabilitiesImpl(tt.args.lggr, tt.args.req)
if (err != nil) != tt.wantErr {
t.Errorf("AppendNodeCapabilities() error = %v, wantErr %v", err, tt.wantErr)
t.Errorf("internal.AppendNodeCapabilities() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr {
Expand All @@ -119,17 +118,3 @@ func TestAppendNodeCapabilities(t *testing.T) {
})
}
}

func testPeerID(t *testing.T, s string) p2pkey.PeerID {
var out [32]byte
b := []byte(s)
copy(out[:], b)
return p2pkey.PeerID(out)
}

func testNop(t *testing.T, name string) kcr.CapabilitiesRegistryNodeOperator {
return kcr.CapabilitiesRegistryNodeOperator{
Admin: common.HexToAddress("0xFFFFFFFF45297A703e4508186d4C1aa1BAf80000"),
Name: name,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,21 @@ import (
"github.com/smartcontractkit/chainlink/deployment/environment/memory"

kslib "github.com/smartcontractkit/chainlink/deployment/keystone"
internal "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal"
kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey"
)

type SetupTestRegistryRequest struct {
P2pToCapabilities map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability
NopToNodes map[kcr.CapabilitiesRegistryNodeOperator][]*kslib.P2PSignerEnc
DonToNodes map[string][]*kslib.P2PSignerEnc
NopToNodes map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc
DonToNodes map[string][]*internal.P2PSignerEnc
}

type SetupTestRegistryResponse struct {
Registry *kcr.CapabilitiesRegistry
Chain deployment.Chain
Registry *kcr.CapabilitiesRegistry
Chain deployment.Chain
RegistrySelector uint64
}

func SetupTestRegistry(t *testing.T, lggr logger.Logger, req *SetupTestRegistryRequest) *SetupTestRegistryResponse {
Expand Down Expand Up @@ -63,7 +65,7 @@ func SetupTestRegistry(t *testing.T, lggr logger.Logger, req *SetupTestRegistryR
for p2pID := range req.P2pToCapabilities {
initialp2pToCapabilities[p2pID] = vanillaCapabilities(registeredCapabilities)
}
phonyRequest := &kslib.UpdateNodesRequest{
phonyRequest := &internal.UpdateNodesRequest{
Chain: chain,
Registry: registry,
P2pToCapabilities: req.P2pToCapabilities,
Expand All @@ -73,8 +75,9 @@ func SetupTestRegistry(t *testing.T, lggr logger.Logger, req *SetupTestRegistryR
require.NoError(t, err)
addNodes(t, lggr, chain, registry, nodeParams)
return &SetupTestRegistryResponse{
Registry: registry,
Chain: chain,
Registry: registry,
Chain: chain,
RegistrySelector: chain.Selector,
}
}

Expand Down
Loading

0 comments on commit 007cf1f

Please sign in to comment.