Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CAPPL-434] feat(deployment/keystone): addNodes generate MCMS proposal #16098

Merged
merged 7 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ abigen: ## Build & install abigen.
.PHONY: generate
generate: abigen codecgen mockery protoc gomods ## Execute all go:generate commands.
## Updating PATH makes sure that go:generate uses the version of protoc installed by the protoc make command.
export PATH=$(HOME)/.local/bin:$(PATH); gomods -w go generate -x ./...
export PATH="$(HOME)/.local/bin:$(PATH)"; gomods -w go generate -x ./...
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prevents failure due to Visual Studio Code.app in PATH.

find . -type f -name .mockery.yaml -execdir mockery \; ## Execute mockery for all .mockery.yaml files

.PHONY: rm-mocked
Expand Down
99 changes: 75 additions & 24 deletions deployment/keystone/changeset/internal/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -668,16 +668,21 @@ func RegisterNodes(lggr logger.Logger, req *RegisterNodesRequest) (*RegisterNode
}

nodeIDToParams := make(map[string]capabilities_registry.CapabilitiesRegistryNodeParams)
nodeIDToDon := make(map[string]string)
for don, nodes := range req.DonToNodes {
caps, ok := req.DonToCapabilities[don]
if !ok {
return nil, fmt.Errorf("capabilities not found for don %s", don)
}
var hashedCapabilityIds [][32]byte
var (
hashedCapabilityIDs [][32]byte
capIDs []string
)
for _, cap := range caps {
hashedCapabilityIds = append(hashedCapabilityIds, cap.ID)
hashedCapabilityIDs = append(hashedCapabilityIDs, cap.ID)
capIDs = append(capIDs, hex.EncodeToString(cap.ID[:]))
}
lggr.Debugw("hashed capability ids", "don", don, "ids", hashedCapabilityIds)
lggr.Debugw("hashed capability ids", "don", don, "ids", capIDs)

for _, n := range nodes {
if n.IsBootstrap { // bootstraps are part of the DON but don't host capabilities
Expand All @@ -703,37 +708,50 @@ func RegisterNodes(lggr logger.Logger, req *RegisterNodesRequest) (*RegisterNode
Signer: signer,
P2pId: n.PeerID,
EncryptionPublicKey: csakey,
HashedCapabilityIds: hashedCapabilityIds,
HashedCapabilityIds: hashedCapabilityIDs,
}
} else {
// when we have a node operator, we need to dedup capabilities against the existing ones
var newCapIds [][32]byte
for _, proposedCapId := range hashedCapabilityIds {
var newCapIDs [][32]byte
for _, proposedCapID := range hashedCapabilityIDs {
shouldAdd := true
for _, existingCapId := range params.HashedCapabilityIds {
if existingCapId == proposedCapId {
for _, existingCapID := range params.HashedCapabilityIds {
if existingCapID == proposedCapID {
shouldAdd = false
break
}
}
if shouldAdd {
newCapIds = append(newCapIds, proposedCapId)
newCapIDs = append(newCapIDs, proposedCapID)
}
}
params.HashedCapabilityIds = append(params.HashedCapabilityIds, newCapIds...)
params.HashedCapabilityIds = append(params.HashedCapabilityIds, newCapIDs...)
}
nodeIDToParams[n.NodeID] = params
nodeIDToDon[n.NodeID] = don
}
}

var uniqueNodeParams []capabilities_registry.CapabilitiesRegistryNodeParams
for _, v := range nodeIDToParams {
uniqueNodeParams = append(uniqueNodeParams, v)
lggr.Debugw("checking for existing nodes", "count", len(nodeIDToParams))

nodes2Add, err := getNodesToRegister(registry, nodeIDToParams)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only register nodes not on the contract

if err != nil {
return nil, fmt.Errorf("failed to get nodes to register: %w", err)
}

lggr.Debugf("found %d missing nodes", len(nodes2Add))

if len(nodes2Add) == 0 {
lggr.Debug("no new nodes to register")
return &RegisterNodesResponse{
nodeIDToParams: nodeIDToParams,
}, nil
}
lggr.Debugw("unique node params to add", "count", len(uniqueNodeParams), "params", uniqueNodeParams)

lggr.Debugw("unique node params to add after deduplication", "count", len(nodes2Add), "params", nodes2Add)

if req.UseMCMS {
ops, err := addNodesMCMSProposal(registry, uniqueNodeParams, registryChain)
ops, err := addNodesMCMSProposal(registry, nodes2Add, registryChain)
if err != nil {
return nil, fmt.Errorf("failed to generate proposal to add nodes: %w", err)
}
Expand All @@ -744,7 +762,7 @@ func RegisterNodes(lggr logger.Logger, req *RegisterNodesRequest) (*RegisterNode
}, nil
}

tx, err := registry.AddNodes(registryChain.DeployerKey, uniqueNodeParams)
tx, err := registry.AddNodes(registryChain.DeployerKey, nodes2Add)
if err != nil {
err = deployment.DecodeErr(capabilities_registry.CapabilitiesRegistryABI, err)
// no typed errors in the abi, so we have to do string matching
Expand All @@ -753,7 +771,7 @@ func RegisterNodes(lggr logger.Logger, req *RegisterNodesRequest) (*RegisterNode
return nil, fmt.Errorf("failed to call AddNodes for bulk add nodes: %w", err)
}
lggr.Warn("nodes already exist, falling back to 1-by-1")
for _, singleNodeParams := range uniqueNodeParams {
for _, singleNodeParams := range nodes2Add {
tx, err = registry.AddNodes(registryChain.DeployerKey, []capabilities_registry.CapabilitiesRegistryNodeParams{singleNodeParams})
if err != nil {
err = deployment.DecodeErr(capabilities_registry.CapabilitiesRegistryABI, err)
Expand Down Expand Up @@ -783,6 +801,34 @@ func RegisterNodes(lggr logger.Logger, req *RegisterNodesRequest) (*RegisterNode
}, nil
}

// getNodesToRegister returns the nodes that are not already registered in the registry
func getNodesToRegister(
registry *capabilities_registry.CapabilitiesRegistry,
nodeIDToParams map[string]capabilities_registry.CapabilitiesRegistryNodeParams,
) ([]capabilities_registry.CapabilitiesRegistryNodeParams, error) {
nodes2Add := make([]capabilities_registry.CapabilitiesRegistryNodeParams, 0)
for nodeID, nodeParams := range nodeIDToParams {
var (
ni capabilities_registry.INodeInfoProviderNodeInfo
err error
)
if ni, err = registry.GetNode(&bind.CallOpts{}, nodeParams.P2pId); err != nil {
if err = deployment.DecodeErr(capabilities_registry.CapabilitiesRegistryABI, err); strings.Contains(err.Error(), "NodeDoesNotExist") {
nodes2Add = append(nodes2Add, nodeParams)
continue
}
return nil, fmt.Errorf("failed to call GetNode for node %s: %w", nodeID, err)
}

// if no error, but node info is empty, then the node does not exist and should be added.
if hex.EncodeToString(ni.P2pId[:]) != hex.EncodeToString(nodeParams.P2pId[:]) && hex.EncodeToString(ni.P2pId[:]) == "0000000000000000000000000000000000000000000000000000000000000000" {
nodes2Add = append(nodes2Add, nodeParams)
continue
}
}
return nodes2Add, nil
}

// addNodesMCMSProposal generates a single call to AddNodes for all the node params at once.
func addNodesMCMSProposal(registry *capabilities_registry.CapabilitiesRegistry, params []capabilities_registry.CapabilitiesRegistryNodeParams, regChain deployment.Chain) (*timelock.BatchChainOperation, error) {
tx, err := registry.AddNodes(deployment.SimTransactOpts(), params)
Expand Down Expand Up @@ -857,7 +903,7 @@ func RegisterDons(lggr logger.Logger, req RegisterDonsRequest) (*RegisterDonsRes
}
lggr.Infow("fetched existing DONs...", "len", len(donInfos), "lenByNodesHash", len(existingDONs))

mcmsOps := make([]mcms.Operation, 0, len(req.DonsToRegister))
mcmsOps := make([]mcms.Operation, 0)
for _, don := range req.DonsToRegister {
var p2pIds [][32]byte
for _, n := range don.Nodes {
Expand Down Expand Up @@ -908,6 +954,8 @@ func RegisterDons(lggr logger.Logger, req RegisterDonsRequest) (*RegisterDonsRes
txOpts = deployment.SimTransactOpts()
}

lggr.Debugw("calling add don", "don", don.Name, "p2p sorted hash", p2pSortedHash, "cgs", cfgs, "wfSupported", wfSupported, "f", don.F,
"p2pids", p2pIds, "node count", len(p2pIds))
tx, err := registry.AddDON(txOpts, p2pIds, cfgs, true, wfSupported, don.F)
if err != nil {
err = deployment.DecodeErr(capabilities_registry.CapabilitiesRegistryABI, err)
Expand All @@ -934,12 +982,15 @@ func RegisterDons(lggr logger.Logger, req RegisterDonsRequest) (*RegisterDonsRes
}

if req.UseMCMS {
return &RegisterDonsResponse{
Ops: &timelock.BatchChainOperation{
ChainIdentifier: mcms.ChainIdentifier(registryChain.Selector),
Batch: mcmsOps,
},
}, nil
if len(mcmsOps) > 0 {
return &RegisterDonsResponse{
Ops: &timelock.BatchChainOperation{
ChainIdentifier: mcms.ChainIdentifier(registryChain.Selector),
Batch: mcmsOps,
},
}, nil
}
return &RegisterDonsResponse{}, nil
}

lggr.Debugf("Registered all DONs (new=%d), waiting for registry to update", addedDons)
Expand Down
Loading
Loading