Skip to content

Commit 9a4d7ff

Browse files
authored
Propose Job Spec Aptos (#21909)
* propose-aptos-job-spec * adding test * test * comments * apto * revert * fix * adding family validation * delta stage is required now
1 parent d21814d commit 9a4d7ff

4 files changed

Lines changed: 684 additions & 81 deletions

File tree

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
package jobs
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
"time"
8+
9+
chainselectors "github.com/smartcontractkit/chain-selectors"
10+
11+
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
12+
"github.com/smartcontractkit/chainlink/deployment/cre/jobs/pkg"
13+
)
14+
15+
var _ cldf.ChangeSetV2[ProposeAptosCapJobSpecInput] = ProposeAptosCapJobSpec{}
16+
17+
const aptosNetwork = "aptos"
18+
19+
type AptosOverrideDefaultCfg struct {
20+
CREForwarderAddress string `json:"creForwarderAddress,omitempty" yaml:"creForwarderAddress,omitempty"`
21+
Network string `json:"network,omitempty" yaml:"network,omitempty"`
22+
ChainID string `json:"chainId,omitempty" yaml:"chainId,omitempty"`
23+
ObservationPollerWorkersCount uint `json:"observationPollerWorkersCount,omitempty" yaml:"observationPollerWorkersCount,omitempty"`
24+
ObservationPollPeriod time.Duration `json:"observationPollPeriod,omitempty" yaml:"observationPollPeriod,omitempty"`
25+
ChainHeightPollPeriod time.Duration `json:"chainHeightPollPeriod,omitempty" yaml:"chainHeightPollPeriod,omitempty"`
26+
UnknownRequestsTTL time.Duration `json:"unknownRequestsTTL,omitempty" yaml:"unknownRequestsTTL,omitempty"`
27+
DeltaStage time.Duration `json:"deltaStage" yaml:"deltaStage,omitempty"`
28+
TxSearchStartingBuffer time.Duration `json:"txSearchStartingBuffer" yaml:"txSearchStartingBuffer,omitempty"`
29+
}
30+
31+
type AptosCapabilityInput struct {
32+
NodeID string `json:"nodeID" yaml:"nodeID"`
33+
OverrideDefaultCfg AptosOverrideDefaultCfg `json:"overrideDefaultCfg" yaml:"overrideDefaultCfg"`
34+
}
35+
36+
type ProposeAptosCapJobSpecInput struct {
37+
Environment string `json:"environment" yaml:"environment"`
38+
Zone string `json:"zone" yaml:"zone"`
39+
Domain string `json:"domain" yaml:"domain"`
40+
DONName string `json:"donName" yaml:"donName"`
41+
42+
ChainSelector uint64 `json:"chainSelector" yaml:"chainSelector"`
43+
BootstrapperOCR3Urls []string `json:"bootstrapperOCR3Urls" yaml:"bootstrapperOCR3Urls"`
44+
OCRContractQualifier string `json:"ocrContractQualifier" yaml:"ocrContractQualifier"`
45+
OCRChainSelector uint64 `json:"ocrChainSelector" yaml:"ocrChainSelector"`
46+
ForwardersQualifier string `json:"forwardersContractQualifier" yaml:"forwardersContractQualifier"`
47+
48+
DeltaStage time.Duration `json:"deltaStage" yaml:"deltaStage,omitempty"`
49+
TxSearchStartingBuffer time.Duration `json:"txSearchStartingBuffer" yaml:"txSearchStartingBuffer,omitempty"`
50+
AptosCapabilityInputs []AptosCapabilityInput `json:"aptosCapabilityInputs" yaml:"aptosCapabilityInputs"`
51+
}
52+
53+
type ProposeAptosCapJobSpec struct{}
54+
55+
func (u ProposeAptosCapJobSpec) VerifyPreconditions(e cldf.Environment, input ProposeAptosCapJobSpecInput) error {
56+
if len(input.AptosCapabilityInputs) == 0 {
57+
return errors.New("at least one aptos capability input is required")
58+
}
59+
for i, aptosCapInput := range input.AptosCapabilityInputs {
60+
if aptosCapInput.NodeID == "" {
61+
return fmt.Errorf("nodeID is required for aptos capability input at index %d", i)
62+
}
63+
}
64+
65+
if err := validateCommonFields(commonCapFields{
66+
Environment: input.Environment,
67+
Domain: input.Domain,
68+
Zone: input.Zone,
69+
DONName: input.DONName,
70+
ChainSelector: input.ChainSelector,
71+
OCRChainSelector: input.OCRChainSelector,
72+
BootstrapperOCR3Urls: input.BootstrapperOCR3Urls,
73+
OCRContractQualifier: input.OCRContractQualifier,
74+
ForwardersQualifier: input.ForwardersQualifier,
75+
DeltaStage: input.DeltaStage,
76+
}); err != nil {
77+
return err
78+
}
79+
80+
family, err := chainselectors.GetSelectorFamily(input.ChainSelector)
81+
if err != nil {
82+
return fmt.Errorf("failed to get family for chain selector %d: %w", input.ChainSelector, err)
83+
}
84+
if family != chainselectors.FamilyAptos {
85+
return fmt.Errorf("chain selector %d belongs to family %q, expected %q", input.ChainSelector, family, chainselectors.FamilyAptos)
86+
}
87+
88+
chainIDStr, err := chainselectors.GetChainIDFromSelector(input.ChainSelector)
89+
if err != nil {
90+
return fmt.Errorf("failed to get chainID from selector: %w", err)
91+
}
92+
93+
resolved, err := resolveContractAddresses(e, input.OCRChainSelector, input.OCRContractQualifier, input.ChainSelector, input.ForwardersQualifier)
94+
if err != nil {
95+
return err
96+
}
97+
98+
for _, aptosCapInput := range input.AptosCapabilityInputs {
99+
ov := aptosCapInput.OverrideDefaultCfg
100+
101+
if ov.ChainID != "" && ov.ChainID != chainIDStr {
102+
return fmt.Errorf(
103+
"chainID in override config (%s) does not match chainID from chain selector (%s) for node %s; "+
104+
"this field is auto-populated and can be omitted",
105+
ov.ChainID, chainIDStr, aptosCapInput.NodeID,
106+
)
107+
}
108+
109+
if err := validateOverrideNetwork(ov.Network, aptosNetwork, aptosCapInput.NodeID); err != nil {
110+
return err
111+
}
112+
if err := validateOverrideForwarder(ov.CREForwarderAddress, resolved.ForwarderAddress, aptosCapInput.NodeID); err != nil {
113+
return err
114+
}
115+
}
116+
117+
return nil
118+
}
119+
120+
func (u ProposeAptosCapJobSpec) Apply(e cldf.Environment, input ProposeAptosCapJobSpecInput) (cldf.ChangesetOutput, error) {
121+
chainName, err := chainselectors.GetChainNameFromSelector(input.ChainSelector)
122+
if err != nil {
123+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to get chain name from selector: %w", err)
124+
}
125+
126+
chainIDStr, err := chainselectors.GetChainIDFromSelector(input.ChainSelector)
127+
if err != nil {
128+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to get chain ID from selector: %w", err)
129+
}
130+
131+
jobName := fmt.Sprintf("aptos-cap-v2-%s-%s", chainName, input.Zone)
132+
job := pkg.StandardCapabilityJob{
133+
JobName: jobName,
134+
Command: "/usr/local/bin/aptos",
135+
GenerateOracleFactory: true,
136+
ContractQualifier: input.OCRContractQualifier,
137+
OCRSigningStrategy: "single-chain",
138+
OCRChainSelector: pkg.ChainSelector(input.OCRChainSelector),
139+
ChainSelectorEVM: pkg.ChainSelector(input.OCRChainSelector),
140+
ChainSelectorAptos: pkg.ChainSelector(input.ChainSelector),
141+
BootstrapPeers: input.BootstrapperOCR3Urls,
142+
}
143+
144+
resolved, err := resolveContractAddresses(e, input.OCRChainSelector, input.OCRContractQualifier, input.ChainSelector, input.ForwardersQualifier)
145+
if err != nil {
146+
return cldf.ChangesetOutput{}, err
147+
}
148+
149+
nodeIDToConfig := make(map[string]string, len(input.AptosCapabilityInputs))
150+
for _, aptosCapInput := range input.AptosCapabilityInputs {
151+
if _, exists := nodeIDToConfig[aptosCapInput.NodeID]; exists {
152+
return cldf.ChangesetOutput{}, fmt.Errorf("duplicate nodeID %q in aptosCapabilityInputs", aptosCapInput.NodeID)
153+
}
154+
155+
cfg := aptosCapInput.OverrideDefaultCfg
156+
cfg.ChainID = chainIDStr
157+
cfg.Network = aptosNetwork
158+
cfg.CREForwarderAddress = resolved.ForwarderAddress
159+
cfg.DeltaStage = input.DeltaStage
160+
cfg.TxSearchStartingBuffer = input.TxSearchStartingBuffer
161+
enc, err := json.Marshal(cfg)
162+
if err != nil {
163+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to marshal aptos cap config: %w", err)
164+
}
165+
166+
nodeIDToConfig[aptosCapInput.NodeID] = string(enc)
167+
}
168+
169+
return proposeAndReport(e, job, nodeIDToConfig, input.Domain, input.DONName, input.Zone)
170+
}

0 commit comments

Comments
 (0)