Skip to content

Commit

Permalink
resurrect update don changeset (#15112)
Browse files Browse the repository at this point in the history
* resurrect update don changeset

* fix setup

* refactor test suite setup

* make update don work

* code cleanup
  • Loading branch information
krehermann authored Nov 6, 2024
1 parent 04a4075 commit c6ad7b2
Show file tree
Hide file tree
Showing 15 changed files with 842 additions and 196 deletions.
32 changes: 32 additions & 0 deletions deployment/environment/clo/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package clo

import (
jd "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node"
"github.com/smartcontractkit/chainlink/deployment/environment/clo/models"
)

// NewChainConfig creates a new JobDistributor ChainConfig from a clo model NodeChainConfig
func NewChainConfig(chain *models.NodeChainConfig) *jd.ChainConfig {
return &jd.ChainConfig{
Chain: &jd.Chain{
Id: chain.Network.ChainID,
Type: jd.ChainType_CHAIN_TYPE_EVM, // TODO: support other chain types
},

AccountAddress: chain.AccountAddress,
AdminAddress: chain.AdminAddress,
Ocr2Config: &jd.OCR2Config{
Enabled: chain.Ocr2Config.Enabled,
P2PKeyBundle: &jd.OCR2Config_P2PKeyBundle{
PeerId: chain.Ocr2Config.P2pKeyBundle.PeerID,
PublicKey: chain.Ocr2Config.P2pKeyBundle.PublicKey,
},
OcrKeyBundle: &jd.OCR2Config_OCRKeyBundle{
BundleId: chain.Ocr2Config.OcrKeyBundle.BundleID,
OnchainSigningAddress: chain.Ocr2Config.OcrKeyBundle.OnchainSigningAddress,
OffchainPublicKey: chain.Ocr2Config.OcrKeyBundle.OffchainPublicKey,
ConfigPublicKey: chain.Ocr2Config.OcrKeyBundle.ConfigPublicKey,
},
},
}
}
1 change: 0 additions & 1 deletion deployment/keystone/changeset/append_node_capbilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,5 @@ func (req *AppendNodeCapabilitiesRequest) convert(e deployment.Environment) (*in
Chain: registryChain,
Registry: registry,
P2pToCapabilities: req.P2pToCapabilities,
NopToNodes: req.NopToNodes,
}, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,12 @@ type AppendNodeCapabilitiesRequest struct {
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")
}
Expand Down Expand Up @@ -59,7 +55,6 @@ func AppendNodeCapabilitiesImpl(lggr logger.Logger, req *AppendNodeCapabilitiesR
Chain: req.Chain,
Registry: req.Registry,
P2pToCapabilities: capsByPeer,
NopToNodes: req.NopToNodes,
}
resp, err := UpdateNodes(lggr, updateNodesReq)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ func TestAppendNodeCapabilities(t *testing.T) {
},
},
},
NopToNodes: nopToNodes,
},
},
want: deployment.ChangesetOutput{},
Expand All @@ -93,7 +92,6 @@ func TestAppendNodeCapabilities(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// chagen the name and args to be mor egeneral
setupResp := kstest.SetupTestRegistry(t, lggr, tt.args.initialState)

tt.args.req.Registry = setupResp.Registry
Expand Down
116 changes: 101 additions & 15 deletions deployment/keystone/changeset/internal/test/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,30 @@ import (

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"

capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/values"
"github.com/smartcontractkit/chainlink/deployment"
"github.com/smartcontractkit/chainlink/deployment/environment/memory"

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

type Don struct {
Name string
P2PIDs []p2pkey.PeerID
CapabilityConfigs []internal.CapabilityConfig
}
type SetupTestRegistryRequest struct {
P2pToCapabilities map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability
NopToNodes map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc
DonToNodes map[string][]*internal.P2PSignerEnc
Dons []Don
}

type SetupTestRegistryResponse struct {
Expand Down Expand Up @@ -59,21 +68,32 @@ func SetupTestRegistry(t *testing.T, lggr logger.Logger, req *SetupTestRegistryR
}
require.Len(t, registeredCapabilities, len(expectedDeduped))

// add the nodes with the phony capabilities. cannot register a node without a capability and capability must exist
// to do this make an initial phony request and extract the node params
initialp2pToCapabilities := make(map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability)
// make the nodes and register node
var nodeParams []kcr.CapabilitiesRegistryNodeParams
initialp2pToCapabilities := make(map[p2pkey.PeerID][][32]byte)
for p2pID := range req.P2pToCapabilities {
initialp2pToCapabilities[p2pID] = vanillaCapabilities(registeredCapabilities)
initialp2pToCapabilities[p2pID] = mustCapabilityIds(t, registry, registeredCapabilities)
}
phonyRequest := &internal.UpdateNodesRequest{
Chain: chain,
Registry: registry,
P2pToCapabilities: req.P2pToCapabilities,
NopToNodes: req.NopToNodes,
// create node with initial capabilities assigned to nop
for i, nop := range nops {
if _, exists := req.NopToNodes[nop]; !exists {
require.Fail(t, "missing nopToNodes for %s", nop.Name)
}
for _, p2pSignerEnc := range req.NopToNodes[nop] {
nodeParams = append(nodeParams, kcr.CapabilitiesRegistryNodeParams{
Signer: p2pSignerEnc.Signer,
P2pId: p2pSignerEnc.P2PKey,
EncryptionPublicKey: p2pSignerEnc.EncryptionPublicKey,
HashedCapabilityIds: initialp2pToCapabilities[p2pSignerEnc.P2PKey],
NodeOperatorId: uint32(i + 1), // nopid in contract is 1-indexed
})
}
}
nodeParams, err := phonyRequest.NodeParams()
require.NoError(t, err)
addNodes(t, lggr, chain, registry, nodeParams)

// add the Dons
addDons(t, lggr, chain, registry, capCache, req.Dons)

return &SetupTestRegistryResponse{
Registry: registry,
Chain: chain,
Expand Down Expand Up @@ -108,6 +128,50 @@ func addNodes(t *testing.T, lggr logger.Logger, chain deployment.Chain, registry
require.NoError(t, err)
}

func addDons(t *testing.T, lggr logger.Logger, chain deployment.Chain, registry *kcr.CapabilitiesRegistry, capCache *CapabilityCache, dons []Don) {
for _, don := range dons {
acceptsWorkflows := false
// lookup the capabilities
var capConfigs []kcr.CapabilitiesRegistryCapabilityConfiguration
for _, ccfg := range don.CapabilityConfigs {
var cc = kcr.CapabilitiesRegistryCapabilityConfiguration{
CapabilityId: [32]byte{},
Config: ccfg.Config,
}
if cc.Config == nil {
cc.Config = defaultCapConfig(t, ccfg.Capability)
}
var exists bool
//var cc kcr.CapabilitiesRegistryCapabilityConfiguration{}
cc.CapabilityId, exists = capCache.Get(ccfg.Capability)
require.True(t, exists, "capability not found in cache %v", ccfg.Capability)
capConfigs = append(capConfigs, cc)
if ccfg.Capability.CapabilityType == 2 { // ocr3 capabilities
acceptsWorkflows = true
}
}
// add the don
isPublic := true
f := len(don.P2PIDs)/3 + 1
tx, err := registry.AddDON(chain.DeployerKey, internal.PeerIDsToBytes(don.P2PIDs), capConfigs, isPublic, acceptsWorkflows, uint8(f))
if err != nil {
err2 := kslib.DecodeErr(kcr.CapabilitiesRegistryABI, err)
require.Fail(t, fmt.Sprintf("failed to call AddDON: %s: %s", err, err2))
}
_, err = chain.Confirm(tx)
require.NoError(t, err)
}
}

func defaultCapConfig(t *testing.T, cap kcr.CapabilitiesRegistryCapability) []byte {
empty := &capabilitiespb.CapabilityConfig{
DefaultConfig: values.Proto(values.EmptyMap()).GetMapValue(),
}
emptyb, err := proto.Marshal(empty)
require.NoError(t, err)
return emptyb
}

// CapabilityCache tracks registered capabilities by name
type CapabilityCache struct {
t *testing.T
Expand All @@ -120,6 +184,10 @@ func NewCapabiltyCache(t *testing.T) *CapabilityCache {
nameToId: make(map[string][32]byte),
}
}
func (cc *CapabilityCache) Get(cap kcr.CapabilitiesRegistryCapability) ([32]byte, bool) {
id, exists := cc.nameToId[kslib.CapabilityID(cap)]
return id, exists
}

// AddCapabilities adds the capabilities to the registry and returns the registered capabilities
// if the capability is already registered, it will not be re-registered
Expand Down Expand Up @@ -182,10 +250,28 @@ func testChain(t *testing.T) deployment.Chain {
return chain
}

func vanillaCapabilities(rcs []kslib.RegisteredCapability) []kcr.CapabilitiesRegistryCapability {
out := make([]kcr.CapabilitiesRegistryCapability, len(rcs))
func capabilityIds(registry *capabilities_registry.CapabilitiesRegistry, rcs []kslib.RegisteredCapability) ([][32]byte, error) {
out := make([][32]byte, len(rcs))
for i := range rcs {
out[i] = rcs[i].CapabilitiesRegistryCapability
id, err := registry.GetHashedCapabilityId(&bind.CallOpts{}, rcs[i].LabelledName, rcs[i].Version)
if err != nil {
return nil, fmt.Errorf("failed to get capability id: %w", err)
}
out[i] = id
}
return out, nil
}

func mustCapabilityIds(t *testing.T, registry *capabilities_registry.CapabilitiesRegistry, rcs []kslib.RegisteredCapability) [][32]byte {
t.Helper()
out, err := capabilityIds(registry, rcs)
require.NoError(t, err)
return out
}

func MustCapabilityId(t *testing.T, registry *capabilities_registry.CapabilitiesRegistry, cap capabilities_registry.CapabilitiesRegistryCapability) [32]byte {
t.Helper()
id, err := registry.GetHashedCapabilityId(&bind.CallOpts{}, cap.LabelledName, cap.Version)
require.NoError(t, err)
return id
}
Loading

0 comments on commit c6ad7b2

Please sign in to comment.