From e3cb8970ec30fc871879aaf89a145b38e711f915 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Wed, 18 Mar 2026 05:45:50 +0000 Subject: [PATCH 01/34] system-tests: finish aptos local CRE write parity --- .github/workflows/cre-system-tests.yaml | 3 + core/capabilities/fakes/register.go | 20 + core/capabilities/fakes/register_test.go | 33 + core/capabilities/fakes/streams_trigger.go | 35 +- .../configs/capability_defaults.toml | 10 + .../configs/workflow-gateway-don-aptos.toml | 83 ++ .../cre/environment/mock/trigger_types.go | 5 +- core/services/chainlink/application.go | 16 + .../conversions/conversions.go | 18 + .../conversions/conversions_test.go | 32 + deployment/cre/jobs/propose_job_spec.go | 15 +- deployment/cre/jobs/propose_job_spec_test.go | 63 + go.md | 17 + plugins/plugins.private.yaml | 6 +- system-tests/lib/cre/contracts/keystone.go | 45 +- system-tests/lib/cre/contracts/ocr3.go | 2 + system-tests/lib/cre/don.go | 75 +- system-tests/lib/cre/don/config/config.go | 77 +- .../environment/blockchains/aptos/aptos.go | 352 ++++++ .../cre/environment/blockchains/sets/sets.go | 2 + system-tests/lib/cre/environment/dons.go | 9 +- .../lib/cre/environment/environment.go | 56 +- system-tests/lib/cre/features/aptos/aptos.go | 1113 +++++++++++++++++ .../lib/cre/features/aptos/aptos_test.go | 251 ++++ .../cre/features/consensus/v1/consensus.go | 2 +- .../cre/features/consensus/v2/consensus.go | 19 +- system-tests/lib/cre/features/cron/cron.go | 2 +- .../features/custom_compute/custom_compute.go | 2 +- .../lib/cre/features/don_time/don_time.go | 2 +- system-tests/lib/cre/features/evm/v1/evm.go | 2 +- system-tests/lib/cre/features/evm/v2/evm.go | 8 +- .../cre/features/http_action/http_action.go | 2 +- .../cre/features/http_trigger/http_trigger.go | 2 +- .../log_event_trigger/log_event_trigger.go | 2 +- system-tests/lib/cre/features/mock/mock.go | 2 +- .../features/read_contract/read_contract.go | 104 +- .../read_contract/read_contract_test.go | 36 + system-tests/lib/cre/features/sets/sets.go | 2 + .../lib/cre/features/solana/v2/solana.go | 10 +- system-tests/lib/cre/features/vault/vault.go | 2 +- .../features/web_api_target/web_api_target.go | 2 +- .../web_api_trigger/web_api_trigger.go | 2 +- system-tests/lib/cre/flags/flags.go | 5 +- system-tests/lib/cre/flags/flags_test.go | 25 + system-tests/lib/cre/flags/provider.go | 3 + system-tests/lib/cre/ocr_signer_families.go | 44 + system-tests/lib/cre/types.go | 56 +- .../cre/aptos/aptosread/config/config.go | 8 + .../tests/smoke/cre/aptos/aptosread/go.mod | 20 + .../tests/smoke/cre/aptos/aptosread/go.sum | 30 + .../tests/smoke/cre/aptos/aptosread/main.go | 113 ++ .../cre/aptos/aptoswrite/config/config.go | 18 + .../tests/smoke/cre/aptos/aptoswrite/go.mod | 20 + .../tests/smoke/cre/aptos/aptoswrite/go.sum | 30 + .../tests/smoke/cre/aptos/aptoswrite/main.go | 285 +++++ .../aptoswriteroundtrip/config/config.go | 15 + .../cre/aptos/aptoswriteroundtrip/go.mod | 20 + .../cre/aptos/aptoswriteroundtrip/go.sum | 30 + .../cre/aptos/aptoswriteroundtrip/main.go | 224 ++++ .../tests/smoke/cre/cre_suite_test.go | 8 +- .../smoke/cre/v2_aptos_capability_test.go | 740 +++++++++++ .../tests/test-helpers/before_suite.go | 36 +- system-tests/tests/test-helpers/t_helpers.go | 29 + 63 files changed, 4177 insertions(+), 123 deletions(-) create mode 100644 core/capabilities/fakes/register.go create mode 100644 core/capabilities/fakes/register_test.go create mode 100644 core/scripts/cre/environment/configs/workflow-gateway-don-aptos.toml create mode 100644 system-tests/lib/cre/environment/blockchains/aptos/aptos.go create mode 100644 system-tests/lib/cre/features/aptos/aptos.go create mode 100644 system-tests/lib/cre/features/aptos/aptos_test.go create mode 100644 system-tests/lib/cre/features/read_contract/read_contract_test.go create mode 100644 system-tests/lib/cre/flags/flags_test.go create mode 100644 system-tests/lib/cre/ocr_signer_families.go create mode 100644 system-tests/tests/smoke/cre/aptos/aptosread/config/config.go create mode 100644 system-tests/tests/smoke/cre/aptos/aptosread/go.mod create mode 100644 system-tests/tests/smoke/cre/aptos/aptosread/go.sum create mode 100644 system-tests/tests/smoke/cre/aptos/aptosread/main.go create mode 100644 system-tests/tests/smoke/cre/aptos/aptoswrite/config/config.go create mode 100644 system-tests/tests/smoke/cre/aptos/aptoswrite/go.mod create mode 100644 system-tests/tests/smoke/cre/aptos/aptoswrite/go.sum create mode 100644 system-tests/tests/smoke/cre/aptos/aptoswrite/main.go create mode 100644 system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/config/config.go create mode 100644 system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.mod create mode 100644 system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.sum create mode 100644 system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/main.go create mode 100644 system-tests/tests/smoke/cre/v2_aptos_capability_test.go diff --git a/.github/workflows/cre-system-tests.yaml b/.github/workflows/cre-system-tests.yaml index a37215fb14f..b9e44a9b936 100644 --- a/.github/workflows/cre-system-tests.yaml +++ b/.github/workflows/cre-system-tests.yaml @@ -75,6 +75,9 @@ jobs: # Add list of tests with certain topologies PER_TEST_TOPOLOGIES_JSON=${PER_TEST_TOPOLOGIES_JSON:-'{ + "Test_CRE_V2_Aptos_Suite": [ + {"topology":"workflow-gateway-aptos","configs":"configs/workflow-gateway-don-aptos.toml"} + ], "Test_CRE_V2_Solana_Suite": [ {"topology":"workflow","configs":"configs/workflow-don-solana.toml"} ], diff --git a/core/capabilities/fakes/register.go b/core/capabilities/fakes/register.go new file mode 100644 index 00000000000..522c0a7bc50 --- /dev/null +++ b/core/capabilities/fakes/register.go @@ -0,0 +1,20 @@ +package fakes + +import ( + "context" + "fmt" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" +) + +const EnableFakeStreamsTriggerEnvVar = "CL_ENABLE_FAKE_STREAMS_TRIGGER" + +func RegisterFakeStreamsTrigger(ctx context.Context, lggr logger.Logger, registry core.CapabilitiesRegistry, nSigners int) (*fakeStreamsTrigger, error) { + trigger := NewFakeStreamsTrigger(lggr, nSigners) + if err := registry.Add(ctx, trigger); err != nil { + return nil, fmt.Errorf("add fake streams trigger: %w", err) + } + + return trigger, nil +} diff --git a/core/capabilities/fakes/register_test.go b/core/capabilities/fakes/register_test.go new file mode 100644 index 00000000000..b71429e0977 --- /dev/null +++ b/core/capabilities/fakes/register_test.go @@ -0,0 +1,33 @@ +package fakes + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink-common/pkg/logger" + corecaps "github.com/smartcontractkit/chainlink/v2/core/capabilities" +) + +func TestRegisterFakeStreamsTrigger(t *testing.T) { + registry := corecaps.NewRegistry(logger.Test(t)) + + trigger, err := RegisterFakeStreamsTrigger(t.Context(), logger.Test(t), registry, 4) + require.NoError(t, err) + require.NotNil(t, trigger) + + capability, err := registry.Get(t.Context(), "streams-trigger@1.0.0") + require.NoError(t, err) + + info, err := capability.Info(t.Context()) + require.NoError(t, err) + require.Equal(t, "streams-trigger@1.0.0", info.ID) +} + +func TestNewFakeStreamsTrigger_UsesDeterministicSigners(t *testing.T) { + triggerA := NewFakeStreamsTrigger(logger.Test(t), 4) + triggerB := NewFakeStreamsTrigger(logger.Test(t), 4) + + require.Equal(t, triggerA.meta.Signers, triggerB.meta.Signers) + require.Equal(t, triggerA.meta.MinRequiredSignatures, triggerB.meta.MinRequiredSignatures) +} diff --git a/core/capabilities/fakes/streams_trigger.go b/core/capabilities/fakes/streams_trigger.go index ac2ae56346d..278a339cf25 100644 --- a/core/capabilities/fakes/streams_trigger.go +++ b/core/capabilities/fakes/streams_trigger.go @@ -2,6 +2,7 @@ package fakes import ( "context" + "crypto/ecdsa" "encoding/hex" "errors" "fmt" @@ -9,11 +10,12 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" "github.com/smartcontractkit/libocr/offchainreporting2/chains/evmutil" ocrTypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-common/keystore/corekeys" commonCap "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/datastreams" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers" @@ -23,7 +25,6 @@ import ( v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" "github.com/smartcontractkit/chainlink-evm/pkg/mercury/v3/reportcodec" - "github.com/smartcontractkit/chainlink-common/keystore/corekeys/ocr2key" "github.com/smartcontractkit/chainlink/v2/core/capabilities/streams" ) @@ -32,7 +33,7 @@ type fakeStreamsTrigger struct { eng *services.Engine lggr logger.Logger - signers []ocr2key.KeyBundle + signers []fakeStreamsTriggerSigner codec datastreams.ReportCodec meta datastreams.Metadata @@ -47,6 +48,10 @@ type regState struct { eventCh chan commonCap.TriggerResponse } +type fakeStreamsTriggerSigner struct { + privateKey *ecdsa.PrivateKey +} + var _ services.Service = (*fakeStreamsTrigger)(nil) var _ commonCap.TriggerCapability = (*fakeStreamsTrigger)(nil) @@ -108,10 +113,16 @@ func (st *fakeStreamsTrigger) UnregisterTrigger(ctx context.Context, request com } func NewFakeStreamsTrigger(lggr logger.Logger, nSigners int) *fakeStreamsTrigger { - signers := make([]ocr2key.KeyBundle, nSigners) + signers := make([]fakeStreamsTriggerSigner, nSigners) rawSigners := make([][]byte, nSigners) for i := range nSigners { - signers[i], _ = ocr2key.New(corekeys.EVM) + keyMaterial := make([]byte, 32) + keyMaterial[31] = byte(i + 1) + privateKey, err := crypto.ToECDSA(keyMaterial) + if err != nil { + panic(err) + } + signers[i] = fakeStreamsTriggerSigner{privateKey: privateKey} rawSigners[i] = signers[i].PublicKey() } @@ -225,6 +236,20 @@ func newReport(ctx context.Context, lggr logger.Logger, feedID [32]byte, price i return raw } +func (s fakeStreamsTriggerSigner) PublicKey() ocrTypes.OnchainPublicKey { + address := crypto.PubkeyToAddress(s.privateKey.PublicKey) + return common.CopyBytes(address[:]) +} + +func (s fakeStreamsTriggerSigner) Sign(reportCtx ocrTypes.ReportContext, report ocrTypes.Report) ([]byte, error) { + rawReportContext := evmutil.RawReportContext(reportCtx) + sigData := crypto.Keccak256(report) + sigData = append(sigData, rawReportContext[0][:]...) + sigData = append(sigData, rawReportContext[1][:]...) + sigData = append(sigData, rawReportContext[2][:]...) + return crypto.Sign(crypto.Keccak256(sigData), s.privateKey) +} + func rawReportContext(reportCtx ocrTypes.ReportContext) []byte { rc := evmutil.RawReportContext(reportCtx) flat := []byte{} diff --git a/core/scripts/cre/environment/configs/capability_defaults.toml b/core/scripts/cre/environment/configs/capability_defaults.toml index fad176d9741..6e46cd8d894 100644 --- a/core/scripts/cre/environment/configs/capability_defaults.toml +++ b/core/scripts/cre/environment/configs/capability_defaults.toml @@ -130,6 +130,16 @@ # FromAddress = "0x0000000000000000000000000000000000000000" # ForwarderAddress = "0x0000000000000000000000000000000000000000" +# Aptos chain capability plugin (View + WriteReport). Runtime values are injected per chain. +[capability_configs.write-aptos] + binary_name = "aptos" + +[capability_configs.write-aptos.values] + # ChainID and forwarder address are injected at job proposal time. + RequestTimeout = "30s" + TransmissionSchedule = "allAtOnce" + DeltaStage = "1500ms" + [capability_configs.solana.values] TxAcceptanceState = 3 TxRetentonTimeout = "120s" diff --git a/core/scripts/cre/environment/configs/workflow-gateway-don-aptos.toml b/core/scripts/cre/environment/configs/workflow-gateway-don-aptos.toml new file mode 100644 index 00000000000..37a3a5acd18 --- /dev/null +++ b/core/scripts/cre/environment/configs/workflow-gateway-don-aptos.toml @@ -0,0 +1,83 @@ +# Same as workflow-gateway-don.toml but with Aptos chain and Aptos read capability plumbing. +# Anvil 1337: registry and gateway. Aptos: local devnet (chain_id 4). Run: env config path , then env start. + +[[blockchains]] + type = "anvil" + chain_id = "1337" + container_name = "anvil-1337" + docker_cmd_params = ["-b", "0.5", "--mixed-mining"] + +[[blockchains]] + type = "aptos" + chain_id = "4" + +[jd] + csa_encryption_key = "d1093c0060d50a3c89c189b2e485da5a3ce57f3dcb38ab7e2c0d5f0bb2314a44" + # change to your version + image = "job-distributor:0.22.1" + +[fake] + port = 8171 + +[fake_http] + port = 8666 + +#[s3provider] +# # use all defaults +# port = 9000 +# console_port = 9001 + +[infra] + # either "docker" or "kubernetes" + type = "docker" + +[[nodesets]] + nodes = 4 + name = "workflow" + don_types = ["workflow"] + override_mode = "all" + http_port_range_start = 10100 + + supported_evm_chains = [1337] + env_vars = { CL_EVM_CMD = "", HOME = "/tmp", CL_CRE_SETTINGS_DEFAULT = '{"PerWorkflow":{"CapabilityCallTimeout":"5m0s","ChainAllowed":{"Default":"false","Values":{"1337":"true","4457093679053095497":"true"}},"ChainWrite":{"EVM":{"GasLimit":{"Default":"5000000","Values":{"1337":"10000000"}}}}}}' } + capabilities = ["ocr3", "custom-compute", "web-api-trigger", "cron", "http-action", "http-trigger", "consensus", "don-time", "write-evm-1337", "read-contract-1337", "read-contract-4", "write-aptos-4", "evm-1337"] + registry_based_launch_allowlist = ["cron-trigger@1.0.0"] + + [nodesets.db] + image = "postgres:12.0" + port = 13000 + + [[nodesets.node_specs]] + roles = ["plugin"] + [nodesets.node_specs.node] + docker_ctx = "../../../.." + docker_file = "core/chainlink.Dockerfile" + docker_build_args = { "CL_IS_PROD_BUILD" = "false" } + # image = "chainlink-tmp:latest" + user_config_overrides = "" + +[[nodesets]] + nodes = 1 + name = "bootstrap-gateway" + don_types = ["bootstrap", "gateway"] + override_mode = "each" + http_port_range_start = 10300 + + env_vars = { CL_EVM_CMD = "", HOME = "/tmp" } + supported_evm_chains = [1337] + + [nodesets.db] + image = "postgres:12.0" + port = 13200 + + [[nodesets.node_specs]] + roles = ["bootstrap", "gateway"] + [nodesets.node_specs.node] + docker_ctx = "../../../.." + docker_file = "core/chainlink.Dockerfile" + docker_build_args = { "CL_IS_PROD_BUILD" = "false" } + # 5002 is the web API capabilities port for incoming requests + # 15002 is the vault port for incoming requests + custom_ports = ["5002:5002", "15002:15002"] + # image = "chainlink-tmp:latest" + user_config_overrides = "" diff --git a/core/scripts/cre/environment/mock/trigger_types.go b/core/scripts/cre/environment/mock/trigger_types.go index 5725b892a2f..9e747c76586 100644 --- a/core/scripts/cre/environment/mock/trigger_types.go +++ b/core/scripts/cre/environment/mock/trigger_types.go @@ -5,9 +5,10 @@ import ( "time" "github.com/google/uuid" - cron2 "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" "google.golang.org/protobuf/types/known/anypb" + crontypedapi "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/triggers/cron" + pb2 "github.com/smartcontractkit/chainlink/system-tests/lib/cre/mock/pb" ) @@ -24,7 +25,7 @@ func getTriggerRequest(triggerType TriggerType) (*pb2.SendTriggerEventRequest, e switch triggerType { case TriggerTypeCron: // First create the payload - payload := &cron2.LegacyPayload{ //nolint:staticcheck // legacy + payload := &crontypedapi.LegacyPayload{ //nolint:staticcheck // legacy ScheduledExecutionTime: time.Now().Format(time.RFC3339Nano), } diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 9ee3b2bc8c9..46a231e93f5 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -7,6 +7,7 @@ import ( "fmt" "math/big" "net/http" + "os" "strconv" "sync" "time" @@ -56,6 +57,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/capabilities" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/fakes" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" @@ -239,6 +241,20 @@ func NewApplication(ctx context.Context, opts ApplicationOpts) (Application, err // for tests only, in prod Registry should always be set at this point opts.CapabilitiesRegistry = capabilities.NewRegistry(globalLogger) } + if raw := os.Getenv(fakes.EnableFakeStreamsTriggerEnvVar); raw != "" { + enabled, parseErr := strconv.ParseBool(raw) + if parseErr != nil { + return nil, fmt.Errorf("failed to parse %s: %w", fakes.EnableFakeStreamsTriggerEnvVar, parseErr) + } + if enabled { + trigger, registerErr := fakes.RegisterFakeStreamsTrigger(ctx, globalLogger, opts.CapabilitiesRegistry, 4) + if registerErr != nil { + return nil, fmt.Errorf("failed to register fake streams trigger: %w", registerErr) + } + srvcs = append(srvcs, trigger) + globalLogger.Infow("enabled fake streams trigger", "envVar", fakes.EnableFakeStreamsTriggerEnvVar) + } + } if opts.DonTimeStore == nil { opts.DonTimeStore = dontime.NewStore(dontime.DefaultRequestTimeout) diff --git a/core/services/standardcapabilities/conversions/conversions.go b/core/services/standardcapabilities/conversions/conversions.go index 3f2130a7b19..257d7c025fd 100644 --- a/core/services/standardcapabilities/conversions/conversions.go +++ b/core/services/standardcapabilities/conversions/conversions.go @@ -25,6 +25,22 @@ func GetCapabilityIDFromCommand(command string, config string) string { return "" } return "evm:ChainSelector:" + strconv.FormatUint(selector, 10) + "@1.0.0" + case "aptos": + var cfg struct { + ChainID string `json:"chainId"` + } + if err := json.Unmarshal([]byte(config), &cfg); err != nil { + return "" + } + chainID, err := strconv.ParseUint(cfg.ChainID, 10, 64) + if err != nil { + return "" + } + selector, ok := chainselectors.AptosChainIdToChainSelector()[chainID] + if !ok { + return "" + } + return "aptos:ChainSelector:" + strconv.FormatUint(selector, 10) + "@1.0.0" case "consensus": return "consensus@1.0.0-alpha" case "cron": @@ -44,6 +60,8 @@ func GetCommandFromCapabilityID(capabilityID string) string { switch { case strings.HasPrefix(capabilityID, "evm"): return "evm" + case strings.HasPrefix(capabilityID, "aptos:ChainSelector:"): + return "aptos" case strings.HasPrefix(capabilityID, "consensus"): return "consensus" case strings.HasPrefix(capabilityID, "cron-trigger"): diff --git a/core/services/standardcapabilities/conversions/conversions_test.go b/core/services/standardcapabilities/conversions/conversions_test.go index f5de925893a..b410cce9ba6 100644 --- a/core/services/standardcapabilities/conversions/conversions_test.go +++ b/core/services/standardcapabilities/conversions/conversions_test.go @@ -43,6 +43,24 @@ func Test_GetCapabilityIDFromCommand(t *testing.T) { config: `{"chainId": 1, "network": "mainnet", "otherField": "value"}`, expected: "evm:ChainSelector:5009297550715157269@1.0.0", }, + { + name: "aptos command with valid config - localnet", + command: "/usr/local/bin/aptos", + config: `{"chainId":"4","network":"aptos"}`, + expected: "aptos:ChainSelector:4457093679053095497@1.0.0", + }, + { + name: "aptos command with invalid chainId", + command: "/usr/local/bin/aptos", + config: `{"chainId":"not-a-number","network":"aptos"}`, + expected: "", + }, + { + name: "aptos command with unknown chainId", + command: "/usr/local/bin/aptos", + config: `{"chainId":"999999","network":"aptos"}`, + expected: "", + }, { name: "evm command with invalid JSON", command: "/usr/local/bin/evm", @@ -173,6 +191,16 @@ func Test_GetCommandFromCapabilityID(t *testing.T) { capabilityID: "evm:ChainSelector:5009297550715157269@2.0.0", expected: "evm", }, + { + name: "aptos localnet capability", + capabilityID: "aptos:ChainSelector:4457093679053095497@1.0.0", + expected: "aptos", + }, + { + name: "aptos capability - different version", + capabilityID: "aptos:ChainSelector:4457093679053095497@2.0.0", + expected: "aptos", + }, { name: "unknown capability", capabilityID: "unknown@1.0.0", @@ -207,4 +235,8 @@ func Test_roundTrip(t *testing.T) { // EVM round-trip: command base name is preserved evmCapID := GetCapabilityIDFromCommand("/usr/local/bin/evm", `{"chainId": 1}`) assert.Equal(t, "evm", GetCommandFromCapabilityID(evmCapID)) + + // Aptos round-trip: command base name is preserved + aptosCapID := GetCapabilityIDFromCommand("/usr/local/bin/aptos", `{"chainId":"4","network":"aptos"}`) + assert.Equal(t, "aptos", GetCommandFromCapabilityID(aptosCapID)) } diff --git a/deployment/cre/jobs/propose_job_spec.go b/deployment/cre/jobs/propose_job_spec.go index fce94a5fbf9..7afed023ca6 100644 --- a/deployment/cre/jobs/propose_job_spec.go +++ b/deployment/cre/jobs/propose_job_spec.go @@ -91,11 +91,11 @@ func (u ProposeJobSpec) Apply(e cldf.Environment, input ProposeJobSpecInput) (cl switch input.Template { // This will hold all standard capabilities jobs as we add support for them. case job_types.EVM, job_types.Cron, job_types.HTTPTrigger, job_types.HTTPAction, job_types.ConfidentialHTTP, job_types.Consensus, job_types.WebAPITrigger, job_types.WebAPITarget, job_types.CustomCompute, job_types.LogEventTrigger, job_types.ReadContract, job_types.Solana: - // Only consensus generates an oracle factory, for now... - job, err := input.Inputs.ToStandardCapabilityJob(input.JobName, input.Template == job_types.Consensus) + job, err := input.Inputs.ToStandardCapabilityJob(input.JobName, false) if err != nil { return cldf.ChangesetOutput{}, fmt.Errorf("failed to convert inputs to standard capability job: %w", err) } + job.GenerateOracleFactory = requiresOracleFactory(input.Template, job) r, rErr := operations.ExecuteSequence( e.OperationsBundle, @@ -328,3 +328,14 @@ func (u ProposeJobSpec) Apply(e cldf.Environment, input ProposeJobSpecInput) (cl Reports: []operations.Report[any, any]{report}, }, nil } + +func requiresOracleFactory(template job_types.JobSpecTemplate, job pkg.StandardCapabilityJob) bool { + if template == job_types.Consensus { + return true + } + + // Aptos worker jobs now use the ReadContract template path. + // Preserve prior behavior from the dedicated Aptos template by enabling oracle + // factory generation whenever an Aptos chain selector is present. + return template == job_types.ReadContract && job.ChainSelectorAptos > 0 +} diff --git a/deployment/cre/jobs/propose_job_spec_test.go b/deployment/cre/jobs/propose_job_spec_test.go index 6fde427d25d..34685ea9563 100644 --- a/deployment/cre/jobs/propose_job_spec_test.go +++ b/deployment/cre/jobs/propose_job_spec_test.go @@ -767,6 +767,69 @@ PerSenderBurst = 100 } }) + t.Run("successful aptos readcontract job distribution includes oracle factory", func(t *testing.T) { + chainSelector := testEnv.RegistrySelector + ds := datastore.NewMemoryDataStore() + + err := ds.Addresses().Add(datastore.AddressRef{ + ChainSelector: chainSelector, + Type: datastore.ContractType(ocr3.OCR3Capability), + Version: semver.MustParse("1.0.0"), + Address: "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", + Qualifier: "ocr3-contract-qualifier", + }) + require.NoError(t, err) + + env.DataStore = ds.Seal() + + input := jobs.ProposeJobSpecInput{ + Environment: "test", + Domain: "cre", + JobName: "aptos-readcontract-cap-job", + DONName: test.DONName, + Template: job_types.ReadContract, + DONFilters: []offchain.TargetDONFilter{ + {Key: offchain.FilterKeyDONName, Value: test.DONName}, + {Key: "environment", Value: "test"}, + {Key: "product", Value: offchain.ProductLabel}, + }, + Inputs: job_types.JobSpecInput{ + "command": "/usr/bin/aptos", + "config": `{"chainId":"4","network":"aptos","creForwarderAddress":"0x1111111111111111111111111111111111111111111111111111111111111111"}`, + "contractQualifier": "ocr3-contract-qualifier", + "chainSelectorEVM": strconv.FormatUint(chainSelector, 10), + "chainSelectorAptos": strconv.FormatUint( + testEnv.AptosSelector, + 10, + ), + "bootstrapPeers": []string{ + "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001", + }, + }, + } + + out, err := jobs.ProposeJobSpec{}.Apply(*env, input) + require.NoError(t, err) + assert.Len(t, out.Reports, 1) + + reqs, err := testEnv.TestJD.ListProposedJobRequests() + require.NoError(t, err) + + filteredReqs := slices.DeleteFunc(reqs, func(s *job.ProposeJobRequest) bool { + return !strings.Contains(s.Spec, `name = "aptos-readcontract-cap-job"`) + }) + assert.Len(t, filteredReqs, 4) + + for _, req := range filteredReqs { + assert.Contains(t, req.Spec, `name = "aptos-readcontract-cap-job"`) + assert.Contains(t, req.Spec, `command = "/usr/bin/aptos"`) + assert.Contains(t, req.Spec, `[oracle_factory]`) + assert.Contains(t, req.Spec, `enabled = true`) + assert.Contains(t, req.Spec, `strategyName = "multi-chain"`) + assert.Contains(t, req.Spec, `aptos = "fake_orc_bundle_aptos"`) + } + }) + t.Run("failed cron job distribution due to bad input", func(t *testing.T) { input := jobs.ProposeJobSpecInput{ Environment: "test", diff --git a/go.md b/go.md index 1fff207c3f9..4916be19939 100644 --- a/go.md +++ b/go.md @@ -481,6 +481,8 @@ flowchart LR chainlink/system-tests/tests --> chainlink/system-tests/tests/regression/cre/evm/logtrigger-negative chainlink/system-tests/tests --> chainlink/system-tests/tests/regression/cre/http chainlink/system-tests/tests --> chainlink/system-tests/tests/regression/cre/httpaction-negative + chainlink/system-tests/tests --> chainlink/system-tests/tests/smoke/cre/aptos/aptoswrite + chainlink/system-tests/tests --> chainlink/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip chainlink/system-tests/tests --> chainlink/system-tests/tests/smoke/cre/evm/evmread chainlink/system-tests/tests --> chainlink/system-tests/tests/smoke/cre/evm/logtrigger chainlink/system-tests/tests --> chainlink/system-tests/tests/smoke/cre/evmread @@ -503,6 +505,15 @@ flowchart LR chainlink/system-tests/tests/regression/cre/httpaction-negative --> cre-sdk-go/capabilities/networking/http chainlink/system-tests/tests/regression/cre/httpaction-negative --> cre-sdk-go/capabilities/scheduler/cron click chainlink/system-tests/tests/regression/cre/httpaction-negative href "https://github.com/smartcontractkit/chainlink" + chainlink/system-tests/tests/smoke/cre/aptos/aptosread --> cre-sdk-go/capabilities/blockchain/aptos + chainlink/system-tests/tests/smoke/cre/aptos/aptosread --> cre-sdk-go/capabilities/scheduler/cron + click chainlink/system-tests/tests/smoke/cre/aptos/aptosread href "https://github.com/smartcontractkit/chainlink" + chainlink/system-tests/tests/smoke/cre/aptos/aptoswrite --> cre-sdk-go/capabilities/blockchain/aptos + chainlink/system-tests/tests/smoke/cre/aptos/aptoswrite --> cre-sdk-go/capabilities/scheduler/cron + click chainlink/system-tests/tests/smoke/cre/aptos/aptoswrite href "https://github.com/smartcontractkit/chainlink" + chainlink/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip --> cre-sdk-go/capabilities/blockchain/aptos + chainlink/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip --> cre-sdk-go/capabilities/scheduler/cron + click chainlink/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip href "https://github.com/smartcontractkit/chainlink" chainlink/system-tests/tests/smoke/cre/evm/evmread --> cre-sdk-go/capabilities/blockchain/evm chainlink/system-tests/tests/smoke/cre/evm/evmread --> cre-sdk-go/capabilities/scheduler/cron click chainlink/system-tests/tests/smoke/cre/evm/evmread href "https://github.com/smartcontractkit/chainlink" @@ -531,6 +542,8 @@ flowchart LR click chainlink/v2 href "https://github.com/smartcontractkit/chainlink" cre-sdk-go --> chainlink-protos/cre/go click cre-sdk-go href "https://github.com/smartcontractkit/cre-sdk-go" + cre-sdk-go/capabilities/blockchain/aptos --> cre-sdk-go + click cre-sdk-go/capabilities/blockchain/aptos href "https://github.com/smartcontractkit/cre-sdk-go" cre-sdk-go/capabilities/blockchain/evm --> chainlink-common/pkg/workflows/sdk/v2/pb cre-sdk-go/capabilities/blockchain/evm --> cre-sdk-go click cre-sdk-go/capabilities/blockchain/evm href "https://github.com/smartcontractkit/cre-sdk-go" @@ -585,6 +598,9 @@ flowchart LR chainlink/system-tests/tests/regression/cre/evm/logtrigger-negative chainlink/system-tests/tests/regression/cre/http chainlink/system-tests/tests/regression/cre/httpaction-negative + chainlink/system-tests/tests/smoke/cre/aptos/aptosread + chainlink/system-tests/tests/smoke/cre/aptos/aptoswrite + chainlink/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip chainlink/system-tests/tests/smoke/cre/evm/evmread chainlink/system-tests/tests/smoke/cre/evm/logtrigger chainlink/system-tests/tests/smoke/cre/evmread @@ -684,6 +700,7 @@ flowchart LR subgraph cre-sdk-go-repo[cre-sdk-go] cre-sdk-go + cre-sdk-go/capabilities/blockchain/aptos cre-sdk-go/capabilities/blockchain/evm cre-sdk-go/capabilities/blockchain/solana cre-sdk-go/capabilities/networking/http diff --git a/plugins/plugins.private.yaml b/plugins/plugins.private.yaml index d78f7987747..d51cd2635de 100644 --- a/plugins/plugins.private.yaml +++ b/plugins/plugins.private.yaml @@ -23,7 +23,7 @@ plugins: installPath: "." consensus: - moduleURI: "github.com/smartcontractkit/capabilities/consensus" - gitRef: "9382dd467b74fe964497d84ac134162eac150322" + gitRef: "v0.0.2-0.20260317221214-ef3252b7b433" installPath: "." workflowevent: - enabled: false @@ -46,6 +46,10 @@ plugins: - moduleURI: "github.com/smartcontractkit/capabilities/chain_capabilities/solana" gitRef: "6d553b1b59f12d948f163012c822f7417d66d996" installPath: "." + aptos: + - moduleURI: "github.com/smartcontractkit/capabilities/chain_capabilities/aptos" + gitRef: "v0.0.0-20260317221214-ef3252b7b433" + installPath: "." mock: - moduleURI: "github.com/smartcontractkit/capabilities/mock" gitRef: "9382dd467b74fe964497d84ac134162eac150322" diff --git a/system-tests/lib/cre/contracts/keystone.go b/system-tests/lib/cre/contracts/keystone.go index 97fce670aad..81d70044527 100644 --- a/system-tests/lib/cre/contracts/keystone.go +++ b/system-tests/lib/cre/contracts/keystone.go @@ -178,7 +178,7 @@ func (d *dons) embedOCR3Config(capConfig *capabilitiespb.CapabilityConfig, don d return nil } -func (d *dons) mustToV2ConfigureInput(chainSelector uint64, contractAddress string, capabilityToOCR3Config map[string]*ocr3.OracleConfig, extraSignerFamilies []string) cap_reg_v2_seq.ConfigureCapabilitiesRegistryInput { +func (d *dons) mustToV2ConfigureInput(chainSelector uint64, contractAddress string, capabilityToOCR3Config map[string]*ocr3.OracleConfig, capabilityToExtraSignerFamilies map[string][]string) cap_reg_v2_seq.ConfigureCapabilitiesRegistryInput { nops := make([]capabilities_registry_v2.CapabilitiesRegistryNodeOperatorParams, 0) nodes := make([]contracts.NodesInput, 0) capabilities := make([]contracts.RegisterableCapability, 0) @@ -213,17 +213,17 @@ func (d *dons) mustToV2ConfigureInput(chainSelector uint64, contractAddress stri } for i, nop := range don.Nops { nopName := nop.Name + + ns, err := deployment.NodeInfo(nop.Nodes, d.offChain) + if err != nil { + panic(err) + } if _, exists := nopMap[nopName]; !exists { nopMap[nopName] = capabilities_registry_v2.CapabilitiesRegistryNodeOperatorParams{ Admin: adminAddrs[i], Name: nopName, } - ns, err := deployment.NodeInfo(nop.Nodes, d.offChain) - if err != nil { - panic(err) - } - // Add nodes for this NOP for _, n := range ns { ocrCfg, ok := n.OCRConfigForChainSelector(chainSelector) @@ -258,17 +258,26 @@ func (d *dons) mustToV2ConfigureInput(chainSelector uint64, contractAddress stri for _, cap := range don.Capabilities { capID := fmt.Sprintf("%s@%s", cap.Capability.LabelledName, cap.Capability.Version) configBytes := []byte("{}") - if cap.Config != nil { - if cap.UseCapRegOCRConfig { - ocrConfig := capabilityToOCR3Config[cap.Capability.LabelledName] - if ocrConfig == nil { - panic("no OCR3 config found for capability " + cap.Capability.LabelledName) - } - if err := d.embedOCR3Config(cap.Config, don, chainSelector, ocrConfig, extraSignerFamilies); err != nil { - panic(fmt.Sprintf("failed to embed OCR3 config for capability %s: %s", cap.Capability.LabelledName, err)) - } + + capConfig := cap.Config + shouldMarshalProtoConfig := capConfig != nil + if cap.UseCapRegOCRConfig { + if capConfig == nil { + capConfig = &capabilitiespb.CapabilityConfig{} + } + shouldMarshalProtoConfig = true + + ocrConfig := capabilityToOCR3Config[cap.Capability.LabelledName] + if ocrConfig == nil { + panic("no OCR3 config found for capability " + cap.Capability.LabelledName) } - if protoBytes, err := proto.Marshal(cap.Config); err == nil { + if err := d.embedOCR3Config(capConfig, don, chainSelector, ocrConfig, capabilityToExtraSignerFamilies[cap.Capability.LabelledName]); err != nil { + panic(fmt.Sprintf("failed to embed OCR3 config for capability %s: %s", cap.Capability.LabelledName, err)) + } + } + + if shouldMarshalProtoConfig { + if protoBytes, err := proto.Marshal(capConfig); err == nil { configBytes = protoBytes } } @@ -455,7 +464,7 @@ func ConfigureCapabilityRegistry(input cre.ConfigureCapabilityRegistryInput) (Ca if ocrConfig == nil { return nil, fmt.Errorf("no OCR3 config found for capability %s", cap.Capability.LabelledName) } - if err := dons.embedOCR3Config(don.Capabilities[i].Config, don, input.ChainSelector, ocrConfig, input.ExtraSignerFamilies); err != nil { + if err := dons.embedOCR3Config(don.Capabilities[i].Config, don, input.ChainSelector, ocrConfig, input.CapabilityToExtraSignerFamilies[cap.Capability.LabelledName]); err != nil { return nil, fmt.Errorf("failed to embed OCR3 config for capability %s: %w", cap.Capability.LabelledName, err) } } @@ -490,7 +499,7 @@ func ConfigureCapabilityRegistry(input cre.ConfigureCapabilityRegistryInput) (Ca } // Transform dons data to V2 sequence input format - v2Input := dons.mustToV2ConfigureInput(input.ChainSelector, input.CapabilitiesRegistryAddress.Hex(), input.CapabilityToOCR3Config, input.ExtraSignerFamilies) + v2Input := dons.mustToV2ConfigureInput(input.ChainSelector, input.CapabilitiesRegistryAddress.Hex(), input.CapabilityToOCR3Config, input.CapabilityToExtraSignerFamilies) _, seqErr := operations.ExecuteSequence( input.CldEnv.OperationsBundle, cap_reg_v2_seq.ConfigureCapabilitiesRegistry, diff --git a/system-tests/lib/cre/contracts/ocr3.go b/system-tests/lib/cre/contracts/ocr3.go index 0916a83e607..9bf7de89d6c 100644 --- a/system-tests/lib/cre/contracts/ocr3.go +++ b/system-tests/lib/cre/contracts/ocr3.go @@ -2,6 +2,7 @@ package contracts import ( "fmt" + "time" "github.com/Masterminds/semver/v3" "github.com/ethereum/go-ethereum/common" @@ -71,6 +72,7 @@ func DefaultOCR3Config() *ocr3.OracleConfig { MaxOutcomeLengthBytes: 1000000, MaxReportLengthBytes: 1000000, MaxBatchSize: 1000, + RequestTimeout: 30 * time.Second, }, UniqueReports: true, } diff --git a/system-tests/lib/cre/don.go b/system-tests/lib/cre/don.go index 9f0c6c7073d..188bfd63b7f 100644 --- a/system-tests/lib/cre/don.go +++ b/system-tests/lib/cre/don.go @@ -426,6 +426,11 @@ func NewNode(ctx context.Context, name string, nodeMetadata *NodeMetadata, ctfNo } } + aptosAccounts, aptosErr := chainlinkClient.MustReadAptosAccounts() + if aptosErr == nil { + node.Addresses.AptosAddresses = aptosAccounts + } + return node, nil } @@ -435,10 +440,9 @@ type JobDistributorDetails struct { } type Addresses struct { - AdminAddress string `toml:"admin_address" json:"admin_address"` // address used to pay for transactions, applicable only for worker nodes - MultiAddress string `toml:"multi_address" json:"multi_address"` // multi address used by OCR2, applicable only for bootstrap nodes - - // maybe in the future add public addresses per chain to avoid the need to access node's keys every time? + AdminAddress string `toml:"admin_address" json:"admin_address"` // address used to pay for transactions, applicable only for worker nodes + MultiAddress string `toml:"multi_address" json:"multi_address"` // multi address used by OCR2, applicable only for bootstrap nodes + AptosAddresses []string `toml:"aptos_addresses" json:"aptos_addresses"` // Aptos public addresses cached from the node key API } type NodeClients struct { @@ -452,8 +456,11 @@ type JDChainConfigInput struct { } func createJDChainConfigs(ctx context.Context, n *Node, supportedChains []blockchains.Blockchain, jd *jd.JobDistributor) error { + // Dedupe by (chain ID, chain type) so we never create the same config twice (avoids unique constraint violation). + seen := make(map[string]struct{}) for _, chain := range supportedChains { var account string + var accountAddrPubKey string chainIDStr := strconv.FormatUint(chain.ChainID(), 10) switch strings.ToLower(chain.ChainFamily()) { @@ -490,15 +497,14 @@ func createJDChainConfigs(ctx context.Context, n *Node, supportedChains []blockc account = accounts[0] } case chainselectors.FamilyAptos: - // always fetch; currently Node doesn't have Aptos keys - accounts, err := n.Clients.GQLClient.FetchKeys(ctx, strings.ToUpper(chain.ChainFamily())) + accounts, err := AptosAccountsForNode(ctx, n) if err != nil { - return fmt.Errorf("failed to fetch account address for node %s and chain %s: %w", n.Name, chain.ChainFamily(), err) - } - if len(accounts) == 0 { - return fmt.Errorf("failed to fetch account address for node %s and chain %s", n.Name, chain.ChainFamily()) + return fmt.Errorf("failed to fetch aptos account address for node %s: %w", n.Name, err) } account = accounts[0] + // Deployment parsing prefers AccountAddressPublicKey for Aptos chain configs. + // Mirror transmitter into this field so OCRConfigForChainSelector always resolves it. + accountAddrPubKey = account default: return fmt.Errorf("unsupported chainType %v", chain.ChainFamily()) } @@ -507,12 +513,18 @@ func createJDChainConfigs(ctx context.Context, n *Node, supportedChains []blockc if chain.IsFamily(blockchain.FamilyTron) { chainType = strings.ToUpper(blockchain.FamilyEVM) } + dedupeKey := chainIDStr + "\x00" + chainType + if _, exists := seen[dedupeKey]; exists { + continue + } + seen[dedupeKey] = struct{}{} + ocr2BundleID, createErr := n.Clients.GQLClient.FetchOCR2KeyBundleID(ctx, chainType) if createErr != nil { return fmt.Errorf("failed to fetch OCR2 key bundle id for node %s: %w", n.Name, createErr) } if ocr2BundleID == "" { - return fmt.Errorf("no OCR2 key bundle id found for node %s", n.Name) + return fmt.Errorf("no OCR2 key bundle id found for node %s (chainType=%s)", n.Name, chainType) } if n.Keys.OCR2BundleIDs == nil { @@ -542,20 +554,24 @@ func createJDChainConfigs(ctx context.Context, n *Node, supportedChains []blockc // we need to create JD chain config for each chain, because later on changestes ask the node for that chain data // each node needs to have OCR2 enabled, because p2pIDs are used by some contracts to identify nodes (e.g. capability registry) _, createErr = n.Clients.GQLClient.CreateJobDistributorChainConfig(ctx, client.JobDistributorChainConfigInput{ - JobDistributorID: n.JobDistributorDetails.JDID, - ChainID: chainIDStr, - ChainType: chainType, - AccountAddr: account, - AdminAddr: n.Addresses.AdminAddress, - Ocr2Enabled: true, - Ocr2IsBootstrap: n.HasRole(RoleBootstrap), - Ocr2Multiaddr: n.Addresses.MultiAddress, - Ocr2P2PPeerID: n.Keys.P2PKey.PeerID.String(), - Ocr2KeyBundleID: ocr2BundleID, - Ocr2Plugins: `{}`, + JobDistributorID: n.JobDistributorDetails.JDID, + ChainID: chainIDStr, + ChainType: chainType, + AccountAddr: account, + AccountAddrPubKey: accountAddrPubKey, + AdminAddr: n.Addresses.AdminAddress, + Ocr2Enabled: true, + Ocr2IsBootstrap: n.HasRole(RoleBootstrap), + Ocr2Multiaddr: n.Addresses.MultiAddress, + Ocr2P2PPeerID: n.Keys.P2PKey.PeerID.String(), + Ocr2KeyBundleID: ocr2BundleID, + Ocr2Plugins: `{}`, }) - // TODO: add a check if the chain config failed because of a duplicate in that case, should we update or return success? if createErr != nil { + // Config may already exist (e.g. duplicate key from prior run or concurrent node registration); treat as success. + if strings.Contains(createErr.Error(), "duplicate key") || strings.Contains(createErr.Error(), "23505") { + return nil + } return createErr } @@ -571,6 +587,13 @@ func createJDChainConfigs(ctx context.Context, n *Node, supportedChains []blockc return nil } +func AptosAccountsForNode(_ context.Context, n *Node) ([]string, error) { + if len(n.Addresses.AptosAddresses) > 0 { + return append([]string(nil), n.Addresses.AptosAddresses...), nil + } + return nil, fmt.Errorf("missing cached aptos addresses for node %s", n.Name) +} + // AcceptJob accepts the job proposal for the given job proposal spec func (n *Node) AcceptJob(ctx context.Context, spec string) error { // fetch JD to get the job proposals @@ -809,12 +832,16 @@ func HasFlag(values []string, capability string) bool { func findDonSupportedChains(donMetadata *DonMetadata, bcs []blockchains.Blockchain) ([]blockchains.Blockchain, error) { chains := make([]blockchains.Blockchain, 0) + chainCapabilityIDs := donMetadata.MustNodeSet().ChainCapabilityChainIDs() for _, bc := range bcs { hasEVMChainEnabled := slices.Contains(donMetadata.EVMChains(), bc.ChainID()) + hasChainCapabilityEnabled := slices.Contains(chainCapabilityIDs, bc.ChainID()) chainIsSolana := bc.IsFamily(chainselectors.FamilySolana) - if !hasEVMChainEnabled && (!chainIsSolana) { + // Include all Solana chains (legacy behavior), and include any chain that is + // explicitly referenced by chain-scoped capabilities (e.g. write-aptos-4). + if !hasEVMChainEnabled && !hasChainCapabilityEnabled && !chainIsSolana { continue } diff --git a/system-tests/lib/cre/don/config/config.go b/system-tests/lib/cre/don/config/config.go index 9e17161b6b3..ab19fc46f2d 100644 --- a/system-tests/lib/cre/don/config/config.go +++ b/system-tests/lib/cre/don/config/config.go @@ -5,6 +5,7 @@ import ( "fmt" "maps" "math/big" + "net/url" "slices" "strconv" "strings" @@ -378,6 +379,18 @@ func addBootstrapNodeConfig( appendSolanaChain(&existingConfig.Solana, commonInputs.solanaChain) } + for _, ac := range commonInputs.aptosChains { + existingConfig.Aptos = append(existingConfig.Aptos, corechainlink.RawConfig{ + "ChainID": ac.ChainID, + "Enabled": true, + "Workflow": map[string]any{"ForwarderAddress": ac.ForwarderAddress}, + "Nodes": []map[string]any{{"Name": "default", "URL": ac.NodeURL}}, + }) + } + + // Set external registry only (local EVM capability registry). We do not set [Capabilities.Local]; + // capabilities (e.g. cron) are registered on the on-chain capability registry via Features (e.g. Cron + // feature PreEnvStartup), same as workflow-don-solana.toml, workflow-gateway-don.toml, workflow-don-tron.toml. if existingConfig.Capabilities.ExternalRegistry.Address == nil { existingConfig.Capabilities.ExternalRegistry = coretoml.ExternalRegistry{ Address: ptr.Ptr(commonInputs.capabilityRegistry.address), @@ -434,8 +447,9 @@ func addWorkerNodeConfig( } // Preserve existing WorkflowRegistry config (e.g., AdditionalSourcesConfig from user_config_overrides) - // before resetting Capabilities struct + // and Local capabilities config before resetting Capabilities struct. existingWorkflowRegistry := existingConfig.Capabilities.WorkflowRegistry + existingLocalCapabilities := existingConfig.Capabilities.Local existingConfig.Capabilities = coretoml.Capabilities{ Peering: coretoml.P2P{ @@ -450,6 +464,7 @@ func addWorkerNodeConfig( SendToSharedPeer: ptr.Ptr(true), }, WorkflowRegistry: existingWorkflowRegistry, + Local: existingLocalCapabilities, } if len(donMetadata.RegistryBasedLaunchAllowlist) > 0 { @@ -466,6 +481,15 @@ func addWorkerNodeConfig( appendSolanaChain(&existingConfig.Solana, commonInputs.solanaChain) } + for _, ac := range commonInputs.aptosChains { + existingConfig.Aptos = append(existingConfig.Aptos, corechainlink.RawConfig{ + "ChainID": ac.ChainID, + "Enabled": true, + "Workflow": map[string]any{"ForwarderAddress": ac.ForwarderAddress}, + "Nodes": []map[string]any{{"Name": "default", "URL": ac.NodeURL}}, + }) + } + if existingConfig.Capabilities.ExternalRegistry.Address == nil { existingConfig.Capabilities.ExternalRegistry = coretoml.ExternalRegistry{ Address: ptr.Ptr(commonInputs.capabilityRegistry.address), @@ -623,6 +647,12 @@ type versionedAddress struct { version *semver.Version } +type aptosChain struct { + ChainID string + NodeURL string + ForwarderAddress string +} + type commonInputs struct { registryChainID uint64 registryChainSelector uint64 @@ -632,6 +662,7 @@ type commonInputs struct { evmChains []*evmChain solanaChain *solanaChain + aptosChains []*aptosChain provider infra.Provider } @@ -651,6 +682,8 @@ func gatherCommonInputs(input cre.GenerateConfigsInput) (*commonInputs, error) { capabilitiesRegistryAddress := crecontracts.MustGetAddressFromDataStore(input.Datastore, input.RegistryChainSelector, keystone_changeset.CapabilitiesRegistry.String(), input.ContractVersions[keystone_changeset.CapabilitiesRegistry.String()], "") workflowRegistryAddress := crecontracts.MustGetAddressFromDataStore(input.Datastore, input.RegistryChainSelector, keystone_changeset.WorkflowRegistry.String(), input.ContractVersions[keystone_changeset.WorkflowRegistry.String()], "") + aptosChains := findAptosChains(input) + return &commonInputs{ registryChainID: registryChainID, registryChainSelector: input.RegistryChainSelector, @@ -660,6 +693,7 @@ func gatherCommonInputs(input cre.GenerateConfigsInput) (*commonInputs, error) { }, evmChains: evmChains, solanaChain: solanaChain, + aptosChains: aptosChains, capabilityRegistry: versionedAddress{ address: capabilitiesRegistryAddress, version: input.ContractVersions[keystone_changeset.CapabilitiesRegistry.String()], @@ -677,8 +711,8 @@ type evmChain struct { func findEVMChains(input cre.GenerateConfigsInput) []*evmChain { evmChains := make([]*evmChain, 0) - for chainSelector, bcOut := range input.Blockchains { - if bcOut.IsFamily(chain_selectors.FamilySolana) { + for _, bcOut := range input.Blockchains { + if bcOut.IsFamily(chain_selectors.FamilySolana) || bcOut.IsFamily(chain_selectors.FamilyAptos) { continue } @@ -688,7 +722,7 @@ func findEVMChains(input cre.GenerateConfigsInput) []*evmChain { } evmChains = append(evmChains, &evmChain{ - Name: fmt.Sprintf("node-%d", chainSelector), + Name: fmt.Sprintf("node-%d", bcOut.ChainSelector()), ChainID: bcOut.ChainID(), HTTPRPC: bcOut.CtfOutput().Nodes[0].InternalHTTPUrl, WSRPC: bcOut.CtfOutput().Nodes[0].InternalWSUrl, @@ -737,6 +771,41 @@ func findOneSolanaChain(input cre.GenerateConfigsInput) (*solanaChain, error) { return solChain, nil } +const aptosZeroForwarderHex = "0x0000000000000000000000000000000000000000000000000000000000000000" + +// aptosNodeURLWithV1 normalizes an Aptos node URL so the path is /v1 (Aptos REST API base). +func aptosNodeURLWithV1(nodeURL string) string { + u, err := url.Parse(nodeURL) + if err != nil { + return nodeURL + } + path := strings.TrimRight(u.Path, "/") + if path == "" || path != "/v1" { + u.Path = "/v1" + } + return u.String() +} + +func findAptosChains(input cre.GenerateConfigsInput) []*aptosChain { + capabilityChainIDs := input.DonMetadata.MustNodeSet().ChainCapabilityChainIDs() + out := make([]*aptosChain, 0) + for _, bcOut := range input.Blockchains { + if !bcOut.IsFamily(chain_selectors.FamilyAptos) { + continue + } + if len(capabilityChainIDs) > 0 && !slices.Contains(capabilityChainIDs, bcOut.ChainID()) { + continue + } + nodeURL := aptosNodeURLWithV1(bcOut.CtfOutput().Nodes[0].InternalHTTPUrl) + out = append(out, &aptosChain{ + ChainID: strconv.FormatUint(bcOut.ChainID(), 10), + NodeURL: nodeURL, + ForwarderAddress: aptosZeroForwarderHex, + }) + } + return out +} + func buildTronEVMConfig(evmChain *evmChain) evmconfigtoml.EVMConfig { tronRPC := strings.Replace(evmChain.HTTPRPC, "jsonrpc", "wallet", 1) return evmconfigtoml.EVMConfig{ diff --git a/system-tests/lib/cre/environment/blockchains/aptos/aptos.go b/system-tests/lib/cre/environment/blockchains/aptos/aptos.go new file mode 100644 index 00000000000..332c847275a --- /dev/null +++ b/system-tests/lib/cre/environment/blockchains/aptos/aptos.go @@ -0,0 +1,352 @@ +package aptos + +import ( + "context" + "errors" + "fmt" + "net/url" + "strconv" + "strings" + "time" + + aptoslib "github.com/aptos-labs/aptos-go-sdk" + aptoscrypto "github.com/aptos-labs/aptos-go-sdk/crypto" + pkgerrors "github.com/pkg/errors" + "github.com/rs/zerolog" + + chainselectors "github.com/smartcontractkit/chain-selectors" + + cldf_chain "github.com/smartcontractkit/chainlink-deployments-framework/chain" + cldf_aptos "github.com/smartcontractkit/chainlink-deployments-framework/chain/aptos" + "github.com/smartcontractkit/chainlink-testing-framework/framework" + "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" + "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains" + "github.com/smartcontractkit/chainlink/system-tests/lib/infra" +) + +type Deployer struct { + provider infra.Provider + testLogger zerolog.Logger +} + +func NewDeployer(testLogger zerolog.Logger, provider *infra.Provider) *Deployer { + return &Deployer{ + provider: *provider, + testLogger: testLogger, + } +} + +type Blockchain struct { + testLogger zerolog.Logger + chainSelector uint64 + chainID uint64 + ctfOutput *blockchain.Output +} + +func (a *Blockchain) ChainSelector() uint64 { + return a.chainSelector +} + +func (a *Blockchain) ChainID() uint64 { + return a.chainID +} + +func (a *Blockchain) CtfOutput() *blockchain.Output { + return a.ctfOutput +} + +func (a *Blockchain) NodeURL() (string, error) { + if a.ctfOutput == nil || len(a.ctfOutput.Nodes) == 0 { + return "", fmt.Errorf("no nodes found for Aptos chain %s-%d", a.ChainFamily(), a.chainID) + } + return aptosNodeURLWithV1(a.ctfOutput.Nodes[0].ExternalHTTPUrl) +} + +func (a *Blockchain) NodeClient() (*aptoslib.NodeClient, error) { + nodeURL, err := a.NodeURL() + if err != nil { + return nil, err + } + chainID, err := aptosChainIDUint8(a.chainID) + if err != nil { + return nil, err + } + return aptoslib.NewNodeClient(nodeURL, chainID) +} + +func (a *Blockchain) LocalDeployerAccount() (*aptoslib.Account, error) { + var deployerPrivateKey aptoscrypto.Ed25519PrivateKey + if err := deployerPrivateKey.FromHex(blockchain.DefaultAptosPrivateKey); err != nil { + return nil, fmt.Errorf("failed to parse default Aptos deployer private key: %w", err) + } + deployerAccount, err := aptoslib.NewAccountFromSigner(&deployerPrivateKey) + if err != nil { + return nil, fmt.Errorf("failed to create default Aptos deployer signer: %w", err) + } + return deployerAccount, nil +} + +func (a *Blockchain) LocalDeploymentChain() (cldf_aptos.Chain, error) { + nodeURL, err := a.NodeURL() + if err != nil { + return cldf_aptos.Chain{}, err + } + client, err := a.NodeClient() + if err != nil { + return cldf_aptos.Chain{}, err + } + deployerAccount, err := a.LocalDeployerAccount() + if err != nil { + return cldf_aptos.Chain{}, err + } + return cldf_aptos.Chain{ + Selector: a.chainSelector, + Client: client, + DeployerSigner: deployerAccount, + URL: nodeURL, + Confirm: func(txHash string, opts ...any) error { + tx, err := client.WaitForTransaction(txHash, opts...) + if err != nil { + return err + } + if !tx.Success { + return fmt.Errorf("transaction failed: %s", tx.VmStatus) + } + return nil + }, + }, nil +} + +func (a *Blockchain) IsFamily(chainFamily string) bool { + return strings.EqualFold(a.ctfOutput.Family, chainFamily) +} + +func (a *Blockchain) ChainFamily() string { + return a.ctfOutput.Family +} + +func (a *Blockchain) Fund(ctx context.Context, address string, amount uint64) error { + client, err := a.NodeClient() + if err != nil { + return fmt.Errorf("cannot fund Aptos address %s: create node client: %w", address, err) + } + + var account aptoslib.AccountAddress + if parseErr := account.ParseStringRelaxed(address); parseErr != nil { + return fmt.Errorf("cannot fund Aptos address %q: parse error: %w", address, parseErr) + } + + // Fast path: use the faucet URL surfaced by CTF. Keep node-URL derivation only as + // a compatibility fallback for older cached outputs that predate that field. + if faucetURL, ferr := a.faucetURL(); ferr == nil { + if faucetClient, cErr := aptoslib.NewFaucetClient(client, faucetURL); cErr == nil { + if fundErr := faucetClient.Fund(account, amount); fundErr == nil { + if waitErr := waitForAptosAccountVisible(ctx, client, account, 15*time.Second); waitErr == nil { + a.testLogger.Info().Msgf("Funded Aptos account %s via host faucet (%d octas)", account.StringLong(), amount) + return nil + } + } + } + } + + containerName := strings.TrimSpace(a.ctfOutput.ContainerName) + if containerName == "" { + return fmt.Errorf("failed to fund Aptos address %s via host faucet and no container fallback available", address) + } + + dc, err := framework.NewDockerClient() + if err != nil { + return fmt.Errorf("failed to create docker client for Aptos funding fallback: %w", err) + } + _, execErr := dc.ExecContainerWithContext(ctx, containerName, []string{ + "aptos", "account", "fund-with-faucet", + "--account", account.StringLong(), + "--amount", strconv.FormatUint(amount, 10), + }) + if execErr != nil { + return fmt.Errorf("failed to fund Aptos address %s via container faucet fallback: %w", address, execErr) + } + if waitErr := waitForAptosAccountVisible(ctx, client, account, 20*time.Second); waitErr != nil { + return fmt.Errorf("aptos funding fallback completed but account still not visible: %w", waitErr) + } + + a.testLogger.Info().Msgf("Funded Aptos account %s via container faucet fallback (%d octas)", account.StringLong(), amount) + return nil +} + +// ToCldfChain returns the chainlink-deployments-framework aptos.Chain for this blockchain +// so that BlockChains.AptosChains() and saved state work like EVM/Solana. +func (a *Blockchain) ToCldfChain() (cldf_chain.BlockChain, error) { + nodeURL, err := a.NodeURL() + if err != nil { + return nil, fmt.Errorf("invalid Aptos ExternalHTTPUrl for chain %d: %w", a.chainID, err) + } + if nodeURL == "" { + return nil, fmt.Errorf("aptos node has no ExternalHTTPUrl for chain %d", a.chainID) + } + client, err := a.NodeClient() + if err != nil { + return nil, pkgerrors.Wrapf(err, "create Aptos RPC client for chain %d", a.chainID) + } + return cldf_aptos.Chain{ + Selector: a.chainSelector, + Client: client, + DeployerSigner: nil, // CRE read-only use; deployer not required for View calls + URL: nodeURL, + Confirm: func(txHash string, opts ...any) error { + tx, err := client.WaitForTransaction(txHash, opts...) + if err != nil { + return err + } + if !tx.Success { + return fmt.Errorf("transaction failed: %s", tx.VmStatus) + } + return nil + }, + }, nil +} + +func (a *Deployer) Deploy(ctx context.Context, input *blockchain.Input) (blockchains.Blockchain, error) { + var bcOut *blockchain.Output + var err error + + switch { + case a.provider.IsKubernetes(): + if err = blockchains.ValidateKubernetesBlockchainOutput(input); err != nil { + return nil, err + } + a.testLogger.Info().Msgf("Using configured Kubernetes blockchain URLs for %s (chain_id: %s)", input.Type, input.ChainID) + bcOut = input.Out + case input.Out != nil: + bcOut = input.Out + default: + bcOut, err = blockchain.NewWithContext(ctx, input) + if err != nil { + return nil, pkgerrors.Wrapf(err, "failed to deploy blockchain %s chainID: %s", input.Type, input.ChainID) + } + } + + // Framework Aptos output may have empty ChainID; use config input.ChainID (e.g. "4" for local devnet) + chainIDStr := bcOut.ChainID + if chainIDStr == "" { + chainIDStr = input.ChainID + } + if chainIDStr == "" { + return nil, pkgerrors.New("aptos chain id is empty (set chain_id in [[blockchains]] in TOML)") + } + chainID, err := strconv.ParseUint(chainIDStr, 10, 64) + if err != nil { + return nil, pkgerrors.Wrapf(err, "failed to parse chain id %s", chainIDStr) + } + + selector, err := aptosChainSelector(chainIDStr, chainID) + if err != nil { + return nil, err + } + + // Ensure ctfOutput has ChainID set for downstream (e.g. findAptosChains) + bcOut.ChainID = chainIDStr + + return &Blockchain{ + testLogger: a.testLogger, + chainSelector: selector, + chainID: chainID, + ctfOutput: bcOut, + }, nil +} + +// aptosChainSelector returns the chain selector for the given Aptos chain ID. +// Uses chain-selectors when available; falls back to known Aptos localnet selector for chain_id 4. +func aptosChainSelector(chainIDStr string, chainID uint64) (uint64, error) { + chainDetails, err := chainselectors.GetChainDetailsByChainIDAndFamily(chainIDStr, chainselectors.FamilyAptos) + if err == nil { + return chainDetails.ChainSelector, nil + } + // Fallback: Aptos local devnet (aptos node run-local-testnet) uses chain_id 4 and this selector + if chainID == 4 { + const aptosLocalnetSelector = 4457093679053095497 + return aptosLocalnetSelector, nil + } + return 0, pkgerrors.Wrapf(err, "failed to get chain selector for Aptos chain id %s", chainIDStr) +} + +func aptosNodeURLWithV1(rawURL string) (string, error) { + u, err := url.Parse(strings.TrimSpace(rawURL)) + if err != nil { + return "", err + } + if u.Scheme == "" || u.Host == "" { + return "", fmt.Errorf("invalid url %q", rawURL) + } + path := strings.TrimRight(u.Path, "/") + if path == "" || path != "/v1" { + u.Path = "/v1" + } + u.RawPath = "" + u.RawQuery = "" + u.Fragment = "" + return u.String(), nil +} + +func aptosFaucetURLFromNodeURL(nodeURL string) (string, error) { + u, err := url.Parse(nodeURL) + if err != nil { + return "", err + } + host := u.Hostname() + if host == "" { + return "", fmt.Errorf("empty host in node url %q", nodeURL) + } + u.Host = host + ":8081" + u.Path = "" + u.RawPath = "" + u.RawQuery = "" + u.Fragment = "" + return u.String(), nil +} + +func (a *Blockchain) faucetURL() (string, error) { + if a.ctfOutput != nil && a.ctfOutput.NetworkSpecificData != nil && a.ctfOutput.NetworkSpecificData.AptosNetwork != nil { + if faucetURL := strings.TrimSpace(a.ctfOutput.NetworkSpecificData.AptosNetwork.FaucetURL); faucetURL != "" { + return faucetURL, nil + } + } + if a.ctfOutput == nil || len(a.ctfOutput.Nodes) == 0 { + return "", errors.New("missing chain nodes output") + } + nodeURL, err := aptosNodeURLWithV1(a.ctfOutput.Nodes[0].ExternalHTTPUrl) + if err != nil { + return "", err + } + return aptosFaucetURLFromNodeURL(nodeURL) +} + +func waitForAptosAccountVisible(ctx context.Context, client *aptoslib.NodeClient, account aptoslib.AccountAddress, timeout time.Duration) error { + deadline := time.Now().Add(timeout) + var lastErr error + for time.Now().Before(deadline) { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + _, accountErr := client.Account(account) + if accountErr == nil { + return nil + } + lastErr = accountErr + time.Sleep(1 * time.Second) + } + if lastErr != nil { + return fmt.Errorf("account %s not visible after funding attempt: %w", account.StringLong(), lastErr) + } + return fmt.Errorf("account %s not visible after funding attempt", account.StringLong()) +} + +func aptosChainIDUint8(chainID uint64) (uint8, error) { + if chainID > uint64(^uint8(0)) { + return 0, fmt.Errorf("aptos chain id %d does not fit in uint8", chainID) + } + + return uint8(chainID), nil +} diff --git a/system-tests/lib/cre/environment/blockchains/sets/sets.go b/system-tests/lib/cre/environment/blockchains/sets/sets.go index c450f607300..ff73c1c9d87 100644 --- a/system-tests/lib/cre/environment/blockchains/sets/sets.go +++ b/system-tests/lib/cre/environment/blockchains/sets/sets.go @@ -5,6 +5,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains" + "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains/aptos" "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains/evm" "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains/solana" "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains/tron" @@ -16,5 +17,6 @@ func NewDeployerSet(testLogger zerolog.Logger, provider *infra.Provider) map[blo blockchain.FamilyEVM: evm.NewDeployer(testLogger, provider), blockchain.FamilySolana: solana.NewDeployer(testLogger, provider), blockchain.FamilyTron: tron.NewDeployer(testLogger, provider), + blockchain.FamilyAptos: aptos.NewDeployer(testLogger, provider), } } diff --git a/system-tests/lib/cre/environment/dons.go b/system-tests/lib/cre/environment/dons.go index d395cbc25b0..07774bd2297 100644 --- a/system-tests/lib/cre/environment/dons.go +++ b/system-tests/lib/cre/environment/dons.go @@ -214,7 +214,7 @@ func FundNodes(ctx context.Context, testLogger zerolog.Logger, dons *cre.Dons, b } for _, node := range don.Nodes { - address, addrErr := nodeAddress(node, chainFamily, bc) + address, addrErr := nodeAddress(ctx, node, chainFamily, bc) if addrErr != nil { return pkgerrors.Wrapf(addrErr, "failed to get address for node %s on chain family %s and chain %d", node.Name, chainFamily, bc.ChainID()) } @@ -237,7 +237,7 @@ func FundNodes(ctx context.Context, testLogger zerolog.Logger, dons *cre.Dons, b return nil } -func nodeAddress(node *cre.Node, chainFamily string, bc blockchains.Blockchain) (string, error) { +func nodeAddress(ctx context.Context, node *cre.Node, chainFamily string, bc blockchains.Blockchain) (string, error) { switch chainFamily { case chainselectors.FamilyEVM, chainselectors.FamilyTron: evmKey, ok := node.Keys.EVM[bc.ChainID()] @@ -253,6 +253,11 @@ func nodeAddress(node *cre.Node, chainFamily string, bc blockchains.Blockchain) return "", nil // Skip nodes without Solana keys for this chain } return solKey.PublicAddress.String(), nil + case chainselectors.FamilyAptos: + if len(node.Addresses.AptosAddresses) > 0 { + return node.Addresses.AptosAddresses[0], nil + } + return "", nil // Skip nodes without cached Aptos keys default: return "", fmt.Errorf("unsupported chain family %s", chainFamily) } diff --git a/system-tests/lib/cre/environment/environment.go b/system-tests/lib/cre/environment/environment.go index f3a1ccaa2a8..f4779040dad 100644 --- a/system-tests/lib/cre/environment/environment.go +++ b/system-tests/lib/cre/environment/environment.go @@ -189,7 +189,7 @@ func SetupTestEnvironment( fmt.Print(libformat.PurpleText("%s", input.StageGen.Wrap("Applying Features before environment startup"))) var donsCapabilities = make(map[uint64][]keystone_changeset.DONCapabilityWithConfig) var capabilityToOCR3Config = make(map[string]*ocr3.OracleConfig) - extraSignerFamiliesSet := make(map[string]bool) + capabilityToExtraSignerFamilies := make(map[string][]string) for _, feature := range input.Features.List() { for _, donMetadata := range topology.DonsMetadataWithFlag(feature.Flag()) { testLogger.Info().Msgf("Executing PreEnvStartup for feature %s for don '%s'", feature.Flag(), donMetadata.Name) @@ -209,17 +209,13 @@ func SetupTestEnvironment( } donsCapabilities[donMetadata.ID] = append(donsCapabilities[donMetadata.ID], output.DONCapabilityWithConfig...) maps.Copy(capabilityToOCR3Config, output.CapabilityToOCR3Config) - for _, f := range output.ExtraSignerFamilies { - extraSignerFamiliesSet[f] = true + for capability, families := range output.CapabilityToExtraSignerFamilies { + capabilityToExtraSignerFamilies[capability] = append([]string(nil), families...) } } testLogger.Info().Msgf("PreEnvStartup for feature %s executed successfully", feature.Flag()) } } - extraSignerFamilies := make([]string, 0, len(extraSignerFamiliesSet)) - for f := range extraSignerFamiliesSet { - extraSignerFamilies = append(extraSignerFamilies, f) - } fmt.Print(libformat.PurpleText("%s", input.StageGen.WrapAndNext("Applied Features in %.2f seconds", input.StageGen.Elapsed().Seconds()))) @@ -283,6 +279,36 @@ func SetupTestEnvironment( } fmt.Print(libformat.PurpleText("%s", input.StageGen.WrapAndNext("DONs and Job Distributor started and linked in %.2f seconds", input.StageGen.Elapsed().Seconds()))) + + fmt.Print(libformat.PurpleText("%s", input.StageGen.Wrap("Applying Features after DON startup"))) + for _, feature := range input.Features.List() { + for _, don := range dons.DonsWithFlag(feature.Flag()) { + testLogger.Info().Msgf("Executing PostDONStartup for feature %s for don '%s'", feature.Flag(), don.Name) + output, err := feature.PostDONStartup( + ctx, + testLogger, + don, + dons, + creEnvironment, + ) + if err != nil { + return nil, fmt.Errorf("failed to execute PostDONStartup for feature %s: %w", feature.Flag(), err) + } + if output != nil { + if donsCapabilities[don.ID] == nil { + donsCapabilities[don.ID] = []keystone_changeset.DONCapabilityWithConfig{} + } + donsCapabilities[don.ID] = append(donsCapabilities[don.ID], output.DONCapabilityWithConfig...) + maps.Copy(capabilityToOCR3Config, output.CapabilityToOCR3Config) + for capability, families := range output.CapabilityToExtraSignerFamilies { + capabilityToExtraSignerFamilies[capability] = append([]string(nil), families...) + } + } + testLogger.Info().Msgf("PostDONStartup for feature %s executed successfully", feature.Flag()) + } + } + fmt.Print(libformat.PurpleText("%s", input.StageGen.WrapAndNext("Features applied in %.2f seconds", input.StageGen.Elapsed().Seconds()))) + fmt.Print(libformat.PurpleText("%s", input.StageGen.Wrap("Creating Jobs with Job Distributor"))) gJobErr := gateway.CreateJobs(ctx, creEnvironment, dons, topology.GatewayServiceConfigs, input.GatewayWhitelistConfig) @@ -321,6 +347,7 @@ func SetupTestEnvironment( chainselectors.FamilyEVM: 10000000000000000, // 0.01 ETH chainselectors.FamilySolana: 50_000_000_000, // 50 SOL chainselectors.FamilyTron: 100_000_000, // 100 TRX in SUN + chainselectors.FamilyAptos: 1_000_000_000_000, // 1,000 APT (octas) for local devnet sender accounts } fErr := FundNodes( @@ -337,7 +364,9 @@ func SetupTestEnvironment( fmt.Print(libformat.PurpleText("%s", input.StageGen.Wrap("Configuring Workflow and Capability Registry contracts"))) - // Configure Capabilities Registry first so we can resolve actual contract donIDs + // Configure Capabilities Registry first so we can resolve actual contract DON IDs + // before wiring the workflow registry. Some downstream changesets read DON info + // from CapReg state rather than the pre-contract topology shape. capRegInput := cre.ConfigureCapabilityRegistryInput{ ChainSelector: deployedBlockchains.RegistryChain().ChainSelector(), CldEnv: creEnvironment.CldfEnvironment, @@ -350,11 +379,11 @@ func SetupTestEnvironment( input.ContractVersions[keystone_changeset.CapabilitiesRegistry.String()], ""), ), - NodeSets: input.NodeSets, - WithV2Registries: input.WithV2Registries, - DONCapabilityWithConfigs: make(map[uint64][]keystone_changeset.DONCapabilityWithConfig), - CapabilityToOCR3Config: capabilityToOCR3Config, - ExtraSignerFamilies: extraSignerFamilies, + NodeSets: input.NodeSets, + WithV2Registries: input.WithV2Registries, + DONCapabilityWithConfigs: make(map[uint64][]keystone_changeset.DONCapabilityWithConfig), + CapabilityToOCR3Config: capabilityToOCR3Config, + CapabilityToExtraSignerFamilies: capabilityToExtraSignerFamilies, } for _, capability := range input.Capabilities { @@ -373,7 +402,6 @@ func SetupTestEnvironment( if err := crecontracts.ResolveAndApplyContractDonIDs(capReg, dons, topology, input.NodeSets, input.WithV2Registries); err != nil { return nil, pkgerrors.Wrap(err, "failed to resolve and apply contract donIDs") } - wfRegVersion := input.ContractVersions[keystone_changeset.WorkflowRegistry.String()] workflowRegistryConfigurationOutput, wfErr := workflow.ConfigureWorkflowRegistry( ctx, diff --git a/system-tests/lib/cre/features/aptos/aptos.go b/system-tests/lib/cre/features/aptos/aptos.go new file mode 100644 index 00000000000..53332757d6f --- /dev/null +++ b/system-tests/lib/cre/features/aptos/aptos.go @@ -0,0 +1,1113 @@ +package aptos + +import ( + "bytes" + "context" + "encoding/hex" + stderrors "errors" + "fmt" + "net/url" + "strconv" + "strings" + "text/template" + "time" + + "dario.cat/mergo" + "github.com/Masterminds/semver/v3" + aptossdk "github.com/aptos-labs/aptos-go-sdk" + "github.com/pelletier/go-toml/v2" + pkgerrors "github.com/pkg/errors" + "github.com/rs/zerolog" + "github.com/sethvargo/go-retry" + "google.golang.org/protobuf/types/known/durationpb" + + chainselectors "github.com/smartcontractkit/chain-selectors" + + "github.com/smartcontractkit/chainlink-aptos/bindings/bind" + aptosplatform "github.com/smartcontractkit/chainlink-aptos/bindings/platform" + capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" + "github.com/smartcontractkit/chainlink-deployments-framework/datastore" + kcr "github.com/smartcontractkit/chainlink-evm/gethwrappers/keystone/generated/capabilities_registry_1_1_0" + "github.com/smartcontractkit/chainlink-protos/cre/go/values" + "github.com/smartcontractkit/chainlink-testing-framework/framework" + "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/cre/jobs" + crejobops "github.com/smartcontractkit/chainlink/deployment/cre/jobs/operations" + jobtypes "github.com/smartcontractkit/chainlink/deployment/cre/jobs/types" + "github.com/smartcontractkit/chainlink/deployment/cre/ocr3" + "github.com/smartcontractkit/chainlink/deployment/cre/pkg/offchain" + aptoschangeset "github.com/smartcontractkit/chainlink/deployment/data-feeds/changeset/aptos" + keystone_changeset "github.com/smartcontractkit/chainlink/deployment/keystone/changeset" + "github.com/smartcontractkit/chainlink/system-tests/lib/cre" + crecontracts "github.com/smartcontractkit/chainlink/system-tests/lib/cre/contracts" + credon "github.com/smartcontractkit/chainlink/system-tests/lib/cre/don" + crejobs "github.com/smartcontractkit/chainlink/system-tests/lib/cre/don/jobs" + "github.com/smartcontractkit/chainlink/system-tests/lib/cre/don/jobs/standardcapability" + creblockchains "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains" + aptoschain "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains/aptos" + corechainlink "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" +) + +const ( + flag = cre.WriteAptosCapability + forwarderContractType = "AptosForwarder" + forwarderConfigVersion = 1 + capabilityVersion = "1.0.0" + capabilityLabelPrefix = "aptos:ChainSelector:" + specConfigP2PMapKey = "p2pToTransmitterMap" + specConfigScheduleKey = "transmissionSchedule" + specConfigDeltaStageKey = "deltaStage" + legacyTransmittersKey = "aptosTransmitters" + requestTimeoutKey = "RequestTimeout" + deltaStageKey = "DeltaStage" + transmissionScheduleKey = "TransmissionSchedule" + forwarderQualifier = "" + zeroForwarderHex = "0x0000000000000000000000000000000000000000000000000000000000000000" + aptosConfigTemplate = `{"chainId":"{{.ChainID}}","network":"aptos","creForwarderAddress":"{{.CREForwarderAddress}}"}` + defaultWriteDeltaStage = 500*time.Millisecond + 1*time.Second + defaultRequestTimeout = 30 * time.Second +) + +var forwarderContractVersion = semver.MustParse("1.0.0") + +type Aptos struct{} + +type methodConfigSettings struct { + RequestTimeout time.Duration + DeltaStage time.Duration + TransmissionSchedule capabilitiespb.TransmissionSchedule +} + +func (a *Aptos) Flag() cre.CapabilityFlag { + return flag +} + +func CapabilityLabel(chainSelector uint64) string { + return capabilityLabelPrefix + strconv.FormatUint(chainSelector, 10) +} + +func ForwarderAddress(ds datastore.DataStore, chainSelector uint64) (string, bool) { + key := datastore.NewAddressRefKey( + chainSelector, + datastore.ContractType(forwarderContractType), + forwarderContractVersion, + forwarderQualifier, + ) + ref, err := ds.Addresses().Get(key) + if err != nil { + return "", false + } + return ref.Address, true +} + +func MustForwarderAddress(ds datastore.DataStore, chainSelector uint64) string { + addr, ok := ForwarderAddress(ds, chainSelector) + if !ok { + panic(fmt.Sprintf("missing Aptos forwarder address for chain selector %d", chainSelector)) + } + return addr +} + +func (a *Aptos) PreEnvStartup( + ctx context.Context, + testLogger zerolog.Logger, + don *cre.DonMetadata, + _ *cre.Topology, + creEnv *cre.Environment, +) (*cre.PreEnvStartupOutput, error) { + enabledChainIDs, err := don.MustNodeSet().GetEnabledChainIDsForCapability(flag) + if err != nil { + return nil, fmt.Errorf("could not find enabled chainIDs for '%s' in don '%s': %w", flag, don.Name, err) + } + if len(enabledChainIDs) == 0 { + return nil, nil + } + + forwardersByChainID := make(map[uint64]string, len(enabledChainIDs)) + for _, chainID := range enabledChainIDs { + aptosChain, err := findAptosChainByChainID(creEnv.Blockchains, chainID) + if err != nil { + return nil, err + } + + forwarderAddress, err := ensureForwarder(ctx, testLogger, creEnv, aptosChain) + if err != nil { + return nil, err + } + forwardersByChainID[chainID] = forwarderAddress + } + + if err := patchNodeTOML(don, forwardersByChainID); err != nil { + return nil, err + } + + return &cre.PreEnvStartupOutput{}, nil +} + +func (a *Aptos) PostDONStartup( + ctx context.Context, + testLogger zerolog.Logger, + don *cre.Don, + _ *cre.Dons, + creEnv *cre.Environment, +) (*cre.PostDONStartupOutput, error) { + enabledChainIDs, err := don.GetEnabledChainIDsForCapability(flag) + if err != nil { + return nil, fmt.Errorf("could not find enabled chainIDs for '%s' in don '%s': %w", flag, don.Name, err) + } + if len(enabledChainIDs) == 0 { + return nil, nil + } + + workerNodeIDs, err := workerJDNodeIDs(don) + if err != nil { + return nil, err + } + nodes, err := deployment.NodeInfo(workerNodeIDs, creEnv.CldfEnvironment.Offchain) + if err != nil { + return nil, fmt.Errorf("failed to get Aptos worker node info for DON %q: %w", don.Name, err) + } + + caps := make([]keystone_changeset.DONCapabilityWithConfig, 0, len(enabledChainIDs)) + ocrConfigs := make(map[string]*ocr3.OracleConfig, len(enabledChainIDs)) + capabilityToExtraSignerFamilies := make(map[string][]string, len(enabledChainIDs)) + for _, chainID := range enabledChainIDs { + aptosChain, err := findAptosChainByChainID(creEnv.Blockchains, chainID) + if err != nil { + return nil, err + } + selector := aptosChain.ChainSelector() + labelledName := CapabilityLabel(selector) + + p2pToTransmitterMap, err := p2pToTransmitterMapForChainSelector(nodes, selector) + if err != nil { + return nil, fmt.Errorf("failed to collect Aptos p2p transmitter map for capability %s: %w", labelledName, err) + } + capabilityConfig, err := cre.ResolveCapabilityConfig(don, flag, cre.ChainCapabilityScope(chainID)) + if err != nil { + return nil, fmt.Errorf("could not resolve capability config for '%s' on chain %d: %w", flag, chainID, err) + } + capConfig, err := BuildCapabilityConfig(capabilityConfig.Values, p2pToTransmitterMap, false) + if err != nil { + return nil, fmt.Errorf("failed to build Aptos capability config for capability %s: %w", labelledName, err) + } + + caps = append(caps, keystone_changeset.DONCapabilityWithConfig{ + Capability: kcr.CapabilitiesRegistryCapability{ + LabelledName: labelledName, + Version: capabilityVersion, + CapabilityType: 1, + }, + Config: capConfig, + UseCapRegOCRConfig: true, + }) + ocrConfigs[labelledName] = crecontracts.DefaultChainCapabilityOCR3Config() + capabilityToExtraSignerFamilies[labelledName] = []string{chainselectors.FamilyAptos} + } + + return &cre.PostDONStartupOutput{ + DONCapabilityWithConfig: caps, + CapabilityToOCR3Config: ocrConfigs, + CapabilityToExtraSignerFamilies: capabilityToExtraSignerFamilies, + }, nil +} + +func (a *Aptos) PostEnvStartup( + ctx context.Context, + testLogger zerolog.Logger, + don *cre.Don, + dons *cre.Dons, + creEnv *cre.Environment, +) error { + specs := make(map[string][]string) + + var nodeSet cre.NodeSetWithCapabilityConfigs + for _, ns := range dons.AsNodeSetWithChainCapabilities() { + if ns.GetName() == don.Name { + nodeSet = ns + break + } + } + if nodeSet == nil { + return fmt.Errorf("could not find node set for Don named '%s'", don.Name) + } + + enabledChainIDs, err := nodeSet.GetEnabledChainIDsForCapability(flag) + if err != nil { + return fmt.Errorf("could not find enabled chainIDs for '%s' in don '%s': %w", flag, don.Name, err) + } + if len(enabledChainIDs) == 0 { + return nil + } + + if configureErr := configureForwarders(ctx, testLogger, don, creEnv, enabledChainIDs); configureErr != nil { + return configureErr + } + + bootstrapNode, ok := dons.Bootstrap() + if !ok { + return pkgerrors.New("bootstrap node not found; required for Aptos OCR bootstrap peers") + } + bootstrapPeers := []string{ + fmt.Sprintf("%s@%s:%d", strings.TrimPrefix(bootstrapNode.Keys.PeerID(), "p2p_"), bootstrapNode.Host, cre.OCRPeeringPort), + } + + capRegSemver, ok := creEnv.ContractVersions[keystone_changeset.CapabilitiesRegistry.String()] + if !ok { + return pkgerrors.New("CapabilitiesRegistry version not found in contract versions") + } + capRegVersion := capRegSemver.String() + + for _, chainID := range enabledChainIDs { + aptosChain, err := findAptosChainByChainID(creEnv.Blockchains, chainID) + if err != nil { + return err + } + + capabilityConfig, resolveErr := cre.ResolveCapabilityConfig(nodeSet, flag, cre.ChainCapabilityScope(chainID)) + if resolveErr != nil { + return fmt.Errorf("could not resolve capability config for '%s' on chain %d: %w", flag, chainID, resolveErr) + } + command, cErr := standardcapability.GetCommand(capabilityConfig.BinaryName) + if cErr != nil { + return pkgerrors.Wrap(cErr, "failed to get command for Aptos capability") + } + + tmpl, tmplErr := template.New("aptos-config").Parse(aptosConfigTemplate) + if tmplErr != nil { + return pkgerrors.Wrap(tmplErr, "failed to parse Aptos config template") + } + + forwarderAddress := MustForwarderAddress(creEnv.CldfEnvironment.DataStore, aptosChain.ChainSelector()) + templateData := map[string]string{ + "ChainID": strconv.FormatUint(chainID, 10), + "CREForwarderAddress": forwarderAddress, + } + + var configBuffer bytes.Buffer + if execErr := tmpl.Execute(&configBuffer, templateData); execErr != nil { + return pkgerrors.Wrap(execErr, "failed to execute Aptos config template") + } + + configStr := configBuffer.String() + if validationErr := credon.ValidateTemplateSubstitution(configStr, flag); validationErr != nil { + return fmt.Errorf("aptos template validation failed: %w\nRendered: %s", validationErr, configStr) + } + + workerInput := jobs.ProposeJobSpecInput{ + Domain: offchain.ProductLabel, + Environment: cre.EnvironmentName, + DONName: don.Name, + JobName: "write-aptos-worker-" + strconv.FormatUint(chainID, 10), + ExtraLabels: map[string]string{cre.CapabilityLabelKey: flag}, + DONFilters: []offchain.TargetDONFilter{ + {Key: offchain.FilterKeyDONName, Value: don.Name}, + }, + Template: jobtypes.ReadContract, + Inputs: jobtypes.JobSpecInput{ + "command": command, + "config": configStr, + "chainSelectorEVM": creEnv.RegistryChainSelector, + "chainSelectorAptos": aptosChain.ChainSelector(), + "bootstrapPeers": bootstrapPeers, + "useCapRegOCRConfig": true, + "capRegVersion": capRegVersion, + }, + } + + proposer := jobs.ProposeJobSpec{} + if verifyErr := proposer.VerifyPreconditions(*creEnv.CldfEnvironment, workerInput); verifyErr != nil { + return fmt.Errorf("precondition verification failed for Aptos worker job: %w", verifyErr) + } + workerReport, err := proposer.Apply(*creEnv.CldfEnvironment, workerInput) + if err != nil { + return fmt.Errorf("failed to propose Aptos worker job spec: %w", err) + } + + for _, report := range workerReport.Reports { + out, ok := report.Output.(crejobops.ProposeStandardCapabilityJobOutput) + if !ok { + return fmt.Errorf("unable to cast to ProposeStandardCapabilityJobOutput, actual type: %T", report.Output) + } + if mergeErr := mergo.Merge(&specs, out.Specs, mergo.WithAppendSlice); mergeErr != nil { + return fmt.Errorf("failed to merge Aptos worker job specs: %w", mergeErr) + } + } + } + + if len(specs) == 0 { + return nil + } + if err := crejobs.Approve(ctx, creEnv.CldfEnvironment.Offchain, dons, specs); err != nil { + return fmt.Errorf("failed to approve Aptos jobs: %w", err) + } + return nil +} + +// BuildCapabilityConfig builds the Aptos capability config using the same config +// split as runtime capabilities: method execution policy in MethodConfigs and +// Aptos-specific runtime inputs in SpecConfig. OCR contract config remains +// separate and is only attached through UseCapRegOCRConfig. +func BuildCapabilityConfig(values map[string]any, p2pToTransmitterMap map[string]string, localOnly bool) (*capabilitiespb.CapabilityConfig, error) { + methodSettings, err := resolveMethodConfigSettings(values) + if err != nil { + return nil, err + } + + capConfig := &capabilitiespb.CapabilityConfig{ + MethodConfigs: methodConfigs(methodSettings), + LocalOnly: localOnly, + } + if err := setRuntimeSpecConfig(capConfig, methodSettings, p2pToTransmitterMap); err != nil { + return nil, err + } + return capConfig, nil +} + +func methodConfigs(settings methodConfigSettings) map[string]*capabilitiespb.CapabilityMethodConfig { + return map[string]*capabilitiespb.CapabilityMethodConfig{ + "View": { + RemoteConfig: &capabilitiespb.CapabilityMethodConfig_RemoteExecutableConfig{ + RemoteExecutableConfig: &capabilitiespb.RemoteExecutableConfig{ + TransmissionSchedule: capabilitiespb.TransmissionSchedule_AllAtOnce, + RequestTimeout: durationpb.New(settings.RequestTimeout), + ServerMaxParallelRequests: 10, + RequestHasherType: capabilitiespb.RequestHasherType_Simple, + }, + }, + }, + "WriteReport": { + RemoteConfig: &capabilitiespb.CapabilityMethodConfig_RemoteExecutableConfig{ + RemoteExecutableConfig: &capabilitiespb.RemoteExecutableConfig{ + TransmissionSchedule: settings.TransmissionSchedule, + DeltaStage: durationpb.New(settings.DeltaStage), + RequestTimeout: durationpb.New(settings.RequestTimeout), + ServerMaxParallelRequests: 10, + RequestHasherType: capabilitiespb.RequestHasherType_WriteReportExcludeSignatures, + }, + }, + }, + } +} + +func resolveMethodConfigSettings(values map[string]any) (methodConfigSettings, error) { + settings := methodConfigSettings{ + RequestTimeout: defaultRequestTimeout, + DeltaStage: defaultWriteDeltaStage, + TransmissionSchedule: capabilitiespb.TransmissionSchedule_AllAtOnce, + } + + if values == nil { + return settings, nil + } + + requestTimeout, ok, err := durationValue(values, requestTimeoutKey) + if err != nil { + return methodConfigSettings{}, err + } + if ok { + settings.RequestTimeout = requestTimeout + } + + deltaStage, ok, err := durationValue(values, deltaStageKey) + if err != nil { + return methodConfigSettings{}, err + } + if ok { + settings.DeltaStage = deltaStage + } + + transmissionSchedule, ok, err := transmissionScheduleValue(values, transmissionScheduleKey) + if err != nil { + return methodConfigSettings{}, err + } + if ok { + settings.TransmissionSchedule = transmissionSchedule + } + + return settings, nil +} + +func transmissionScheduleValue(values map[string]any, key string) (capabilitiespb.TransmissionSchedule, bool, error) { + raw, ok := values[key] + if !ok { + return 0, false, nil + } + + schedule, ok := raw.(string) + if !ok { + return 0, false, fmt.Errorf("%s must be a string, got %T", key, raw) + } + + switch strings.TrimSpace(schedule) { + case "allAtOnce": + return capabilitiespb.TransmissionSchedule_AllAtOnce, true, nil + case "oneAtATime": + return capabilitiespb.TransmissionSchedule_OneAtATime, true, nil + default: + return 0, false, fmt.Errorf("%s must be allAtOnce or oneAtATime, got %q", key, schedule) + } +} + +func durationValue(values map[string]any, key string) (time.Duration, bool, error) { + raw, ok := values[key] + if !ok { + return 0, false, nil + } + + switch v := raw.(type) { + case string: + parsed, err := time.ParseDuration(strings.TrimSpace(v)) + if err != nil { + return 0, false, fmt.Errorf("%s must be a valid duration string: %w", key, err) + } + return parsed, true, nil + case time.Duration: + return v, true, nil + default: + return 0, false, fmt.Errorf("%s must be a duration string, got %T", key, raw) + } +} + +func patchNodeTOML(don *cre.DonMetadata, forwardersByChainID map[uint64]string) error { + for nodeIndex := range don.MustNodeSet().NodeSpecs { + currentConfig := don.MustNodeSet().NodeSpecs[nodeIndex].Node.TestConfigOverrides + if strings.TrimSpace(currentConfig) == "" { + return fmt.Errorf("missing node config for node index %d in DON %q", nodeIndex, don.Name) + } + + var typedConfig corechainlink.Config + if err := toml.Unmarshal([]byte(currentConfig), &typedConfig); err != nil { + return fmt.Errorf("failed to unmarshal config for node index %d: %w", nodeIndex, err) + } + + for chainID, forwarderAddress := range forwardersByChainID { + if err := setForwarderAddress(&typedConfig, strconv.FormatUint(chainID, 10), forwarderAddress); err != nil { + return fmt.Errorf("failed to patch Aptos forwarder address for node index %d: %w", nodeIndex, err) + } + } + + stringifiedConfig, err := toml.Marshal(typedConfig) + if err != nil { + return fmt.Errorf("failed to marshal patched config for node index %d: %w", nodeIndex, err) + } + don.MustNodeSet().NodeSpecs[nodeIndex].Node.TestConfigOverrides = string(stringifiedConfig) + } + + return nil +} + +func setForwarderAddress(cfg *corechainlink.Config, chainID, forwarderAddress string) error { + for i := range cfg.Aptos { + raw := map[string]any(cfg.Aptos[i]) + if fmt.Sprint(raw["ChainID"]) != chainID { + continue + } + + workflow := make(map[string]any) + switch existing := raw["Workflow"].(type) { + case map[string]any: + for k, v := range existing { + workflow[k] = v + } + case corechainlink.RawConfig: + for k, v := range existing { + workflow[k] = v + } + case nil: + default: + return fmt.Errorf("unexpected Aptos workflow config type %T", existing) + } + workflow["ForwarderAddress"] = forwarderAddress + raw["Workflow"] = workflow + cfg.Aptos[i] = corechainlink.RawConfig(raw) + return nil + } + + return fmt.Errorf("Aptos chain %s not found in node config", chainID) +} + +func ensureForwarder( + ctx context.Context, + testLogger zerolog.Logger, + creEnv *cre.Environment, + chain *aptoschain.Blockchain, +) (string, error) { + if addr, ok := ForwarderAddress(creEnv.CldfEnvironment.DataStore, chain.ChainSelector()); ok { + return addr, nil + } + if !creEnv.Provider.IsDocker() { + return "", fmt.Errorf("missing Aptos forwarder address for chain selector %d", chain.ChainSelector()) + } + + nodeURL, err := chain.NodeURL() + if err != nil { + return "", fmt.Errorf("invalid Aptos node URL for chain selector %d: %w", chain.ChainSelector(), err) + } + client, err := chain.NodeClient() + if err != nil { + return "", fmt.Errorf("failed to create Aptos client for chain selector %d (%s): %w", chain.ChainSelector(), nodeURL, err) + } + deployerAccount, err := chain.LocalDeployerAccount() + if err != nil { + return "", fmt.Errorf("failed to create Aptos deployer signer: %w", err) + } + deploymentChain, err := chain.LocalDeploymentChain() + if err != nil { + return "", fmt.Errorf("failed to build Aptos deployment chain for chain selector %d: %w", chain.ChainSelector(), err) + } + + owner := deployerAccount.AccountAddress() + containerName := "" + if output := chain.CtfOutput(); output != nil { + containerName = output.ContainerName + } + if ensureErr := ensureAccountVisible(ctx, testLogger, client, nodeURL, owner, chain.ChainSelector(), containerName); ensureErr != nil { + testLogger.Warn(). + Uint64("chainSelector", chain.ChainSelector()). + Str("nodeURL", nodeURL). + Err(ensureErr). + Msg("Aptos deployer account not confirmed visible yet; proceeding with deploy retries") + } + + var deployedAddress string + var pendingTxHash string + var lastDeployErr error + if retryErr := retry.Do(ctx, retry.WithMaxDuration(3*time.Minute, retry.NewFibonacci(500*time.Millisecond)), func(ctx context.Context) error { + deploymentResp, deployErr := aptoschangeset.DeployPlatform(deploymentChain, owner, nil) + if deployErr != nil { + lastDeployErr = deployErr + if fundErr := chain.Fund(ctx, owner.StringLong(), 1_000_000_000_000); fundErr != nil { + testLogger.Warn(). + Uint64("chainSelector", chain.ChainSelector()). + Err(fundErr). + Msg("failed to re-fund Aptos deployer account during deploy retry") + } + return retry.RetryableError(fmt.Errorf("deploy-to-object failed: %w", deployErr)) + } + if deploymentResp == nil { + lastDeployErr = pkgerrors.New("nil deployment response") + return retry.RetryableError(pkgerrors.New("DeployPlatform returned nil response")) + } + deployedAddress = deploymentResp.Address.StringLong() + pendingTxHash = deploymentResp.Tx + return nil + }); retryErr != nil { + if lastDeployErr != nil { + return "", fmt.Errorf("failed to deploy Aptos platform forwarder for chain selector %d after retries: %w", chain.ChainSelector(), stderrors.Join(lastDeployErr, retryErr)) + } + return "", fmt.Errorf("failed to deploy Aptos platform forwarder for chain selector %d after retries: %w", chain.ChainSelector(), retryErr) + } + + addr, err := normalizeForwarderAddress(deployedAddress) + if err != nil { + return "", fmt.Errorf("invalid Aptos forwarder address parsed from deployment output for chain selector %d: %w", chain.ChainSelector(), err) + } + + if err := addForwarderToDataStore(creEnv, chain.ChainSelector(), addr); err != nil { + return "", err + } + + testLogger.Info(). + Uint64("chainSelector", chain.ChainSelector()). + Str("nodeURL", nodeURL). + Str("txHash", pendingTxHash). + Str("forwarderAddress", addr). + Msg("Aptos platform forwarder deployed") + + return addr, nil +} + +func addForwarderToDataStore(creEnv *cre.Environment, chainSelector uint64, address string) error { + memoryDatastore, err := crecontracts.NewDataStoreFromExisting(creEnv.CldfEnvironment.DataStore) + if err != nil { + return fmt.Errorf("failed to create memory datastore: %w", err) + } + + err = memoryDatastore.AddressRefStore.Add(datastore.AddressRef{ + Address: address, + ChainSelector: chainSelector, + Type: datastore.ContractType(forwarderContractType), + Version: forwarderContractVersion, + Qualifier: forwarderQualifier, + }) + if err != nil && !stderrors.Is(err, datastore.ErrAddressRefExists) { + return fmt.Errorf("failed to add Aptos forwarder address to datastore: %w", err) + } + + creEnv.CldfEnvironment.DataStore = memoryDatastore.Seal() + return nil +} + +func configureForwarders( + ctx context.Context, + testLogger zerolog.Logger, + don *cre.Don, + creEnv *cre.Environment, + chainIDs []uint64, +) error { + workers, err := don.Workers() + if err != nil { + return fmt.Errorf("failed to get worker nodes for DON %q: %w", don.Name, err) + } + f := (len(workers) - 1) / 3 + if f <= 0 { + return fmt.Errorf("invalid Aptos DON %q fault tolerance F=%d (workers=%d)", don.Name, f, len(workers)) + } + if f > 255 { + return fmt.Errorf("aptos DON %q fault tolerance F=%d exceeds u8", don.Name, f) + } + + donIDUint32, err := aptosDonIDUint32(don.ID) + if err != nil { + return fmt.Errorf("invalid DON id for Aptos forwarder config: %w", err) + } + + oracles, err := donOraclePublicKeys(ctx, don) + if err != nil { + return err + } + + for _, chainID := range chainIDs { + aptosChain, err := findAptosChainByChainID(creEnv.Blockchains, chainID) + if err != nil { + return err + } + + nodeURL, err := aptosChain.NodeURL() + if err != nil { + return fmt.Errorf("invalid Aptos node URL for chain selector %d: %w", aptosChain.ChainSelector(), err) + } + client, err := aptosChain.NodeClient() + if err != nil { + return fmt.Errorf("failed to create Aptos client for chain selector %d (%s): %w", aptosChain.ChainSelector(), nodeURL, err) + } + deployerAccount, err := aptosChain.LocalDeployerAccount() + if err != nil { + return fmt.Errorf("failed to create Aptos deployer signer for forwarder config: %w", err) + } + deployerAddress := deployerAccount.AccountAddress() + + containerName := "" + if output := aptosChain.CtfOutput(); output != nil { + containerName = output.ContainerName + } + + if err := ensureAccountVisible(ctx, testLogger, client, nodeURL, deployerAddress, aptosChain.ChainSelector(), containerName); err != nil { + testLogger.Warn(). + Uint64("chainSelector", aptosChain.ChainSelector()). + Str("nodeURL", nodeURL). + Err(err). + Msg("Aptos deployer account not confirmed visible yet; proceeding with forwarder set_config retries") + } + + forwarderHex := MustForwarderAddress(creEnv.CldfEnvironment.DataStore, aptosChain.ChainSelector()) + var forwarderAddr aptossdk.AccountAddress + if err := forwarderAddr.ParseStringRelaxed(forwarderHex); err != nil { + return fmt.Errorf("invalid Aptos forwarder address for chain selector %d: %w", aptosChain.ChainSelector(), err) + } + forwarderContract := aptosplatform.Bind(forwarderAddr, client).Forwarder() + + var pendingTxHash string + var lastSetConfigErr error + if err := retry.Do(ctx, retry.WithMaxDuration(2*time.Minute, retry.NewFibonacci(500*time.Millisecond)), func(ctx context.Context) error { + pendingTx, err := forwarderContract.SetConfig(&bind.TransactOpts{Signer: deployerAccount}, donIDUint32, forwarderConfigVersion, byte(f), oracles) + if err != nil { + lastSetConfigErr = err + if fundErr := aptosChain.Fund(ctx, deployerAddress.StringLong(), 1_000_000_000_000); fundErr != nil { + testLogger.Warn(). + Uint64("chainSelector", aptosChain.ChainSelector()). + Err(fundErr). + Msg("failed to fund Aptos deployer account during set_config retry") + } + return retry.RetryableError(fmt.Errorf("set_config transaction submit failed: %w", err)) + } + pendingTxHash = pendingTx.Hash + receipt, err := client.WaitForTransaction(pendingTxHash) + if err != nil { + lastSetConfigErr = err + return retry.RetryableError(fmt.Errorf("waiting for set_config transaction failed: %w", err)) + } + if !receipt.Success { + lastSetConfigErr = fmt.Errorf("vm status: %s", receipt.VmStatus) + return retry.RetryableError(fmt.Errorf("set_config transaction failed: %s", receipt.VmStatus)) + } + return nil + }); err != nil { + if lastSetConfigErr != nil { + return fmt.Errorf("failed to configure Aptos forwarder %s for DON %q on chain selector %d: %w", forwarderHex, don.Name, aptosChain.ChainSelector(), stderrors.Join(lastSetConfigErr, err)) + } + return fmt.Errorf("failed to configure Aptos forwarder %s for DON %q on chain selector %d: %w", forwarderHex, don.Name, aptosChain.ChainSelector(), err) + } + + testLogger.Info(). + Str("donName", don.Name). + Uint64("donID", don.ID). + Uint64("chainSelector", aptosChain.ChainSelector()). + Str("txHash", pendingTxHash). + Str("forwarderAddress", forwarderHex). + Msg("configured Aptos forwarder set_config") + } + + return nil +} + +func donOraclePublicKeys(ctx context.Context, don *cre.Don) ([][]byte, error) { + workers, err := don.Workers() + if err != nil { + return nil, fmt.Errorf("failed to list worker nodes for DON %q: %w", don.Name, err) + } + + oracles := make([][]byte, 0, len(workers)) + for _, worker := range workers { + ocr2ID := "" + if worker.Keys != nil && worker.Keys.OCR2BundleIDs != nil { + ocr2ID = worker.Keys.OCR2BundleIDs[chainselectors.FamilyAptos] + } + if ocr2ID == "" { + fetchedID, err := worker.Clients.GQLClient.FetchOCR2KeyBundleID(ctx, strings.ToUpper(chainselectors.FamilyAptos)) + if err != nil { + return nil, fmt.Errorf("missing Aptos OCR2 bundle id for worker %q in DON %q and fallback fetch failed: %w", worker.Name, don.Name, err) + } + if fetchedID == "" { + return nil, fmt.Errorf("missing Aptos OCR2 bundle id for worker %q in DON %q", worker.Name, don.Name) + } + ocr2ID = fetchedID + if worker.Keys != nil { + if worker.Keys.OCR2BundleIDs == nil { + worker.Keys.OCR2BundleIDs = make(map[string]string) + } + worker.Keys.OCR2BundleIDs[chainselectors.FamilyAptos] = ocr2ID + } + } + + exported, err := worker.ExportOCR2Keys(ocr2ID) + if err != nil { + return nil, fmt.Errorf("failed to export Aptos OCR2 key for worker %q (bundle %s): %w", worker.Name, ocr2ID, err) + } + pubkey, err := parseOCR2OnchainPublicKey(exported.OnchainPublicKey) + if err != nil { + return nil, fmt.Errorf("invalid Aptos OCR2 onchain public key for worker %q: %w", worker.Name, err) + } + oracles = append(oracles, pubkey) + } + + return oracles, nil +} + +func workerJDNodeIDs(don *cre.Don) ([]string, error) { + workers, err := don.Workers() + if err != nil { + return nil, err + } + + nodeIDs := make([]string, 0, len(workers)) + for _, worker := range workers { + if worker.JobDistributorDetails.NodeID == "" { + return nil, fmt.Errorf("missing Job Distributor node id for worker %q in DON %q", worker.Name, don.Name) + } + nodeIDs = append(nodeIDs, worker.JobDistributorDetails.NodeID) + } + + return nodeIDs, nil +} + +func p2pToTransmitterMapForChainSelector(nodes deployment.Nodes, chainSelector uint64) (map[string]string, error) { + if len(nodes) == 0 { + return nil, pkgerrors.New("no DON worker nodes provided") + } + + p2pToTransmitterMap := make(map[string]string) + for _, node := range nodes { + ocrCfg, ok := node.OCRConfigForChainSelector(chainSelector) + if !ok { + continue + } + + transmitter, err := normalizeTransmitter(string(ocrCfg.TransmitAccount)) + if err != nil { + return nil, fmt.Errorf("invalid Aptos transmitter for node %s: %w", node.Name, err) + } + + peerKey := hex.EncodeToString(node.PeerID[:]) + p2pToTransmitterMap[peerKey] = transmitter + } + + if len(p2pToTransmitterMap) == 0 { + return nil, fmt.Errorf("no Aptos OCR config/transmitters found for chain selector %d", chainSelector) + } + + return p2pToTransmitterMap, nil +} + +func setRuntimeSpecConfig(capConfig *capabilitiespb.CapabilityConfig, settings methodConfigSettings, p2pToTransmitterMap map[string]string) error { + if capConfig == nil { + return pkgerrors.New("capability config is nil") + } + + specConfig, err := values.FromMapValueProto(capConfig.SpecConfig) + if err != nil { + return fmt.Errorf("failed to decode existing spec config: %w", err) + } + if specConfig == nil { + specConfig = values.EmptyMap() + } + + delete(specConfig.Underlying, legacyTransmittersKey) + + scheduleValue, err := values.Wrap(remoteTransmissionScheduleString(settings.TransmissionSchedule)) + if err != nil { + return fmt.Errorf("failed to wrap transmission schedule: %w", err) + } + specConfig.Underlying[specConfigScheduleKey] = scheduleValue + + deltaStageValue, err := values.Wrap(settings.DeltaStage) + if err != nil { + return fmt.Errorf("failed to wrap delta stage: %w", err) + } + specConfig.Underlying[specConfigDeltaStageKey] = deltaStageValue + + if len(p2pToTransmitterMap) > 0 { + mapValue, err := values.Wrap(p2pToTransmitterMap) + if err != nil { + return fmt.Errorf("failed to wrap p2p transmitter map: %w", err) + } + specConfig.Underlying[specConfigP2PMapKey] = mapValue + } + + capConfig.SpecConfig = values.ProtoMap(specConfig) + return nil +} + +func remoteTransmissionScheduleString(schedule capabilitiespb.TransmissionSchedule) string { + switch schedule { + case capabilitiespb.TransmissionSchedule_OneAtATime: + return "oneAtATime" + default: + return "allAtOnce" + } +} + +func normalizeTransmitter(raw string) (string, error) { + s := strings.TrimSpace(raw) + if s == "" { + return "", pkgerrors.New("empty Aptos transmitter") + } + + var addr aptossdk.AccountAddress + if err := addr.ParseStringRelaxed(s); err != nil { + return "", err + } + return addr.StringLong(), nil +} + +func normalizeForwarderAddress(raw string) (string, error) { + var addr aptossdk.AccountAddress + if err := addr.ParseStringRelaxed(strings.TrimSpace(raw)); err != nil { + return "", err + } + return addr.StringLong(), nil +} + +func findAptosChainByChainID(chains []creblockchains.Blockchain, chainID uint64) (*aptoschain.Blockchain, error) { + for _, bc := range chains { + if bc.IsFamily(chainselectors.FamilyAptos) && bc.ChainID() == chainID { + aptosBlockchain, ok := bc.(*aptoschain.Blockchain) + if !ok { + return nil, fmt.Errorf("Aptos blockchain for chain id %d has unexpected type %T", chainID, bc) + } + return aptosBlockchain, nil + } + } + return nil, fmt.Errorf("Aptos blockchain for chain id %d not found", chainID) +} + +func normalizeNodeURL(rawURL string) (string, error) { + u, err := url.Parse(rawURL) + if err != nil { + return "", err + } + if u.Scheme == "" || u.Host == "" { + return "", fmt.Errorf("aptos node URL %q must include scheme and host", rawURL) + } + path := strings.TrimRight(u.Path, "/") + if path == "" || path != "/v1" { + u.Path = "/v1" + } + return u.String(), nil +} + +func NormalizeNodeURL(rawURL string) (string, error) { + return normalizeNodeURL(rawURL) +} + +func faucetURLFromNodeURL(nodeURL string) (string, error) { + parsed, err := url.Parse(nodeURL) + if err != nil { + return "", err + } + host := parsed.Hostname() + if host == "" { + return "", fmt.Errorf("aptos node URL %q has empty host", nodeURL) + } + parsed.Host = fmt.Sprintf("%s:%s", host, blockchain.DefaultAptosFaucetPort) + parsed.Path = "" + parsed.RawPath = "" + parsed.RawQuery = "" + parsed.Fragment = "" + return parsed.String(), nil +} + +func FaucetURLFromNodeURL(nodeURL string) (string, error) { + return faucetURLFromNodeURL(nodeURL) +} + +func aptosChainIDUint8(chainID uint64) (uint8, error) { + if chainID > 255 { + return 0, fmt.Errorf("aptos chain id %d does not fit in uint8", chainID) + } + return uint8(chainID), nil +} + +func ChainIDUint8(chainID uint64) (uint8, error) { + return aptosChainIDUint8(chainID) +} + +func aptosDonIDUint32(donID uint64) (uint32, error) { + if donID > uint64(^uint32(0)) { + return 0, fmt.Errorf("don id %d exceeds u32", donID) + } + return uint32(donID), nil +} + +func ensureAccountVisible( + ctx context.Context, + testLogger zerolog.Logger, + client *aptossdk.NodeClient, + nodeURL string, + address aptossdk.AccountAddress, + chainSelector uint64, + containerName string, +) error { + if err := FundAccountBestEffort(ctx, testLogger, client, nodeURL, containerName, address, 0, 100_000_000); err == nil { + return nil + } + + testLogger.Warn(). + Uint64("chainSelector", chainSelector). + Str("nodeURL", nodeURL). + Str("account", address.StringLong()). + Msg("Aptos account not confirmed visible after funding attempts") + return fmt.Errorf("aptos account %s not visible yet on %s", address.StringLong(), nodeURL) +} + +func waitForAccountVisible(ctx context.Context, client *aptossdk.NodeClient, address aptossdk.AccountAddress) error { + var lastErr error + err := retry.Do(ctx, retry.WithMaxDuration(20*time.Second, retry.NewFibonacci(250*time.Millisecond)), func(context.Context) error { + if _, err := client.Account(address); err != nil { + lastErr = err + return retry.RetryableError(err) + } + return nil + }) + if err != nil { + if lastErr != nil { + return lastErr + } + return err + } + return nil +} + +func WaitForAccountVisible(ctx context.Context, client *aptossdk.NodeClient, address aptossdk.AccountAddress, timeout time.Duration) error { + waitCtx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + return waitForAccountVisible(waitCtx, client, address) +} + +func fundAccountInContainer(ctx context.Context, containerName, address string, amount uint64) error { + dc, err := framework.NewDockerClient() + if err != nil { + return fmt.Errorf("failed to create docker client: %w", err) + } + cmd := []string{ + "aptos", "account", "fund-with-faucet", + "--account", address, + "--amount", strconv.FormatUint(amount, 10), + } + if _, err = dc.ExecContainerWithContext(ctx, containerName, cmd); err != nil { + return fmt.Errorf("failed to execute aptos faucet funding command in container %s: %w", containerName, err) + } + return nil +} + +func FundAccountInContainer(ctx context.Context, containerName, address string, amount uint64) error { + return fundAccountInContainer(ctx, containerName, address, amount) +} + +func FundAccountBestEffort( + ctx context.Context, + testLogger zerolog.Logger, + client *aptossdk.NodeClient, + nodeURL string, + containerName string, + address aptossdk.AccountAddress, + minBalance uint64, + fundingAmount uint64, +) error { + if _, err := client.Account(address); err == nil { + if minBalance == 0 { + return nil + } + if balance, balErr := client.AccountAPTBalance(address); balErr == nil && balance >= minBalance { + return nil + } + } + + if faucetURL, err := faucetURLFromNodeURL(nodeURL); err == nil { + if faucetClient, err := aptossdk.NewFaucetClient(client, faucetURL); err == nil { + if fundErr := faucetClient.Fund(address, fundingAmount); fundErr != nil { + testLogger.Warn(). + Err(fundErr). + Str("faucet_url", faucetURL). + Str("account", address.StringLong()). + Msg("Aptos host faucet funding failed") + } else if waitErr := WaitForAccountVisible(ctx, client, address, 8*time.Second); waitErr == nil { + return nil + } + } + } + + if strings.TrimSpace(containerName) == "" { + return fmt.Errorf("aptos account %s not visible after host funding attempts", address.StringLong()) + } + if err := fundAccountInContainer(ctx, containerName, address.StringLong(), fundingAmount); err != nil { + return err + } + return WaitForAccountVisible(ctx, client, address, 8*time.Second) +} + +func WaitForTransactionSuccess(client *aptossdk.NodeClient, txHash, label string) error { + tx, err := client.WaitForTransaction(txHash) + if err != nil { + return fmt.Errorf("failed waiting for Aptos tx %s: %w", label, err) + } + if !tx.Success { + return fmt.Errorf("aptos tx failed: %s vm_status=%s", label, tx.VmStatus) + } + return nil +} + +func parseOCR2OnchainPublicKey(hexValue string) ([]byte, error) { + trimmed := strings.TrimPrefix(strings.TrimSpace(hexValue), "ocr2on_aptos_") + decoded, err := hex.DecodeString(trimmed) + if err != nil { + return nil, err + } + return decoded, nil +} + +var ( + _ cre.Feature = (*Aptos)(nil) +) diff --git a/system-tests/lib/cre/features/aptos/aptos_test.go b/system-tests/lib/cre/features/aptos/aptos_test.go new file mode 100644 index 00000000000..42568360ddb --- /dev/null +++ b/system-tests/lib/cre/features/aptos/aptos_test.go @@ -0,0 +1,251 @@ +package aptos + +import ( + "encoding/hex" + "math/big" + "testing" + "time" + + "github.com/stretchr/testify/require" + + chainselectors "github.com/smartcontractkit/chain-selectors" + + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/p2pkey" + capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" + "github.com/smartcontractkit/chainlink-protos/cre/go/values" + "github.com/smartcontractkit/chainlink/deployment" +) + +func TestSetRuntimeSpecConfig_ReplacesLegacyKey(t *testing.T) { + specConfig := values.EmptyMap() + legacy, err := values.Wrap([]string{"0x1"}) + require.NoError(t, err) + specConfig.Underlying[legacyTransmittersKey] = legacy + + capConfig := &capabilitiespb.CapabilityConfig{ + SpecConfig: values.ProtoMap(specConfig), + } + + expectedMap := map[string]string{ + "peer-a": "0x000000000000000000000000000000000000000000000000000000000000000a", + } + require.NoError(t, setRuntimeSpecConfig(capConfig, methodConfigSettings{ + TransmissionSchedule: capabilitiespb.TransmissionSchedule_AllAtOnce, + DeltaStage: 1500 * time.Millisecond, + }, expectedMap)) + + decoded, err := values.FromMapValueProto(capConfig.SpecConfig) + require.NoError(t, err) + require.NotNil(t, decoded) + require.NotContains(t, decoded.Underlying, legacyTransmittersKey) + + rawSchedule, ok := decoded.Underlying[specConfigScheduleKey] + require.True(t, ok) + schedule, err := rawSchedule.Unwrap() + require.NoError(t, err) + require.Equal(t, "allAtOnce", schedule) + + rawDeltaStage, ok := decoded.Underlying[specConfigDeltaStageKey] + require.True(t, ok) + deltaStage, err := rawDeltaStage.Unwrap() + require.NoError(t, err) + require.EqualValues(t, 1500*time.Millisecond, deltaStage) + + rawMap, ok := decoded.Underlying[specConfigP2PMapKey] + require.True(t, ok) + unwrapped, err := rawMap.Unwrap() + require.NoError(t, err) + require.Equal(t, map[string]any{ + "peer-a": "0x000000000000000000000000000000000000000000000000000000000000000a", + }, unwrapped) +} + +func TestBuildCapabilityConfig_UsesMethodConfigsAndSpecConfig(t *testing.T) { + capConfig, err := BuildCapabilityConfig( + map[string]any{ + requestTimeoutKey: "45s", + deltaStageKey: "2500ms", + }, + map[string]string{ + "peer-a": "0x000000000000000000000000000000000000000000000000000000000000000a", + }, + false, + ) + require.NoError(t, err) + require.False(t, capConfig.LocalOnly) + require.Nil(t, capConfig.Ocr3Configs) + require.Contains(t, capConfig.MethodConfigs, "View") + require.Contains(t, capConfig.MethodConfigs, "WriteReport") + + writeCfg := capConfig.MethodConfigs["WriteReport"].GetRemoteExecutableConfig() + require.NotNil(t, writeCfg) + require.Equal(t, capabilitiespb.TransmissionSchedule_AllAtOnce, writeCfg.TransmissionSchedule) + require.Equal(t, 2500*time.Millisecond, writeCfg.DeltaStage.AsDuration()) + require.Equal(t, 45*time.Second, writeCfg.RequestTimeout.AsDuration()) + + specConfig, err := values.FromMapValueProto(capConfig.SpecConfig) + require.NoError(t, err) + require.NotNil(t, specConfig) + + rawSchedule, ok := specConfig.Underlying[specConfigScheduleKey] + require.True(t, ok) + schedule, err := rawSchedule.Unwrap() + require.NoError(t, err) + require.Equal(t, "allAtOnce", schedule) + + rawDeltaStage, ok := specConfig.Underlying[specConfigDeltaStageKey] + require.True(t, ok) + deltaStage, err := rawDeltaStage.Unwrap() + require.NoError(t, err) + require.EqualValues(t, 2500*time.Millisecond, deltaStage) + + rawMap, ok := specConfig.Underlying[specConfigP2PMapKey] + require.True(t, ok) + unwrapped, err := rawMap.Unwrap() + require.NoError(t, err) + require.Equal(t, map[string]any{ + "peer-a": "0x000000000000000000000000000000000000000000000000000000000000000a", + }, unwrapped) +} + +func TestBuildCapabilityConfig_WithoutP2PMap_StillSetsRuntimeSpecConfig(t *testing.T) { + capConfig, err := BuildCapabilityConfig(nil, nil, true) + require.NoError(t, err) + require.True(t, capConfig.LocalOnly) + require.Nil(t, capConfig.Ocr3Configs) + require.Contains(t, capConfig.MethodConfigs, "View") + require.Contains(t, capConfig.MethodConfigs, "WriteReport") + + specConfig, err := values.FromMapValueProto(capConfig.SpecConfig) + require.NoError(t, err) + require.NotNil(t, specConfig) + require.NotContains(t, specConfig.Underlying, specConfigP2PMapKey) + require.Contains(t, specConfig.Underlying, specConfigScheduleKey) + require.Contains(t, specConfig.Underlying, specConfigDeltaStageKey) +} + +func TestNormalizeTransmitter(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "short address is normalized", + input: "0xa", + want: "0x000000000000000000000000000000000000000000000000000000000000000a", + }, + { + name: "whitespace is trimmed", + input: " 0xB ", + want: "0x000000000000000000000000000000000000000000000000000000000000000b", + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got, err := normalizeTransmitter(tc.input) + require.NoError(t, err) + require.Equal(t, tc.want, got) + }) + } + + _, err := normalizeTransmitter("not-an-address") + require.Error(t, err) +} + +func TestP2PToTransmitterMapForChainSelector(t *testing.T) { + selector := uint64(4457093679053095497) + chainDetails, err := chainselectors.GetChainDetails(selector) + require.NoError(t, err) + + key := p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)) + transmitAccount := ocrtypes.Account("0xa") + + nodes := deployment.Nodes{ + { + Name: "node-1", + PeerID: key.PeerID(), + SelToOCRConfig: map[chainselectors.ChainDetails]deployment.OCRConfig{ + chainDetails: { + PeerID: key.PeerID(), + TransmitAccount: transmitAccount, + }, + }, + }, + } + + got, err := p2pToTransmitterMapForChainSelector(nodes, selector) + require.NoError(t, err) + + peerID := key.PeerID() + expectedPeerKey := hex.EncodeToString(peerID[:]) + require.Equal(t, map[string]string{ + expectedPeerKey: "0x000000000000000000000000000000000000000000000000000000000000000a", + }, got) +} + +func TestNormalizeNodeURL(t *testing.T) { + t.Run("adds v1 when path is empty", func(t *testing.T) { + got, err := NormalizeNodeURL("http://127.0.0.1:8080") + require.NoError(t, err) + require.Equal(t, "http://127.0.0.1:8080/v1", got) + }) + + t.Run("preserves v1 path", func(t *testing.T) { + got, err := NormalizeNodeURL("http://127.0.0.1:8080/v1") + require.NoError(t, err) + require.Equal(t, "http://127.0.0.1:8080/v1", got) + }) +} + +func TestFaucetURLFromNodeURL(t *testing.T) { + got, err := FaucetURLFromNodeURL("http://127.0.0.1:8080/v1") + require.NoError(t, err) + require.Equal(t, "http://127.0.0.1:8081", got) +} + +func TestChainIDUint8(t *testing.T) { + got, err := ChainIDUint8(4) + require.NoError(t, err) + require.Equal(t, uint8(4), got) + + _, err = ChainIDUint8(256) + require.Error(t, err) +} + +func TestResolveMethodConfigSettings_Defaults(t *testing.T) { + settings, err := resolveMethodConfigSettings(nil) + require.NoError(t, err) + require.Equal(t, defaultRequestTimeout, settings.RequestTimeout) + require.Equal(t, defaultWriteDeltaStage, settings.DeltaStage) + require.Equal(t, capabilitiespb.TransmissionSchedule_AllAtOnce, settings.TransmissionSchedule) +} + +func TestResolveMethodConfigSettings_Overrides(t *testing.T) { + settings, err := resolveMethodConfigSettings(map[string]any{ + requestTimeoutKey: "45s", + deltaStageKey: "2500ms", + transmissionScheduleKey: "oneAtATime", + }) + require.NoError(t, err) + require.Equal(t, 45*time.Second, settings.RequestTimeout) + require.Equal(t, 2500*time.Millisecond, settings.DeltaStage) + require.Equal(t, capabilitiespb.TransmissionSchedule_OneAtATime, settings.TransmissionSchedule) +} + +func TestResolveMethodConfigSettings_InvalidDuration(t *testing.T) { + _, err := resolveMethodConfigSettings(map[string]any{ + requestTimeoutKey: "not-a-duration", + }) + require.Error(t, err) +} + +func TestResolveMethodConfigSettings_InvalidTransmissionSchedule(t *testing.T) { + _, err := resolveMethodConfigSettings(map[string]any{ + transmissionScheduleKey: "staggered", + }) + require.Error(t, err) +} diff --git a/system-tests/lib/cre/features/consensus/v1/consensus.go b/system-tests/lib/cre/features/consensus/v1/consensus.go index 27111084a9f..ecd60137194 100644 --- a/system-tests/lib/cre/features/consensus/v1/consensus.go +++ b/system-tests/lib/cre/features/consensus/v1/consensus.go @@ -31,7 +31,7 @@ import ( const flag = cre.ConsensusCapability -type Consensus struct{} +type Consensus struct{ cre.NoopPostDONStartup } func (c *Consensus) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/consensus/v2/consensus.go b/system-tests/lib/cre/features/consensus/v2/consensus.go index ee1ca7e5e6f..a74f034f390 100644 --- a/system-tests/lib/cre/features/consensus/v2/consensus.go +++ b/system-tests/lib/cre/features/consensus/v2/consensus.go @@ -34,7 +34,7 @@ import ( const flag = cre.ConsensusCapabilityV2 const consensusLabelledName = "consensus" -type Consensus struct{} +type Consensus struct{ cre.NoopPostDONStartup } func (c *Consensus) Flag() cre.CapabilityFlag { return flag @@ -65,6 +65,10 @@ func (c *Consensus) PreEnvStartup( CapabilityToOCR3Config: map[string]*ocr3.OracleConfig{ consensusLabelledName: contracts.DefaultOCR3Config(), }, + CapabilityToExtraSignerFamilies: cre.CapabilityToExtraSignerFamilies( + cre.NonEVMOCRSignerFamilies(creEnv.Blockchains), + consensusLabelledName, + ), }, nil } @@ -221,8 +225,13 @@ func proposeNodeJob(creEnv *cre.Environment, don *cre.Don, command string, boots inputs["config"] = configStr } - // Add Solana chain selector if present + // Add non-EVM OCR selectors when present so consensus can select the correct + // offchain key bundle path for report generation. for _, blockchain := range creEnv.Blockchains { + if blockchain.IsFamily(chainselectors.FamilyAptos) { + inputs["chainSelectorAptos"] = blockchain.ChainSelector() + continue + } if blockchain.IsFamily(chainselectors.FamilySolana) { inputs["chainSelectorSolana"] = blockchain.ChainSelector() break @@ -249,6 +258,12 @@ func proposeNodeJob(creEnv *cre.Environment, don *cre.Don, command string, boots report, applyErr := proposer.Apply(*creEnv.CldfEnvironment, input) if applyErr != nil { + if strings.Contains(applyErr.Error(), "no aptos ocr2 config for node") { + return nil, fmt.Errorf( + "failed to propose Consensus v2 node job spec: %w; Aptos workflows require Aptos OCR2 key bundles on all workflow DON nodes", + applyErr, + ) + } return nil, fmt.Errorf("failed to propose Consensus v2 node job spec: %w", applyErr) } diff --git a/system-tests/lib/cre/features/cron/cron.go b/system-tests/lib/cre/features/cron/cron.go index 4d64b45be22..e98b6b08e6d 100644 --- a/system-tests/lib/cre/features/cron/cron.go +++ b/system-tests/lib/cre/features/cron/cron.go @@ -14,7 +14,7 @@ import ( const flag = cre.CronCapability -type Cron struct{} +type Cron struct{ cre.NoopPostDONStartup } func (c *Cron) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/custom_compute/custom_compute.go b/system-tests/lib/cre/features/custom_compute/custom_compute.go index b8184149d8d..d33747055de 100644 --- a/system-tests/lib/cre/features/custom_compute/custom_compute.go +++ b/system-tests/lib/cre/features/custom_compute/custom_compute.go @@ -28,7 +28,7 @@ import ( const flag = cre.CustomComputeCapability -type CustomCompute struct{} +type CustomCompute struct{ cre.NoopPostDONStartup } func (o *CustomCompute) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/don_time/don_time.go b/system-tests/lib/cre/features/don_time/don_time.go index 711fee093f5..dc31974af18 100644 --- a/system-tests/lib/cre/features/don_time/don_time.go +++ b/system-tests/lib/cre/features/don_time/don_time.go @@ -28,7 +28,7 @@ const flag = cre.DONTimeCapability const donTimeLabelledName = "dontime" -type DONTime struct{} +type DONTime struct{ cre.NoopPostDONStartup } func (o *DONTime) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/evm/v1/evm.go b/system-tests/lib/cre/features/evm/v1/evm.go index c1fae2fcdd2..71d288f6b4f 100644 --- a/system-tests/lib/cre/features/evm/v1/evm.go +++ b/system-tests/lib/cre/features/evm/v1/evm.go @@ -42,7 +42,7 @@ import ( const flag = cre.WriteEVMCapability -type EVM struct{} +type EVM struct{ cre.NoopPostDONStartup } func (o *EVM) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/evm/v2/evm.go b/system-tests/lib/cre/features/evm/v2/evm.go index bfd2602feff..10374fec232 100644 --- a/system-tests/lib/cre/features/evm/v2/evm.go +++ b/system-tests/lib/cre/features/evm/v2/evm.go @@ -50,7 +50,7 @@ const ( requestTimeout = 30 * time.Second ) -type EVM struct{} +type EVM struct{ cre.NoopPostDONStartup } func (o *EVM) Flag() cre.CapabilityFlag { return flag @@ -127,13 +127,19 @@ func (o *EVM) PreEnvStartup( } capabilityToOCR3Config := make(map[string]*ocr3.OracleConfig, len(capabilities)) + capabilityLabels := make([]string, 0, len(capabilities)) for _, cap := range capabilities { capabilityToOCR3Config[cap.Capability.LabelledName] = contracts.DefaultChainCapabilityOCR3Config() + capabilityLabels = append(capabilityLabels, cap.Capability.LabelledName) } return &cre.PreEnvStartupOutput{ DONCapabilityWithConfig: capabilities, CapabilityToOCR3Config: capabilityToOCR3Config, + CapabilityToExtraSignerFamilies: cre.CapabilityToExtraSignerFamilies( + cre.NonEVMOCRSignerFamilies(creEnv.Blockchains), + capabilityLabels..., + ), }, nil } diff --git a/system-tests/lib/cre/features/http_action/http_action.go b/system-tests/lib/cre/features/http_action/http_action.go index 348509b41d4..7aed84a13cf 100644 --- a/system-tests/lib/cre/features/http_action/http_action.go +++ b/system-tests/lib/cre/features/http_action/http_action.go @@ -29,7 +29,7 @@ import ( const flag = cre.HTTPActionCapability -type HTTPAction struct{} +type HTTPAction struct{ cre.NoopPostDONStartup } func (o *HTTPAction) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/http_trigger/http_trigger.go b/system-tests/lib/cre/features/http_trigger/http_trigger.go index 7a8436bf9e1..25702abf453 100644 --- a/system-tests/lib/cre/features/http_trigger/http_trigger.go +++ b/system-tests/lib/cre/features/http_trigger/http_trigger.go @@ -29,7 +29,7 @@ import ( const flag = cre.HTTPTriggerCapability -type HTTPTrigger struct{} +type HTTPTrigger struct{ cre.NoopPostDONStartup } func (o *HTTPTrigger) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/log_event_trigger/log_event_trigger.go b/system-tests/lib/cre/features/log_event_trigger/log_event_trigger.go index eed2d258aab..0a00edc16de 100644 --- a/system-tests/lib/cre/features/log_event_trigger/log_event_trigger.go +++ b/system-tests/lib/cre/features/log_event_trigger/log_event_trigger.go @@ -26,7 +26,7 @@ import ( const flag = cre.LogEventTriggerCapability -type LogEventTrigger struct{} +type LogEventTrigger struct{ cre.NoopPostDONStartup } func (o *LogEventTrigger) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/mock/mock.go b/system-tests/lib/cre/features/mock/mock.go index 4166243f7ff..1250bf3bddc 100644 --- a/system-tests/lib/cre/features/mock/mock.go +++ b/system-tests/lib/cre/features/mock/mock.go @@ -26,7 +26,7 @@ import ( const flag = cre.MockCapability -type Mock struct{} +type Mock struct{ cre.NoopPostDONStartup } func (o *Mock) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/read_contract/read_contract.go b/system-tests/lib/cre/features/read_contract/read_contract.go index 05aed9fa941..5a7760c33b7 100644 --- a/system-tests/lib/cre/features/read_contract/read_contract.go +++ b/system-tests/lib/cre/features/read_contract/read_contract.go @@ -12,6 +12,7 @@ import ( capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" kcr "github.com/smartcontractkit/chainlink-evm/gethwrappers/keystone/generated/capabilities_registry_1_1_0" + "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" cre_jobs "github.com/smartcontractkit/chainlink/deployment/cre/jobs" cre_jobs_ops "github.com/smartcontractkit/chainlink/deployment/cre/jobs/operations" job_types "github.com/smartcontractkit/chainlink/deployment/cre/jobs/types" @@ -22,11 +23,13 @@ import ( credon "github.com/smartcontractkit/chainlink/system-tests/lib/cre/don" "github.com/smartcontractkit/chainlink/system-tests/lib/cre/don/jobs" "github.com/smartcontractkit/chainlink/system-tests/lib/cre/don/jobs/standardcapability" + creblockchains "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains" + aptosfeature "github.com/smartcontractkit/chainlink/system-tests/lib/cre/features/aptos" ) const flag = cre.ReadContractCapability -type ReadContract struct{} +type ReadContract struct{ cre.NoopPostDONStartup } func (o *ReadContract) Flag() cre.CapabilityFlag { return flag @@ -46,15 +49,40 @@ func (o *ReadContract) PreEnvStartup( } for _, chainID := range enabledChainIDs { + bc, findErr := findBlockchainByChainID(creEnv, chainID) + if findErr != nil { + return nil, findErr + } + + labelledName, skip, labelErr := capabilityLabelForChain(don, creEnv, chainID) + if labelErr != nil { + return nil, labelErr + } + if skip { + continue + } + + capConfig := &capabilitiespb.CapabilityConfig{ + LocalOnly: don.HasOnlyLocalCapabilities(), + } + if bc.IsFamily(blockchain.FamilyAptos) { + capabilityConfig, resolveErr := cre.ResolveCapabilityConfig(don.MustNodeSet(), flag, cre.ChainCapabilityScope(chainID)) + if resolveErr != nil { + return nil, fmt.Errorf("could not resolve capability config for '%s' on chain %d: %w", flag, chainID, resolveErr) + } + capConfig, err = aptosfeature.BuildCapabilityConfig(capabilityConfig.Values, nil, don.HasOnlyLocalCapabilities()) + if err != nil { + return nil, fmt.Errorf("failed to build Aptos read capability config for chain %d: %w", chainID, err) + } + } + capabilities = append(capabilities, keystone_changeset.DONCapabilityWithConfig{ Capability: kcr.CapabilitiesRegistryCapability{ - LabelledName: fmt.Sprintf("read-contract-evm-%d", chainID), + LabelledName: labelledName, Version: "1.0.0", CapabilityType: 1, // ACTION }, - Config: &capabilitiespb.CapabilityConfig{ - LocalOnly: don.HasOnlyLocalCapabilities(), - }, + Config: capConfig, }) } @@ -63,6 +91,42 @@ func (o *ReadContract) PreEnvStartup( }, nil } +func capabilityLabelForChain(don *cre.DonMetadata, creEnv *cre.Environment, chainID uint64) (string, bool, error) { + for _, bc := range creEnv.Blockchains { + if bc.ChainID() != chainID { + continue + } + + switch { + case bc.IsFamily(blockchain.FamilyAptos): + return aptosCapabilityLabel(don, bc) + case bc.IsFamily(blockchain.FamilyEVM), bc.IsFamily(blockchain.FamilyTron): + return fmt.Sprintf("read-contract-evm-%d", chainID), false, nil + default: + return "", false, fmt.Errorf("read-contract is not supported for chain family %s on chainID %d", bc.ChainFamily(), chainID) + } + } + + return "", false, fmt.Errorf("could not find blockchain for read-contract chainID %d", chainID) +} + +func aptosCapabilityLabel(don *cre.DonMetadata, bc blockchainOutput) (string, bool, error) { + // The Aptos feature owns capability registration when Aptos write is enabled on the DON. + if don.HasFlag(cre.WriteAptosCapability) { + return "", true, nil + } + return aptosfeature.CapabilityLabel(bc.ChainSelector()), false, nil +} + +type blockchainOutput interface { + ChainSelector() uint64 + ChainFamily() string +} + +type familyMatcher interface { + IsFamily(chainFamily string) bool +} + const configTemplate = `{"chainId":{{printf "%d" .ChainID}},"network":"{{.NetworkFamily}}"}` func (o *ReadContract) PostEnvStartup( @@ -91,6 +155,14 @@ func (o *ReadContract) PostEnvStartup( } for _, chainID := range enabledChainIDs { + blockchainOutput, findErr := findBlockchainByChainID(creEnv, chainID) + if findErr != nil { + return findErr + } + if shouldSkipPostEnvStartup(don, blockchainOutput) { + continue + } + capabilityConfig, resolveErr := cre.ResolveCapabilityConfig(nodeSet, flag, cre.ChainCapabilityScope(chainID)) if resolveErr != nil { return fmt.Errorf("could not resolve capability config for '%s' on chain %d: %w", flag, chainID, resolveErr) @@ -157,10 +229,26 @@ func (o *ReadContract) PostEnvStartup( } } - approveErr := jobs.Approve(ctx, creEnv.CldfEnvironment.Offchain, dons, specs) - if approveErr != nil { - return fmt.Errorf("failed to approve Read Contract jobs: %w", approveErr) + if len(specs) > 0 { + approveErr := jobs.Approve(ctx, creEnv.CldfEnvironment.Offchain, dons, specs) + if approveErr != nil { + return fmt.Errorf("failed to approve Read Contract jobs: %w", approveErr) + } } return nil } + +func findBlockchainByChainID(creEnv *cre.Environment, chainID uint64) (creblockchains.Blockchain, error) { + for _, bc := range creEnv.Blockchains { + if bc.ChainID() == chainID { + return bc, nil + } + } + + return nil, fmt.Errorf("could not find blockchain for read-contract chainID %d", chainID) +} + +func shouldSkipPostEnvStartup(don *cre.Don, bc familyMatcher) bool { + return bc.IsFamily(blockchain.FamilyAptos) && don.HasFlag(cre.WriteAptosCapability) +} diff --git a/system-tests/lib/cre/features/read_contract/read_contract_test.go b/system-tests/lib/cre/features/read_contract/read_contract_test.go new file mode 100644 index 00000000000..2f41c13c530 --- /dev/null +++ b/system-tests/lib/cre/features/read_contract/read_contract_test.go @@ -0,0 +1,36 @@ +package readcontract + +import ( + "testing" + + "github.com/stretchr/testify/require" + + chainselectors "github.com/smartcontractkit/chain-selectors" + + "github.com/smartcontractkit/chainlink/system-tests/lib/cre" +) + +type familyMatcherStub struct { + family string +} + +func (s familyMatcherStub) IsFamily(chainFamily string) bool { + return s.family == chainFamily +} + +func TestShouldSkipPostEnvStartup(t *testing.T) { + t.Run("skips aptos when write aptos feature owns the don", func(t *testing.T) { + don := &cre.Don{Flags: []cre.CapabilityFlag{cre.ReadContractCapability, cre.WriteAptosCapability}} + require.True(t, shouldSkipPostEnvStartup(don, familyMatcherStub{family: chainselectors.FamilyAptos})) + }) + + t.Run("does not skip aptos for read-only dons", func(t *testing.T) { + don := &cre.Don{Flags: []cre.CapabilityFlag{cre.ReadContractCapability}} + require.False(t, shouldSkipPostEnvStartup(don, familyMatcherStub{family: chainselectors.FamilyAptos})) + }) + + t.Run("does not skip non-aptos chains", func(t *testing.T) { + don := &cre.Don{Flags: []cre.CapabilityFlag{cre.ReadContractCapability, cre.WriteAptosCapability}} + require.False(t, shouldSkipPostEnvStartup(don, familyMatcherStub{family: chainselectors.FamilyEVM})) + }) +} diff --git a/system-tests/lib/cre/features/sets/sets.go b/system-tests/lib/cre/features/sets/sets.go index f29a5ad9be8..73d4c5e373e 100644 --- a/system-tests/lib/cre/features/sets/sets.go +++ b/system-tests/lib/cre/features/sets/sets.go @@ -2,6 +2,7 @@ package sets import ( "github.com/smartcontractkit/chainlink/system-tests/lib/cre" + aptos_feature "github.com/smartcontractkit/chainlink/system-tests/lib/cre/features/aptos" consensus_v1_feature "github.com/smartcontractkit/chainlink/system-tests/lib/cre/features/consensus/v1" consensus_v2_feature "github.com/smartcontractkit/chainlink/system-tests/lib/cre/features/consensus/v2" cron_feature "github.com/smartcontractkit/chainlink/system-tests/lib/cre/features/cron" @@ -33,6 +34,7 @@ func New() cre.Features { &http_trigger_feature.HTTPTrigger{}, &log_event_trigger_feature.LogEventTrigger{}, &mock_feature.Mock{}, + &aptos_feature.Aptos{}, &read_contract_feature.ReadContract{}, &web_api_target_feature.WebAPITarget{}, &web_api_trigger_feature.WebAPITrigger{}, diff --git a/system-tests/lib/cre/features/solana/v2/solana.go b/system-tests/lib/cre/features/solana/v2/solana.go index 91b2519ec70..6730e4a435d 100644 --- a/system-tests/lib/cre/features/solana/v2/solana.go +++ b/system-tests/lib/cre/features/solana/v2/solana.go @@ -64,7 +64,7 @@ type SolChain interface { SolChainID() string } -type Solana struct{} +type Solana struct{ cre.NoopPostDONStartup } func (s *Solana) Flag() cre.CapabilityFlag { return flag @@ -103,10 +103,14 @@ func (s *Solana) PreEnvStartup( } // 4. Register Solana capability & its methods with Keystone capabilities := registerSolanaCapability(solChain.ChainSelector()) + capabilityToExtraSignerFamilies := make(map[string][]string, len(capabilities)) + for _, capability := range capabilities { + capabilityToExtraSignerFamilies[capability.Capability.LabelledName] = []string{chainselectors.FamilySolana} + } return &cre.PreEnvStartupOutput{ - DONCapabilityWithConfig: capabilities, - ExtraSignerFamilies: []string{chainselectors.FamilySolana}, + DONCapabilityWithConfig: capabilities, + CapabilityToExtraSignerFamilies: capabilityToExtraSignerFamilies, }, nil } diff --git a/system-tests/lib/cre/features/vault/vault.go b/system-tests/lib/cre/features/vault/vault.go index 9eefa2db649..0766c12d9b2 100644 --- a/system-tests/lib/cre/features/vault/vault.go +++ b/system-tests/lib/cre/features/vault/vault.go @@ -50,7 +50,7 @@ const ( ContractQualifier = "vault" ) -type Vault struct{} +type Vault struct{ cre.NoopPostDONStartup } func (o *Vault) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/web_api_target/web_api_target.go b/system-tests/lib/cre/features/web_api_target/web_api_target.go index ff94e1a39e9..ca6067501b8 100644 --- a/system-tests/lib/cre/features/web_api_target/web_api_target.go +++ b/system-tests/lib/cre/features/web_api_target/web_api_target.go @@ -28,7 +28,7 @@ import ( const flag = cre.WebAPITargetCapability -type WebAPITarget struct{} +type WebAPITarget struct{ cre.NoopPostDONStartup } func (o *WebAPITarget) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/web_api_trigger/web_api_trigger.go b/system-tests/lib/cre/features/web_api_trigger/web_api_trigger.go index d0cf033e0aa..99ea848148c 100644 --- a/system-tests/lib/cre/features/web_api_trigger/web_api_trigger.go +++ b/system-tests/lib/cre/features/web_api_trigger/web_api_trigger.go @@ -25,7 +25,7 @@ import ( const flag = cre.WebAPITriggerCapability -type WebAPITrigger struct{} +type WebAPITrigger struct{ cre.NoopPostDONStartup } func (o *WebAPITrigger) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/flags/flags.go b/system-tests/lib/cre/flags/flags.go index 9640af140f9..ab3d568bf1b 100644 --- a/system-tests/lib/cre/flags/flags.go +++ b/system-tests/lib/cre/flags/flags.go @@ -42,7 +42,10 @@ func HasFlagForAnyChain(values []string, capability string) bool { } func RequiresForwarderContract(values []string, chainID uint64) bool { - return HasFlagForChain(values, cre.EVMCapability, chainID) || HasFlagForChain(values, cre.WriteEVMCapability, chainID) || HasFlagForAnyChain(values, cre.SolanaCapability) + return HasFlagForChain(values, cre.EVMCapability, chainID) || + HasFlagForChain(values, cre.WriteEVMCapability, chainID) || + HasFlagForChain(values, cre.WriteAptosCapability, chainID) || + HasFlagForAnyChain(values, cre.SolanaCapability) } func DonMetadataWithFlag(donTopologies []*cre.DonMetadata, flag string) []*cre.DonMetadata { diff --git a/system-tests/lib/cre/flags/flags_test.go b/system-tests/lib/cre/flags/flags_test.go new file mode 100644 index 00000000000..32593fc67b4 --- /dev/null +++ b/system-tests/lib/cre/flags/flags_test.go @@ -0,0 +1,25 @@ +package flags + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/system-tests/lib/cre" +) + +func TestRequiresForwarderContract(t *testing.T) { + t.Run("returns true for aptos write capability", func(t *testing.T) { + require.True(t, RequiresForwarderContract([]string{cre.WriteAptosCapability + "-4"}, 4)) + }) + + t.Run("returns true for evm and solana write paths", func(t *testing.T) { + require.True(t, RequiresForwarderContract([]string{cre.EVMCapability + "-1337"}, 1337)) + require.True(t, RequiresForwarderContract([]string{cre.WriteEVMCapability + "-1337"}, 1337)) + require.True(t, RequiresForwarderContract([]string{cre.SolanaCapability + "-1"}, 1)) + }) + + t.Run("returns false for read-only aptos capability set", func(t *testing.T) { + require.False(t, RequiresForwarderContract([]string{cre.ReadContractCapability + "-4"}, 4)) + }) +} diff --git a/system-tests/lib/cre/flags/provider.go b/system-tests/lib/cre/flags/provider.go index 7e38245f207..151123f1fa2 100644 --- a/system-tests/lib/cre/flags/provider.go +++ b/system-tests/lib/cre/flags/provider.go @@ -25,6 +25,7 @@ func NewDefaultCapabilityFlagsProvider() *DefaultCapbilityFlagsProvider { cre.WriteEVMCapability, cre.ReadContractCapability, cre.LogEventTriggerCapability, + cre.WriteAptosCapability, }, } } @@ -58,6 +59,7 @@ func NewExtensibleCapabilityFlagsProvider(extraGlobalFlags []string) *Extensible cre.SolanaCapability, cre.ReadContractCapability, cre.LogEventTriggerCapability, + cre.WriteAptosCapability, }, } } @@ -89,6 +91,7 @@ func NewSwappableCapabilityFlagsProvider() *DefaultCapbilityFlagsProvider { cre.ReadContractCapability, cre.LogEventTriggerCapability, cre.SolanaCapability, + cre.WriteAptosCapability, }, } } diff --git a/system-tests/lib/cre/ocr_signer_families.go b/system-tests/lib/cre/ocr_signer_families.go new file mode 100644 index 00000000000..d143c2df75c --- /dev/null +++ b/system-tests/lib/cre/ocr_signer_families.go @@ -0,0 +1,44 @@ +package cre + +import ( + "slices" + + chainselectors "github.com/smartcontractkit/chain-selectors" + + "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains" +) + +// NonEVMOCRSignerFamilies returns the non-EVM OCR signer families present in the +// environment. EVM is always included separately by OCR config generation. +func NonEVMOCRSignerFamilies(blockchains []blockchains.Blockchain) []string { + familiesSet := make(map[string]struct{}) + for _, blockchain := range blockchains { + switch { + case blockchain.IsFamily(chainselectors.FamilyAptos): + familiesSet[chainselectors.FamilyAptos] = struct{}{} + case blockchain.IsFamily(chainselectors.FamilySolana): + familiesSet[chainselectors.FamilySolana] = struct{}{} + } + } + + families := make([]string, 0, len(familiesSet)) + for family := range familiesSet { + families = append(families, family) + } + slices.Sort(families) + + return families +} + +func CapabilityToExtraSignerFamilies(families []string, labelledNames ...string) map[string][]string { + if len(families) == 0 || len(labelledNames) == 0 { + return nil + } + + capabilityToFamilies := make(map[string][]string, len(labelledNames)) + for _, labelledName := range labelledNames { + capabilityToFamilies[labelledName] = append([]string(nil), families...) + } + + return capabilityToFamilies +} diff --git a/system-tests/lib/cre/types.go b/system-tests/lib/cre/types.go index 84a9da7074d..49c01189f21 100644 --- a/system-tests/lib/cre/types.go +++ b/system-tests/lib/cre/types.go @@ -70,6 +70,7 @@ const ( HTTPTriggerCapability CapabilityFlag = "http-trigger" HTTPActionCapability CapabilityFlag = "http-action" SolanaCapability CapabilityFlag = "solana" + WriteAptosCapability CapabilityFlag = "write-aptos" // Add more capabilities as needed ) @@ -229,9 +230,10 @@ type CapabilityConfig struct { } // mergeCapabilityConfigs copies entries from src to dst only for keys that -// do not already exist in dst. This is NOT a deep merge - if a key exists -// in dst, its entire CapabilityConfig is preserved without modification. -// Users who override a capability config must provide all required values. +// do not already exist in dst. This is NOT a deep merge - when a key exists +// in dst, only BinaryName may be backfilled from src and Values are preserved +// exactly as provided by the override. Users who override a capability config +// must still provide all required Values. func mergeCapabilityConfigs(dst, src CapabilityConfigs) { for srcKey, srcValue := range src { if dstValue, exists := dst[srcKey]; !exists { @@ -395,9 +397,10 @@ type ConfigureCapabilityRegistryInput struct { // keyed by LabelledName CapabilityToOCR3Config map[string]*ocr3.OracleConfig - // Non-EVM chain families whose signing keys should be included in OCR3 - // config signers (e.g. ["solana"]). EVM is always included. - ExtraSignerFamilies []string + // keyed by LabelledName. Non-EVM chain families whose signing keys should be + // included in OCR3 config signers for that capability (e.g. ["solana"]). + // EVM is always included. + CapabilityToExtraSignerFamilies map[string][]string } func (c *ConfigureCapabilityRegistryInput) Validate() error { @@ -1286,6 +1289,11 @@ func (c *NodeSet) chainCapabilityIDs() []uint64 { return out } +// ChainCapabilityChainIDs returns the set of chain IDs supported by this node set's chain-scoped capabilities (e.g. read-contract-4, write-aptos-4). +func (c *NodeSet) ChainCapabilityChainIDs() []uint64 { + return c.chainCapabilityIDs() +} + func (c *NodeSet) Flags() []string { var stringCaps []string @@ -1627,13 +1635,43 @@ type Feature interface { dons *Dons, creEnv *Environment, ) error + PostDONStartup( + ctx context.Context, + testLogger zerolog.Logger, + don *Don, + dons *Dons, + creEnv *Environment, + ) (*PostDONStartupOutput, error) +} + +type NoopPostDONStartup struct{} + +func (NoopPostDONStartup) PostDONStartup( + context.Context, + zerolog.Logger, + *Don, + *Dons, + *Environment, +) (*PostDONStartupOutput, error) { + return nil, nil } type PreEnvStartupOutput struct { DONCapabilityWithConfig []keystone_changeset.DONCapabilityWithConfig // keyed by LabelledName CapabilityToOCR3Config map[string]*ocr3.OracleConfig - // Non-EVM chain families whose signing keys should be included in OCR3 - // config signers (e.g. ["solana"]). EVM is always included. - ExtraSignerFamilies []string + // keyed by LabelledName. Non-EVM chain families whose signing keys should be + // included in OCR3 config signers for that capability (e.g. ["solana"]). + // EVM is always included. + CapabilityToExtraSignerFamilies map[string][]string +} + +type PostDONStartupOutput struct { + DONCapabilityWithConfig []keystone_changeset.DONCapabilityWithConfig + // keyed by LabelledName + CapabilityToOCR3Config map[string]*ocr3.OracleConfig + // keyed by LabelledName. Non-EVM chain families whose signing keys should be + // included in OCR3 config signers for that capability (e.g. ["solana"]). + // EVM is always included. + CapabilityToExtraSignerFamilies map[string][]string } diff --git a/system-tests/tests/smoke/cre/aptos/aptosread/config/config.go b/system-tests/tests/smoke/cre/aptos/aptosread/config/config.go new file mode 100644 index 00000000000..a6b16c256db --- /dev/null +++ b/system-tests/tests/smoke/cre/aptos/aptosread/config/config.go @@ -0,0 +1,8 @@ +package config + +// Config for the Aptos read consensus workflow (reads 0x1::coin::name() on local devnet). +type Config struct { + ChainSelector uint64 `yaml:"chainSelector"` + WorkflowName string `yaml:"workflowName"` + ExpectedCoinName string `yaml:"expectedCoinName"` // expected exact value in the View reply data (e.g. "Aptos Coin" for 0x1::coin::name()) +} diff --git a/system-tests/tests/smoke/cre/aptos/aptosread/go.mod b/system-tests/tests/smoke/cre/aptos/aptosread/go.mod new file mode 100644 index 00000000000..0dca8e844ce --- /dev/null +++ b/system-tests/tests/smoke/cre/aptos/aptosread/go.mod @@ -0,0 +1,20 @@ +module github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptosread + +go 1.25.5 + +require ( + github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 + github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed + github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c // indirect + github.com/stretchr/testify v1.11.1 // indirect + google.golang.org/protobuf v1.36.11 // indirect +) diff --git a/system-tests/tests/smoke/cre/aptos/aptosread/go.sum b/system-tests/tests/smoke/cre/aptos/aptosread/go.sum new file mode 100644 index 00000000000..22417e77c98 --- /dev/null +++ b/system-tests/tests/smoke/cre/aptos/aptosread/go.sum @@ -0,0 +1,30 @@ +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260317131216-1b30a2aeee6a h1:xVDm2UqUwhAMFwXGOm7sGD97+g9IhUMDioi917GMltI= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260317131216-1b30a2aeee6a/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c h1:m+XflniQiuMPvcKtiWpnsqpOiRNcONKrhF5zwpR2QJM= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260317133250-2edd562283ed h1:u6eLUgwf3bAEa75R0wYZxmXCr7momhl3yOSIogAufdU= +github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260317133250-2edd562283ed/go.mod h1:L/02KvMl4ZtFc16LvBZQcvX4b0pCU1lQtcsZLyWMvFE= +github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 h1:sY79Ue8wkzPbpo4tFvvGSQiTMiqBvgyL0FBJV2UIhWI= +github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373/go.mod h1:MP93PP7lxaFyW+RRNYcEdXHm/gJM/HPqRPUPOAfBH4w= +github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed h1:sShKvyFh1MNBXW5cxau/U2IB4dTdYGah/n5d9G0gOnA= +github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed/go.mod h1:gonMhNKHWWnkNYSfxad+6sVUgZP2LVM4+qm8VqrWqZQ= +github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0 h1:g7UrVaNKVEmIhVkJTk4f8raCM8Kp/RTFnAT64wqNmTY= +github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0/go.mod h1:PWyrIw16It4TSyq6mDXqmSR0jF2evZRKuBxu7pK1yDw= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/system-tests/tests/smoke/cre/aptos/aptosread/main.go b/system-tests/tests/smoke/cre/aptos/aptosread/main.go new file mode 100644 index 00000000000..9a3ad82fc1d --- /dev/null +++ b/system-tests/tests/smoke/cre/aptos/aptosread/main.go @@ -0,0 +1,113 @@ +//go:build wasip1 + +package main + +import ( + "encoding/json" + "errors" + "fmt" + "log/slog" + "strings" + + "gopkg.in/yaml.v3" + + "github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos" + "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" + sdk "github.com/smartcontractkit/cre-sdk-go/cre" + "github.com/smartcontractkit/cre-sdk-go/cre/wasm" + + "github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptosread/config" +) + +var aptosCoinTypeTag = &aptos.TypeTag{ + Kind: aptos.TypeTagKind_TYPE_TAG_KIND_STRUCT, + Value: &aptos.TypeTag_Struct{ + Struct: &aptos.StructTag{ + Address: []byte{0x1}, + Module: "aptos_coin", + Name: "AptosCoin", + }, + }, +} + +func main() { + wasm.NewRunner(func(b []byte) (config.Config, error) { + cfg := config.Config{} + if err := yaml.Unmarshal(b, &cfg); err != nil { + return config.Config{}, fmt.Errorf("unmarshal config: %w", err) + } + return cfg, nil + }).Run(RunReadWorkflow) +} + +func RunReadWorkflow(cfg config.Config, logger *slog.Logger, secretsProvider sdk.SecretsProvider) (sdk.Workflow[config.Config], error) { + return sdk.Workflow[config.Config]{ + sdk.Handler( + cron.Trigger(&cron.Config{Schedule: "*/30 * * * * *"}), + onAptosReadTrigger, + ), + }, nil +} + +func onAptosReadTrigger(cfg config.Config, runtime sdk.Runtime, payload *cron.Payload) (_ any, err error) { + runtime.Logger().Info("onAptosReadTrigger called", "workflow", cfg.WorkflowName) + defer func() { + if r := recover(); r != nil { + runtime.Logger().Info("Aptos read failed: panic in onAptosReadTrigger", "workflow", cfg.WorkflowName, "panic", fmt.Sprintf("%v", r)) + err = fmt.Errorf("panic: %v", r) + } + }() + + client := aptos.Client{ChainSelector: cfg.ChainSelector} + reply, err := client.View(runtime, &aptos.ViewRequest{ + Payload: &aptos.ViewPayload{ + Module: &aptos.ModuleID{ + Address: []byte{0x1}, + Name: "coin", + }, + Function: "name", + ArgTypes: []*aptos.TypeTag{aptosCoinTypeTag}, + }, + }).Await() + if err != nil { + msg := fmt.Sprintf("Aptos read failed: View error: %v", err) + runtime.Logger().Info(msg, "workflow", cfg.WorkflowName, "chainSelector", cfg.ChainSelector) + return nil, fmt.Errorf("Aptos View(0x1::coin::name): %w", err) + } + if reply == nil { + runtime.Logger().Info("Aptos read failed: View reply is nil", "workflow", cfg.WorkflowName) + return nil, errors.New("View reply is nil") + } + if len(reply.Data) == 0 { + runtime.Logger().Info("Aptos read failed: View reply data is empty", "workflow", cfg.WorkflowName) + return nil, errors.New("View reply data is empty") + } + + onchainValue, parseErr := parseSingleStringViewReply(reply.Data) + if parseErr != nil { + msg := fmt.Sprintf("Aptos read failed: cannot parse view reply data %q: %v", string(reply.Data), parseErr) + runtime.Logger().Info(msg, "workflow", cfg.WorkflowName) + return nil, fmt.Errorf("invalid Aptos view reply payload: %w", parseErr) + } + + if onchainValue != cfg.ExpectedCoinName { + msg := fmt.Sprintf("Aptos read failed: onchain value %q does not match expected %q", onchainValue, cfg.ExpectedCoinName) + runtime.Logger().Info(msg, "workflow", cfg.WorkflowName) + return nil, fmt.Errorf("onchain value %q does not match expected %q", onchainValue, cfg.ExpectedCoinName) + } + + msg := "Aptos read consensus succeeded" + runtime.Logger().Info(msg, "onchain_value", strings.TrimSpace(onchainValue), "workflow", cfg.WorkflowName) + return nil, nil +} + +func parseSingleStringViewReply(data []byte) (string, error) { + var values []string + if err := json.Unmarshal(data, &values); err != nil { + return "", fmt.Errorf("decode json string array: %w", err) + } + if len(values) == 0 { + return "", errors.New("empty json array") + } + return values[0], nil +} diff --git a/system-tests/tests/smoke/cre/aptos/aptoswrite/config/config.go b/system-tests/tests/smoke/cre/aptos/aptoswrite/config/config.go new file mode 100644 index 00000000000..bffa8499395 --- /dev/null +++ b/system-tests/tests/smoke/cre/aptos/aptoswrite/config/config.go @@ -0,0 +1,18 @@ +package config + +// Config for Aptos write workflow (submits a report via the Aptos write capability). +type Config struct { + ChainSelector uint64 `yaml:"chainSelector"` + WorkflowName string `yaml:"workflowName"` + ReceiverHex string `yaml:"receiverHex"` + ReportMessage string `yaml:"reportMessage"` + // When true, the workflow expects WriteReport to return a non-success tx status and treats that as success. + ExpectFailure bool `yaml:"expectFailure"` + // Number of OCR signatures to include in the submitted report (forwarder expects f+1). + RequiredSignatures int `yaml:"requiredSignatures"` + // Optional hex-encoded payload to pass through OCR report generation. + // If empty, ReportMessage bytes are used. + ReportPayloadHex string `yaml:"reportPayloadHex"` + MaxGasAmount uint64 `yaml:"maxGasAmount"` + GasUnitPrice uint64 `yaml:"gasUnitPrice"` +} diff --git a/system-tests/tests/smoke/cre/aptos/aptoswrite/go.mod b/system-tests/tests/smoke/cre/aptos/aptoswrite/go.mod new file mode 100644 index 00000000000..d8337bae77c --- /dev/null +++ b/system-tests/tests/smoke/cre/aptos/aptoswrite/go.mod @@ -0,0 +1,20 @@ +module github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptoswrite + +go 1.25.5 + +require ( + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c + github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 + github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed + github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/stretchr/testify v1.11.1 // indirect + google.golang.org/protobuf v1.36.11 // indirect +) diff --git a/system-tests/tests/smoke/cre/aptos/aptoswrite/go.sum b/system-tests/tests/smoke/cre/aptos/aptoswrite/go.sum new file mode 100644 index 00000000000..22417e77c98 --- /dev/null +++ b/system-tests/tests/smoke/cre/aptos/aptoswrite/go.sum @@ -0,0 +1,30 @@ +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260317131216-1b30a2aeee6a h1:xVDm2UqUwhAMFwXGOm7sGD97+g9IhUMDioi917GMltI= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260317131216-1b30a2aeee6a/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c h1:m+XflniQiuMPvcKtiWpnsqpOiRNcONKrhF5zwpR2QJM= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260317133250-2edd562283ed h1:u6eLUgwf3bAEa75R0wYZxmXCr7momhl3yOSIogAufdU= +github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260317133250-2edd562283ed/go.mod h1:L/02KvMl4ZtFc16LvBZQcvX4b0pCU1lQtcsZLyWMvFE= +github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 h1:sY79Ue8wkzPbpo4tFvvGSQiTMiqBvgyL0FBJV2UIhWI= +github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373/go.mod h1:MP93PP7lxaFyW+RRNYcEdXHm/gJM/HPqRPUPOAfBH4w= +github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed h1:sShKvyFh1MNBXW5cxau/U2IB4dTdYGah/n5d9G0gOnA= +github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed/go.mod h1:gonMhNKHWWnkNYSfxad+6sVUgZP2LVM4+qm8VqrWqZQ= +github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0 h1:g7UrVaNKVEmIhVkJTk4f8raCM8Kp/RTFnAT64wqNmTY= +github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0/go.mod h1:PWyrIw16It4TSyq6mDXqmSR0jF2evZRKuBxu7pK1yDw= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/system-tests/tests/smoke/cre/aptos/aptoswrite/main.go b/system-tests/tests/smoke/cre/aptos/aptoswrite/main.go new file mode 100644 index 00000000000..41275dcbb26 --- /dev/null +++ b/system-tests/tests/smoke/cre/aptos/aptoswrite/main.go @@ -0,0 +1,285 @@ +//go:build wasip1 + +package main + +import ( + "encoding/hex" + "fmt" + "log/slog" + "regexp" + "strings" + + "gopkg.in/yaml.v3" + + "github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos" + "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" + sdk "github.com/smartcontractkit/cre-sdk-go/cre" + "github.com/smartcontractkit/cre-sdk-go/cre/wasm" + + sdkpb "github.com/smartcontractkit/chainlink-protos/cre/go/sdk" + "github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptoswrite/config" +) + +func main() { + wasm.NewRunner(func(b []byte) (config.Config, error) { + cfg := config.Config{} + if err := yaml.Unmarshal(b, &cfg); err != nil { + return config.Config{}, fmt.Errorf("unmarshal config: %w", err) + } + return cfg, nil + }).Run(RunAptosWriteWorkflow) +} + +func RunAptosWriteWorkflow(cfg config.Config, logger *slog.Logger, secretsProvider sdk.SecretsProvider) (sdk.Workflow[config.Config], error) { + return sdk.Workflow[config.Config]{ + sdk.Handler( + cron.Trigger(&cron.Config{Schedule: "*/30 * * * * *"}), + onAptosWriteTrigger, + ), + }, nil +} + +func onAptosWriteTrigger(cfg config.Config, runtime sdk.Runtime, payload *cron.Payload) (_ any, err error) { + runtime.Logger().Info("onAptosWriteTrigger called", "workflow", cfg.WorkflowName) + + receiver, err := decodeAptosAddressHex(cfg.ReceiverHex) + if err != nil { + msg := fmt.Sprintf("Aptos write failed: invalid receiver address: %v", err) + runtime.Logger().Info(msg, "workflow", cfg.WorkflowName) + return nil, err + } + + reportPayload, err := resolveReportPayload(cfg) + if err != nil { + failMsg := fmt.Sprintf("Aptos write failed: invalid report payload: %v", err) + runtime.Logger().Info(failMsg, "workflow", cfg.WorkflowName) + return nil, err + } + + report, err := runtime.GenerateReport(&sdkpb.ReportRequest{ + EncodedPayload: reportPayload, + // Select Aptos key bundle path in consensus report generation. + EncoderName: "aptos", + // Aptos forwarder verifies ed25519 signatures over blake2b_256(raw_report). + SigningAlgo: "ed25519", + HashingAlgo: "blake2b_256", + }).Await() + if err != nil { + failMsg := fmt.Sprintf("Aptos write failed: generate report error: %v", err) + runtime.Logger().Info(failMsg, "workflow", cfg.WorkflowName) + return nil, err + } + reportResp := report.X_GeneratedCodeOnly_Unwrap() + if len(reportResp.ReportContext) == 0 { + err := fmt.Errorf("missing report context from generated report") + runtime.Logger().Info("Aptos write failed: missing report context", "workflow", cfg.WorkflowName, "error", err.Error()) + return nil, err + } + if len(reportResp.ReportContext) != 96 { + err := fmt.Errorf("unexpected report context length: got=%d want=96", len(reportResp.ReportContext)) + runtime.Logger().Info("Aptos write failed: invalid report context length", "workflow", cfg.WorkflowName, "error", err.Error()) + return nil, err + } + if len(reportResp.RawReport) == 0 { + err := fmt.Errorf("missing raw report from generated report") + runtime.Logger().Info("Aptos write failed: missing raw report", "workflow", cfg.WorkflowName, "error", err.Error()) + return nil, err + } + // Preserve generated report bytes as-is; Aptos capability handles wire-format packing. + reportVersion := int(reportResp.RawReport[0]) + runtime.Logger().Info( + "Aptos write: generated report details", + "workflow", cfg.WorkflowName, + "reportContextLen", len(reportResp.ReportContext), + "rawReportLen", len(reportResp.RawReport), + "reportVersion", reportVersion, + ) + + runtime.Logger().Info( + "Aptos write: generated report", + "workflow", cfg.WorkflowName, + "sigCount", len(reportResp.Sigs), + ) + if len(reportResp.Sigs) > 0 { + runtime.Logger().Info( + "Aptos write: first signature details", + "workflow", cfg.WorkflowName, + "firstSigLen", len(reportResp.Sigs[0].Signature), + "firstSignerID", reportResp.Sigs[0].SignerId, + ) + } + requiredSignatures := cfg.RequiredSignatures + if requiredSignatures <= 0 { + requiredSignatures = len(reportResp.Sigs) + } + if len(reportResp.Sigs) > requiredSignatures { + reportResp.Sigs = reportResp.Sigs[:requiredSignatures] + runtime.Logger().Info( + "Aptos write: trimmed report signatures for forwarder", + "workflow", cfg.WorkflowName, + "requiredSignatures", requiredSignatures, + "sigCount", len(reportResp.Sigs), + ) + } + if len(reportResp.Sigs) < requiredSignatures { + err := fmt.Errorf("insufficient report signatures: have=%d need=%d", len(reportResp.Sigs), requiredSignatures) + runtime.Logger().Info("Aptos write failed: report has fewer signatures than required", "workflow", cfg.WorkflowName, "error", err.Error()) + return nil, err + } + + client := aptos.Client{ChainSelector: cfg.ChainSelector} + runtime.Logger().Info( + "Aptos write: using gas config", + "workflow", cfg.WorkflowName, + "chainSelector", cfg.ChainSelector, + "maxGasAmount", cfg.MaxGasAmount, + "gasUnitPrice", cfg.GasUnitPrice, + ) + reply, err := client.WriteReport(runtime, &aptos.WriteReportRequest{ + Receiver: receiver, + Report: reportResp, + GasConfig: &aptos.GasConfig{ + MaxGasAmount: cfg.MaxGasAmount, + GasUnitPrice: cfg.GasUnitPrice, + }, + }).Await() + if err != nil { + if cfg.ExpectFailure { + runtime.Logger().Info( + "Aptos write failed: expected failure path requires non-empty failed tx hash", + "workflow", cfg.WorkflowName, + "txStatus", "call_error", + "txHash", "", + "error", err.Error(), + ) + return nil, fmt.Errorf("expected failed tx hash in WriteReport reply, got error instead: %w", err) + } + failMsg := fmt.Sprintf("Aptos write failed: WriteReport error: %v", err) + runtime.Logger().Info(failMsg, "workflow", cfg.WorkflowName, "chainSelector", cfg.ChainSelector) + return nil, err + } + if reply == nil { + runtime.Logger().Info("Aptos write failed: WriteReport reply is nil", "workflow", cfg.WorkflowName) + return nil, fmt.Errorf("nil WriteReport reply") + } + if cfg.ExpectFailure { + if reply.TxStatus == aptos.TxStatus_TX_STATUS_SUCCESS { + errorMsg := "" + if reply.ErrorMessage != nil { + errorMsg = *reply.ErrorMessage + } + runtime.Logger().Info( + "Aptos write failed: expected non-success tx status", + "workflow", cfg.WorkflowName, + "txStatus", reply.TxStatus.String(), + "error", errorMsg, + ) + return nil, fmt.Errorf("expected non-success tx status, got %s", reply.TxStatus.String()) + } + txHashRaw := reply.GetTxHash() + if txHashRaw == "" { + runtime.Logger().Info( + "Aptos write failed: expected failed tx hash but got empty hash", + "workflow", cfg.WorkflowName, + ) + return nil, fmt.Errorf("expected failed tx hash in WriteReport reply") + } + + txHash, err := normalizeTxHash(txHashRaw) + if err != nil { + runtime.Logger().Info("Aptos write failed: invalid failed tx hash format", "workflow", cfg.WorkflowName, "error", err.Error()) + return nil, fmt.Errorf("invalid failed tx hash format: %w", err) + } + + errorMsg := "" + if reply.ErrorMessage != nil { + errorMsg = *reply.ErrorMessage + } + runtime.Logger().Info( + fmt.Sprintf("Aptos write failure observed as expected txHash=%s", txHash), + "workflow", cfg.WorkflowName, + "txStatus", reply.TxStatus.String(), + "txHash", txHash, + "error", errorMsg, + ) + return nil, nil + } + if reply.TxStatus != aptos.TxStatus_TX_STATUS_SUCCESS { + errorMsg := "" + if reply.ErrorMessage != nil { + errorMsg = *reply.ErrorMessage + } + failMsg := fmt.Sprintf("Aptos write failed: tx status=%s error=%s", reply.TxStatus.String(), errorMsg) + runtime.Logger().Info(failMsg, "workflow", cfg.WorkflowName) + return nil, fmt.Errorf("unexpected tx status: %s", reply.TxStatus.String()) + } + txHashRaw := reply.GetTxHash() + if txHashRaw == "" { + runtime.Logger().Info( + "Aptos write failed: expected successful tx hash but got empty hash", + "workflow", cfg.WorkflowName, + "txStatus", reply.TxStatus.String(), + ) + return nil, fmt.Errorf("expected non-empty tx hash in successful WriteReport reply") + } + + txHash, err := normalizeTxHash(txHashRaw) + if err != nil { + runtime.Logger().Info("Aptos write failed: invalid tx hash format", "workflow", cfg.WorkflowName, "error", err.Error()) + return nil, fmt.Errorf("invalid tx hash format: %w", err) + } + + runtime.Logger().Info("Aptos write capability succeeded", "workflow", cfg.WorkflowName, "txHash", txHash) + return nil, nil +} + +func resolveReportPayload(cfg config.Config) ([]byte, error) { + if strings.TrimSpace(cfg.ReportPayloadHex) != "" { + trimmed := strings.TrimPrefix(strings.TrimSpace(cfg.ReportPayloadHex), "0x") + if trimmed == "" { + return nil, fmt.Errorf("empty hex payload") + } + raw, err := hex.DecodeString(trimmed) + if err != nil { + return nil, fmt.Errorf("decode hex payload: %w", err) + } + return raw, nil + } + + msg := cfg.ReportMessage + if msg == "" { + msg = "Aptos write workflow executed successfully" + } + return []byte(msg), nil +} + +func decodeAptosAddressHex(in string) ([]byte, error) { + trimmed := strings.TrimPrefix(strings.TrimSpace(in), "0x") + if trimmed == "" { + return nil, fmt.Errorf("empty address") + } + if len(trimmed)%2 != 0 { + trimmed = "0" + trimmed + } + raw, err := hex.DecodeString(trimmed) + if err != nil { + return nil, fmt.Errorf("decode hex address: %w", err) + } + if len(raw) > 32 { + return nil, fmt.Errorf("address too long: %d bytes", len(raw)) + } + out := make([]byte, 32) + copy(out[32-len(raw):], raw) + return out, nil +} + +var aptosHashRe = regexp.MustCompile(`^[0-9a-fA-F]{64}$`) + +func normalizeTxHash(raw string) (string, error) { + s := strings.TrimSpace(raw) + s = strings.TrimPrefix(strings.ToLower(s), "0x") + if !aptosHashRe.MatchString(s) { + return "", fmt.Errorf("expected 32-byte tx hash, got %q", raw) + } + return "0x" + s, nil +} diff --git a/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/config/config.go b/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/config/config.go new file mode 100644 index 00000000000..0e1987859c7 --- /dev/null +++ b/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/config/config.go @@ -0,0 +1,15 @@ +package config + +// Config for Aptos write->read roundtrip workflow. +// The workflow writes a benchmark report, then reads back get_feeds and validates the value. +type Config struct { + ChainSelector uint64 `yaml:"chainSelector"` + WorkflowName string `yaml:"workflowName"` + ReceiverHex string `yaml:"receiverHex"` + RequiredSignatures int `yaml:"requiredSignatures"` + ReportPayloadHex string `yaml:"reportPayloadHex"` + MaxGasAmount uint64 `yaml:"maxGasAmount"` + GasUnitPrice uint64 `yaml:"gasUnitPrice"` + FeedIDHex string `yaml:"feedIDHex"` + ExpectedBenchmark uint64 `yaml:"expectedBenchmark"` +} diff --git a/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.mod b/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.mod new file mode 100644 index 00000000000..b76176fc279 --- /dev/null +++ b/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.mod @@ -0,0 +1,20 @@ +module github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip + +go 1.25.5 + +require ( + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c + github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 + github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed + github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/stretchr/testify v1.11.1 // indirect + google.golang.org/protobuf v1.36.11 // indirect +) diff --git a/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.sum b/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.sum new file mode 100644 index 00000000000..22417e77c98 --- /dev/null +++ b/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.sum @@ -0,0 +1,30 @@ +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260317131216-1b30a2aeee6a h1:xVDm2UqUwhAMFwXGOm7sGD97+g9IhUMDioi917GMltI= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260317131216-1b30a2aeee6a/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c h1:m+XflniQiuMPvcKtiWpnsqpOiRNcONKrhF5zwpR2QJM= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260317133250-2edd562283ed h1:u6eLUgwf3bAEa75R0wYZxmXCr7momhl3yOSIogAufdU= +github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260317133250-2edd562283ed/go.mod h1:L/02KvMl4ZtFc16LvBZQcvX4b0pCU1lQtcsZLyWMvFE= +github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 h1:sY79Ue8wkzPbpo4tFvvGSQiTMiqBvgyL0FBJV2UIhWI= +github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373/go.mod h1:MP93PP7lxaFyW+RRNYcEdXHm/gJM/HPqRPUPOAfBH4w= +github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed h1:sShKvyFh1MNBXW5cxau/U2IB4dTdYGah/n5d9G0gOnA= +github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed/go.mod h1:gonMhNKHWWnkNYSfxad+6sVUgZP2LVM4+qm8VqrWqZQ= +github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0 h1:g7UrVaNKVEmIhVkJTk4f8raCM8Kp/RTFnAT64wqNmTY= +github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0/go.mod h1:PWyrIw16It4TSyq6mDXqmSR0jF2evZRKuBxu7pK1yDw= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/main.go b/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/main.go new file mode 100644 index 00000000000..5ca3cfa592b --- /dev/null +++ b/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/main.go @@ -0,0 +1,224 @@ +//go:build wasip1 + +package main + +import ( + "encoding/hex" + "encoding/json" + "fmt" + "log/slog" + "strconv" + "strings" + + "gopkg.in/yaml.v3" + + "github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos" + "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron" + sdk "github.com/smartcontractkit/cre-sdk-go/cre" + "github.com/smartcontractkit/cre-sdk-go/cre/wasm" + + sdkpb "github.com/smartcontractkit/chainlink-protos/cre/go/sdk" + "github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/config" +) + +type feedEntry struct { + FeedID string `json:"feed_id"` + Feed struct { + Benchmark string `json:"benchmark"` + } `json:"feed"` +} + +func main() { + wasm.NewRunner(func(b []byte) (config.Config, error) { + cfg := config.Config{} + if err := yaml.Unmarshal(b, &cfg); err != nil { + return config.Config{}, fmt.Errorf("unmarshal config: %w", err) + } + return cfg, nil + }).Run(RunAptosWriteReadRoundtripWorkflow) +} + +func RunAptosWriteReadRoundtripWorkflow(cfg config.Config, logger *slog.Logger, secretsProvider sdk.SecretsProvider) (sdk.Workflow[config.Config], error) { + return sdk.Workflow[config.Config]{ + sdk.Handler( + cron.Trigger(&cron.Config{Schedule: "*/30 * * * * *"}), + onAptosWriteReadRoundtripTrigger, + ), + }, nil +} + +func onAptosWriteReadRoundtripTrigger(cfg config.Config, runtime sdk.Runtime, payload *cron.Payload) (_ any, err error) { + runtime.Logger().Info("onAptosWriteReadRoundtripTrigger called", "workflow", cfg.WorkflowName) + + receiverBytes, err := decodeAptosAddressHex(cfg.ReceiverHex) + if err != nil { + return nil, fmt.Errorf("invalid receiver address: %w", err) + } + + reportPayload, err := resolveReportPayload(cfg.ReportPayloadHex) + if err != nil { + return nil, fmt.Errorf("invalid report payload: %w", err) + } + + report, err := runtime.GenerateReport(&sdkpb.ReportRequest{ + EncodedPayload: reportPayload, + EncoderName: "aptos", + SigningAlgo: "ed25519", + HashingAlgo: "blake2b_256", + }).Await() + if err != nil { + return nil, fmt.Errorf("generate report error: %w", err) + } + reportResp := report.X_GeneratedCodeOnly_Unwrap() + if len(reportResp.ReportContext) != 96 { + return nil, fmt.Errorf("invalid report context length: got=%d want=96", len(reportResp.ReportContext)) + } + if len(reportResp.RawReport) == 0 { + return nil, fmt.Errorf("missing raw report") + } + + requiredSignatures := cfg.RequiredSignatures + if requiredSignatures <= 0 { + requiredSignatures = len(reportResp.Sigs) + } + if len(reportResp.Sigs) < requiredSignatures { + return nil, fmt.Errorf("insufficient report signatures: have=%d need=%d", len(reportResp.Sigs), requiredSignatures) + } + if len(reportResp.Sigs) > requiredSignatures { + reportResp.Sigs = reportResp.Sigs[:requiredSignatures] + } + + client := aptos.Client{ChainSelector: cfg.ChainSelector} + reply, err := client.WriteReport(runtime, &aptos.WriteReportRequest{ + Receiver: receiverBytes, + Report: reportResp, + GasConfig: &aptos.GasConfig{ + MaxGasAmount: cfg.MaxGasAmount, + GasUnitPrice: cfg.GasUnitPrice, + }, + }).Await() + if err != nil { + return nil, fmt.Errorf("WriteReport error: %w", err) + } + if reply == nil { + return nil, fmt.Errorf("nil WriteReport reply") + } + if reply.TxStatus != aptos.TxStatus_TX_STATUS_SUCCESS { + return nil, fmt.Errorf("unexpected tx status: %s", reply.TxStatus.String()) + } + + viewReply, err := client.View(runtime, &aptos.ViewRequest{ + Payload: &aptos.ViewPayload{ + Module: &aptos.ModuleID{ + Address: receiverBytes, + Name: "registry", + }, + Function: "get_feeds", + }, + }).Await() + if err != nil { + return nil, fmt.Errorf("Aptos View(%s::registry::get_feeds): %w", normalizeHex(cfg.ReceiverHex), err) + } + if viewReply == nil || len(viewReply.Data) == 0 { + return nil, fmt.Errorf("empty view reply for %s::registry::get_feeds", normalizeHex(cfg.ReceiverHex)) + } + + benchmark, found, parseErr := parseBenchmark(viewReply.Data, cfg.FeedIDHex) + if parseErr != nil { + return nil, fmt.Errorf("parse benchmark view reply: %w", parseErr) + } + if !found { + return nil, fmt.Errorf("feed %s not found in get_feeds reply", cfg.FeedIDHex) + } + if benchmark != cfg.ExpectedBenchmark { + return nil, fmt.Errorf("benchmark mismatch: got=%d want=%d", benchmark, cfg.ExpectedBenchmark) + } + + runtime.Logger().Info( + "Aptos write/read consensus succeeded", + "workflow", cfg.WorkflowName, + "benchmark", benchmark, + "feedID", normalizeHex(cfg.FeedIDHex), + ) + return nil, nil +} + +func resolveReportPayload(reportPayloadHex string) ([]byte, error) { + trimmed := strings.TrimPrefix(strings.TrimSpace(reportPayloadHex), "0x") + if trimmed == "" { + return nil, fmt.Errorf("empty hex payload") + } + raw, err := hex.DecodeString(trimmed) + if err != nil { + return nil, fmt.Errorf("decode hex payload: %w", err) + } + return raw, nil +} + +func decodeAptosAddressHex(in string) ([]byte, error) { + trimmed := strings.TrimPrefix(strings.TrimSpace(in), "0x") + if trimmed == "" { + return nil, fmt.Errorf("empty address") + } + if len(trimmed)%2 != 0 { + trimmed = "0" + trimmed + } + raw, err := hex.DecodeString(trimmed) + if err != nil { + return nil, fmt.Errorf("decode hex address: %w", err) + } + if len(raw) > 32 { + return nil, fmt.Errorf("address too long: %d bytes", len(raw)) + } + out := make([]byte, 32) + copy(out[32-len(raw):], raw) + return out, nil +} + +func parseBenchmark(data []byte, feedIDHex string) (uint64, bool, error) { + normalizedFeedID := normalizeHex(feedIDHex) + if normalizedFeedID == "" { + return 0, false, fmt.Errorf("empty feed id") + } + + var wrapped [][]feedEntry + if err := json.Unmarshal(data, &wrapped); err == nil && len(wrapped) > 0 { + for _, entry := range wrapped[0] { + if normalizeHex(entry.FeedID) != normalizedFeedID { + continue + } + v, convErr := strconv.ParseUint(strings.TrimSpace(entry.Feed.Benchmark), 10, 64) + if convErr != nil { + return 0, false, fmt.Errorf("parse benchmark %q: %w", entry.Feed.Benchmark, convErr) + } + return v, true, nil + } + return 0, false, nil + } + + var direct []feedEntry + if err := json.Unmarshal(data, &direct); err != nil { + return 0, false, fmt.Errorf("decode get_feeds payload: %w", err) + } + for _, entry := range direct { + if normalizeHex(entry.FeedID) != normalizedFeedID { + continue + } + v, convErr := strconv.ParseUint(strings.TrimSpace(entry.Feed.Benchmark), 10, 64) + if convErr != nil { + return 0, false, fmt.Errorf("parse benchmark %q: %w", entry.Feed.Benchmark, convErr) + } + return v, true, nil + } + return 0, false, nil +} + +func normalizeHex(in string) string { + s := strings.TrimSpace(strings.ToLower(in)) + s = strings.TrimPrefix(s, "0x") + s = strings.TrimLeft(s, "0") + if s == "" { + return "0x0" + } + return "0x" + s +} diff --git a/system-tests/tests/smoke/cre/cre_suite_test.go b/system-tests/tests/smoke/cre/cre_suite_test.go index 8afebf4a006..1cd8225cd4f 100644 --- a/system-tests/tests/smoke/cre/cre_suite_test.go +++ b/system-tests/tests/smoke/cre/cre_suite_test.go @@ -66,7 +66,7 @@ func Test_CRE_V1_Billing_EVM_Write(t *testing.T) { "failed to start Billing stack", ) - priceProvider, porWfCfg := BeforePoRTest(t, testEnv, "por-workflowV2-billing", PoRWFV2Location) + priceProvider, porWfCfg := beforePoRTest(t, testEnv, "por-workflowV2-billing", PoRWFV2Location) porWfCfg.FeedIDs = []string{porWfCfg.FeedIDs[0]} ExecutePoRTest(t, testEnv, priceProvider, porWfCfg, true) } @@ -242,6 +242,12 @@ func Test_CRE_V2_Solana_Suite(t *testing.T) { }) } +func Test_CRE_V2_Aptos_Suite(t *testing.T) { + testEnv := t_helpers.SetupTestEnvironmentWithConfig(t, t_helpers.GetTestConfig(t, "/configs/workflow-gateway-don-aptos.toml")) + t.Run("[v2] Aptos", func(t *testing.T) { + ExecuteAptosTest(t, testEnv) + }) +} func Test_CRE_V2_HTTP_Action_Regression_Suite(t *testing.T) { testEnv := t_helpers.SetupTestEnvironmentWithConfig(t, t_helpers.GetDefaultTestConfig(t)) diff --git a/system-tests/tests/smoke/cre/v2_aptos_capability_test.go b/system-tests/tests/smoke/cre/v2_aptos_capability_test.go new file mode 100644 index 00000000000..f2c63fa4537 --- /dev/null +++ b/system-tests/tests/smoke/cre/v2_aptos_capability_test.go @@ -0,0 +1,740 @@ +package cre + +import ( + "context" + "encoding/binary" + "encoding/hex" + "errors" + "fmt" + "os" + "regexp" + "strings" + "testing" + "time" + + aptoslib "github.com/aptos-labs/aptos-go-sdk" + aptoscrypto "github.com/aptos-labs/aptos-go-sdk/crypto" + "github.com/ethereum/go-ethereum/common" + "github.com/rs/zerolog" + "github.com/stretchr/testify/require" + + aptosbind "github.com/smartcontractkit/chainlink-aptos/bindings/bind" + aptosdatafeeds "github.com/smartcontractkit/chainlink-aptos/bindings/data_feeds" + aptosplatformsecondary "github.com/smartcontractkit/chainlink-aptos/bindings/platform_secondary" + "github.com/smartcontractkit/chainlink-testing-framework/framework" + "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" + + commonevents "github.com/smartcontractkit/chainlink-protos/workflows/go/common" + workflowevents "github.com/smartcontractkit/chainlink-protos/workflows/go/events" + + crelib "github.com/smartcontractkit/chainlink/system-tests/lib/cre" + "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains" + blockchains_aptos "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains/aptos" + blockchains_evm "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains/evm" + aptosfeature "github.com/smartcontractkit/chainlink/system-tests/lib/cre/features/aptos" + aptoswrite_config "github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptoswrite/config" + aptoswriteroundtrip_config "github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/config" + t_helpers "github.com/smartcontractkit/chainlink/system-tests/tests/test-helpers" + "github.com/smartcontractkit/chainlink/system-tests/tests/test-helpers/configuration" +) + +const aptosLocalMaxGasAmount uint64 = 200_000 +const aptosWorkerFundingAmountOctas uint64 = 1_000_000_000_000 +const aptosWorkerMinBalanceOctas uint64 = 100_000_000 + +// ExecuteAptosTest runs the Aptos CRE suite with the minimum CI scenarios that +// still cover the end-to-end happy path and the expected-failure path. +func ExecuteAptosTest(t *testing.T, tenv *configuration.TestEnvironment) { + executeAptosScenarios(t, tenv, aptosDefaultScenarios()) +} + +type aptosScenario struct { + name string + run func( + t *testing.T, + tenv *configuration.TestEnvironment, + aptosChain blockchains.Blockchain, + userLogsCh <-chan *workflowevents.UserLogs, + baseMessageCh <-chan *commonevents.BaseMessage, + ) +} + +func aptosDefaultScenarios() []aptosScenario { + return []aptosScenario{ + {name: "Aptos Write Read Roundtrip", run: ExecuteAptosWriteReadRoundtripTest}, + {name: "Aptos Write Expected Failure", run: ExecuteAptosWriteExpectedFailureTest}, + } +} + +func executeAptosScenarios(t *testing.T, tenv *configuration.TestEnvironment, scenarios []aptosScenario) { + creEnv := tenv.CreEnvironment + require.NotEmpty(t, creEnv.Blockchains, "Aptos suite expects at least one blockchain in the environment") + + var aptosChain blockchains.Blockchain + for _, bc := range creEnv.Blockchains { + if bc.IsFamily(blockchain.FamilyAptos) { + aptosChain = bc + break + } + } + require.NotNil(t, aptosChain, "Aptos suite expects an Aptos chain in the environment (use config workflow-gateway-don-aptos.toml)") + + lggr := framework.L + userLogsCh := make(chan *workflowevents.UserLogs, 1000) + baseMessageCh := make(chan *commonevents.BaseMessage, 1000) + + server := t_helpers.StartChipTestSink(t, t_helpers.GetLoggingPublishFn(lggr, userLogsCh, baseMessageCh, "./logs/aptos_capability_workflow_test.log")) + t.Cleanup(func() { + server.Shutdown(t.Context()) + close(userLogsCh) + close(baseMessageCh) + }) + + for _, scenario := range scenarios { + t.Run(scenario.name, func(t *testing.T) { + scenario.run(t, tenv, aptosChain, userLogsCh, baseMessageCh) + }) + } +} + +// ExecuteAptosReadTest deploys a workflow that reads 0x1::coin::name() on Aptos local devnet +// in a consensus read step and asserts the expected value. +func ExecuteAptosReadTest( + t *testing.T, + tenv *configuration.TestEnvironment, + aptosChain blockchains.Blockchain, + userLogsCh <-chan *workflowevents.UserLogs, + baseMessageCh <-chan *commonevents.BaseMessage, +) { + lggr := framework.L + + // Fixed name so re-runs against the same DON overwrite the same workflow instead of accumulating multiple (e.g. aptos-read-workflow-4838 and aptos-read-workflow-5736). + const workflowName = "aptos-read-workflow" + workflowConfig := t_helpers.AptosReadWorkflowConfig{ + ChainSelector: aptosChain.ChainSelector(), + WorkflowName: workflowName, + ExpectedCoinName: "Aptos Coin", // 0x1::coin::name<0x1::aptos_coin::AptosCoin>() on local devnet + } + + const workflowFileLocation = "./aptos/aptosread/main.go" + t_helpers.CompileAndDeployWorkflow(t, tenv, lggr, workflowName, &workflowConfig, workflowFileLocation) + + expectedLog := "Aptos read consensus succeeded" + t_helpers.WatchWorkflowLogs(t, lggr, userLogsCh, baseMessageCh, t_helpers.WorkflowEngineInitErrorLog, expectedLog, 4*time.Minute) + lggr.Info().Str("expected_log", expectedLog).Msg("Aptos read capability test passed") +} + +func ExecuteAptosWriteTest( + t *testing.T, + tenv *configuration.TestEnvironment, + aptosChain blockchains.Blockchain, + userLogsCh <-chan *workflowevents.UserLogs, + baseMessageCh <-chan *commonevents.BaseMessage, +) { + lggr := framework.L + scenario := prepareAptosWriteScenario(t, tenv, aptosChain) + + const workflowName = "aptos-write-workflow" + workflowConfig := aptoswrite_config.Config{ + ChainSelector: scenario.chainSelector, + WorkflowName: workflowName, + ReceiverHex: scenario.receiverHex, + RequiredSignatures: scenario.requiredSignatures, + ReportPayloadHex: scenario.reportPayloadHex, + // Keep within the current local Aptos transaction max-gas bound. + MaxGasAmount: aptosLocalMaxGasAmount, + GasUnitPrice: 100, + } + + const workflowFileLocation = "./aptos/aptoswrite/main.go" + ensureAptosWriteWorkersFunded(t, aptosChain, scenario.writeDon) + t_helpers.CompileAndDeployWorkflow(t, tenv, lggr, workflowName, &workflowConfig, workflowFileLocation) + + txHash := waitForAptosWriteSuccessLogAndTxHash(t, lggr, userLogsCh, baseMessageCh, 4*time.Minute) + assertAptosReceiverUpdatedOnChain(t, aptosChain, scenario.receiverHex, scenario.expectedBenchmarkValue) + assertAptosWriteTxOnChain(t, aptosChain, txHash, scenario.receiverHex) + lggr.Info(). + Str("tx_hash", txHash). + Str("receiver", scenario.receiverHex). + Msg("Aptos write capability test passed with onchain verification") +} + +func ExecuteAptosWriteReadRoundtripTest( + t *testing.T, + tenv *configuration.TestEnvironment, + aptosChain blockchains.Blockchain, + userLogsCh <-chan *workflowevents.UserLogs, + baseMessageCh <-chan *commonevents.BaseMessage, +) { + lggr := framework.L + scenario := prepareAptosRoundtripScenario(t, tenv, aptosChain) + + const workflowName = "aptos-write-read-roundtrip-workflow" + roundtripCfg := aptoswriteroundtrip_config.Config{ + ChainSelector: scenario.chainSelector, + WorkflowName: workflowName, + ReceiverHex: scenario.receiverHex, + RequiredSignatures: scenario.requiredSignatures, + ReportPayloadHex: scenario.reportPayloadHex, + MaxGasAmount: aptosLocalMaxGasAmount, + GasUnitPrice: 100, + FeedIDHex: scenario.feedIDHex, + ExpectedBenchmark: scenario.expectedBenchmarkValue, + } + + ensureAptosWriteWorkersFunded(t, aptosChain, scenario.writeDon) + t_helpers.CompileAndDeployWorkflow(t, tenv, lggr, workflowName, &roundtripCfg, "./aptos/aptoswriteroundtrip/main.go") + t_helpers.WatchWorkflowLogs( + t, + lggr, + userLogsCh, + baseMessageCh, + t_helpers.WorkflowEngineInitErrorLog, + "Aptos write/read consensus succeeded", + 4*time.Minute, + ) + lggr.Info(). + Str("receiver", scenario.receiverHex). + Uint64("expected_benchmark", scenario.expectedBenchmarkValue). + Str("feed_id", scenario.feedIDHex). + Msg("Aptos write/read roundtrip capability test passed") +} + +func ExecuteAptosWriteExpectedFailureTest( + t *testing.T, + tenv *configuration.TestEnvironment, + aptosChain blockchains.Blockchain, + userLogsCh <-chan *workflowevents.UserLogs, + baseMessageCh <-chan *commonevents.BaseMessage, +) { + lggr := framework.L + scenario := prepareAptosWriteScenario(t, tenv, aptosChain) + + const workflowName = "aptos-write-expected-failure-workflow" + workflowConfig := aptoswrite_config.Config{ + ChainSelector: scenario.chainSelector, + WorkflowName: workflowName, + ReceiverHex: "0x0", // Intentionally invalid write receiver to force onchain failure path. + RequiredSignatures: scenario.requiredSignatures, + ReportPayloadHex: scenario.reportPayloadHex, + MaxGasAmount: aptosLocalMaxGasAmount, + GasUnitPrice: 100, + ExpectFailure: true, + } + + const workflowFileLocation = "./aptos/aptoswrite/main.go" + ensureAptosWriteWorkersFunded(t, aptosChain, scenario.writeDon) + t_helpers.CompileAndDeployWorkflow(t, tenv, lggr, workflowName, &workflowConfig, workflowFileLocation) + + txHash := waitForAptosWriteExpectedFailureLogAndTxHash(t, lggr, userLogsCh, baseMessageCh, 4*time.Minute) + assertAptosWriteFailureTxOnChain(t, aptosChain, txHash) + + lggr.Info(). + Str("tx_hash", txHash). + Msg("Aptos expected write-failure workflow test passed") +} + +type aptosWriteScenario struct { + chainSelector uint64 + receiverHex string + reportPayloadHex string + feedIDHex string + expectedBenchmarkValue uint64 + requiredSignatures int + writeDon *crelib.Don +} + +func prepareAptosWriteScenario(t *testing.T, tenv *configuration.TestEnvironment, aptosChain blockchains.Blockchain) aptosWriteScenario { + return prepareAptosWriteScenarioWithBenchmark(t, tenv, aptosChain, aptosBenchmarkFeedID(), 123456789) +} + +func prepareAptosRoundtripScenario(t *testing.T, tenv *configuration.TestEnvironment, aptosChain blockchains.Blockchain) aptosWriteScenario { + return prepareAptosWriteScenarioWithBenchmark(t, tenv, aptosChain, aptosRoundtripFeedID(), 987654321) +} + +func prepareAptosWriteScenarioWithBenchmark( + t *testing.T, + tenv *configuration.TestEnvironment, + aptosChain blockchains.Blockchain, + feedID []byte, + expectedBenchmark uint64, +) aptosWriteScenario { + t.Helper() + + forwarderHex, ok := aptosfeature.ForwarderAddress(tenv.CreEnvironment.CldfEnvironment.DataStore, aptosChain.ChainSelector()) + require.True(t, ok, "Aptos write test requires forwarder address in datastore for chainSelector=%d", aptosChain.ChainSelector()) + require.NotEmpty(t, forwarderHex, "Aptos write test requires forwarder address for chainSelector=%d", aptosChain.ChainSelector()) + require.False(t, isZeroAptosAddress(forwarderHex), "Aptos write test requires non-zero forwarder address for chainSelector=%d", aptosChain.ChainSelector()) + + writeDon := findWriteAptosDonForChain(t, tenv, aptosChain.ChainID()) + workers, workerErr := writeDon.Workers() + require.NoError(t, workerErr, "failed to list Aptos write DON workers") + f := (len(workers) - 1) / 3 + require.GreaterOrEqual(t, f, 1, "Aptos write DON requires f>=1") + + return aptosWriteScenario{ + chainSelector: aptosChain.ChainSelector(), + receiverHex: deployAptosDataFeedsReceiverForWrite(t, tenv, aptosChain, forwarderHex, feedID), + reportPayloadHex: hex.EncodeToString(buildAptosDataFeedsBenchmarkPayloadFor(feedID, expectedBenchmark)), + feedIDHex: hex.EncodeToString(feedID), + expectedBenchmarkValue: expectedBenchmark, + requiredSignatures: f + 1, + writeDon: writeDon, + } +} + +func findWriteAptosDonForChain(t *testing.T, tenv *configuration.TestEnvironment, chainID uint64) *crelib.Don { + t.Helper() + require.NotNil(t, tenv.Dons, "test environment DON metadata is required") + + for _, don := range tenv.Dons.List() { + if !don.HasFlag("write-aptos") { + continue + } + chainIDs, err := don.GetEnabledChainIDsForCapability("write-aptos") + require.NoError(t, err, "failed to read enabled chain ids for DON %q", don.Name) + for _, id := range chainIDs { + if id == chainID { + return don + } + } + } + + require.FailNowf(t, "missing Aptos write DON", "could not find write-aptos DON for chainID=%d", chainID) + return nil +} + +func isZeroAptosAddress(addr string) bool { + trimmed := strings.TrimPrefix(strings.ToLower(strings.TrimSpace(addr)), "0x") + if trimmed == "" { + return true + } + for _, ch := range trimmed { + if ch != '0' { + return false + } + } + return true +} + +var aptosTxHashInLogRe = regexp.MustCompile(`txHash=([^\s"]+)`) + +func waitForAptosWriteSuccessLogAndTxHash( + t *testing.T, + lggr zerolog.Logger, + userLogsCh <-chan *workflowevents.UserLogs, + baseMessageCh <-chan *commonevents.BaseMessage, + timeout time.Duration, +) string { + t.Helper() + return waitForAptosLogAndTxHash(t, lggr, userLogsCh, baseMessageCh, "Aptos write capability succeeded", timeout) +} + +func waitForAptosWriteExpectedFailureLogAndTxHash( + t *testing.T, + lggr zerolog.Logger, + userLogsCh <-chan *workflowevents.UserLogs, + baseMessageCh <-chan *commonevents.BaseMessage, + timeout time.Duration, +) string { + t.Helper() + return waitForAptosLogAndTxHash(t, lggr, userLogsCh, baseMessageCh, "Aptos write failure observed as expected", timeout) +} + +func waitForAptosLogAndTxHash( + t *testing.T, + lggr zerolog.Logger, + userLogsCh <-chan *workflowevents.UserLogs, + baseMessageCh <-chan *commonevents.BaseMessage, + expectedLog string, + timeout time.Duration, +) string { + t.Helper() + + ctx, cancelFn := context.WithTimeoutCause(t.Context(), timeout, fmt.Errorf("failed to find Aptos workflow log with non-empty tx hash: %s", expectedLog)) + defer cancelFn() + + cancelCtx, cancelCauseFn := context.WithCancelCause(ctx) + defer cancelCauseFn(nil) + + go func() { + t_helpers.FailOnBaseMessage(cancelCtx, cancelCauseFn, t, lggr, baseMessageCh, t_helpers.WorkflowEngineInitErrorLog) + }() + + mismatchCount := 0 + for { + select { + case <-cancelCtx.Done(): + require.NoError(t, context.Cause(cancelCtx), "failed to observe Aptos log with non-empty tx hash: %s", expectedLog) + return "" + case logs := <-userLogsCh: + for _, line := range logs.LogLines { + if !strings.Contains(line.Message, expectedLog) { + mismatchCount++ + if mismatchCount%20 == 0 { + lggr.Warn(). + Str("expected_log", expectedLog). + Str("found_message", strings.TrimSpace(line.Message)). + Int("mismatch_count", mismatchCount). + Msg("[soft assertion] Received UserLogs messages, but none match expected log yet") + } + continue + } + + matches := aptosTxHashInLogRe.FindStringSubmatch(line.Message) + if len(matches) == 2 { + txHash := normalizeTxHash(matches[1]) + if txHash != "" { + return txHash + } + } + + lggr.Warn(). + Str("message", strings.TrimSpace(line.Message)). + Str("expected_log", expectedLog). + Msg("[soft assertion] Matched Aptos log without non-empty tx hash; waiting for another match") + } + } + } +} + +func assertAptosWriteFailureTxOnChain(t *testing.T, aptosChain blockchains.Blockchain, txHash string) { + t.Helper() + + bc, ok := aptosChain.(*blockchains_aptos.Blockchain) + require.True(t, ok, "expected aptos blockchain type") + + nodeURL := bc.CtfOutput().Nodes[0].ExternalHTTPUrl + require.NotEmpty(t, nodeURL, "Aptos node URL is required for onchain verification") + nodeURL, err := aptosfeature.NormalizeNodeURL(nodeURL) + require.NoError(t, err, "failed to normalize Aptos node URL for onchain verification") + + chainID := bc.ChainID() + require.LessOrEqual(t, chainID, uint64(255), "Aptos chain id must fit in uint8") + chainIDUint8, err := aptosfeature.ChainIDUint8(chainID) + require.NoError(t, err, "failed to convert Aptos chain id") + + client, err := aptoslib.NewNodeClient(nodeURL, chainIDUint8) + require.NoError(t, err, "failed to create Aptos client") + + tx, err := client.WaitForTransaction(txHash) + require.NoError(t, err, "failed waiting for Aptos tx by hash") + require.False(t, tx.Success, "Aptos tx must fail in expected-failure workflow; vm_status=%s", tx.VmStatus) +} + +func assertAptosWriteTxOnChain(t *testing.T, aptosChain blockchains.Blockchain, txHash string, expectedReceiver string) { + t.Helper() + + bc, ok := aptosChain.(*blockchains_aptos.Blockchain) + require.True(t, ok, "expected aptos blockchain type") + + nodeURL := bc.CtfOutput().Nodes[0].ExternalHTTPUrl + require.NotEmpty(t, nodeURL, "Aptos node URL is required for onchain verification") + nodeURL, err := aptosfeature.NormalizeNodeURL(nodeURL) + require.NoError(t, err, "failed to normalize Aptos node URL for onchain verification") + + chainID := bc.ChainID() + require.LessOrEqual(t, chainID, uint64(255), "Aptos chain id must fit in uint8") + chainIDUint8, err := aptosfeature.ChainIDUint8(chainID) + require.NoError(t, err, "failed to convert Aptos chain id") + + client, err := aptoslib.NewNodeClient(nodeURL, chainIDUint8) + require.NoError(t, err, "failed to create Aptos client") + + tx, err := client.WaitForTransaction(txHash) + require.NoError(t, err, "failed waiting for Aptos tx by hash") + require.True(t, tx.Success, "Aptos tx must be successful; vm_status=%s", tx.VmStatus) + + expectedReceiverNorm := normalizeTxHashLikeHex(expectedReceiver) + found := false + for _, evt := range tx.Events { + if !strings.HasSuffix(evt.Type, "::forwarder::ReportProcessed") { + continue + } + receiverVal, ok := evt.Data["receiver"].(string) + require.True(t, ok, "ReportProcessed event receiver field must be a string") + if normalizeTxHashLikeHex(receiverVal) != expectedReceiverNorm { + continue + } + _, hasExecutionID := evt.Data["workflow_execution_id"] + _, hasReportID := evt.Data["report_id"] + require.True(t, hasExecutionID, "ReportProcessed must include workflow_execution_id") + require.True(t, hasReportID, "ReportProcessed must include report_id") + found = true + break + } + require.True(t, found, "expected ReportProcessed event for receiver %s in tx %s", expectedReceiverNorm, txHash) +} + +func assertAptosReceiverUpdatedOnChain( + t *testing.T, + aptosChain blockchains.Blockchain, + receiverHex string, + expectedBenchmark uint64, +) { + t.Helper() + + aptosBC, ok := aptosChain.(*blockchains_aptos.Blockchain) + require.True(t, ok, "expected aptos blockchain type") + nodeURL := aptosBC.CtfOutput().Nodes[0].ExternalHTTPUrl + require.NotEmpty(t, nodeURL, "Aptos node URL is required for onchain verification") + nodeURL, err := aptosfeature.NormalizeNodeURL(nodeURL) + require.NoError(t, err, "failed to normalize Aptos node URL for onchain verification") + + chainID := aptosBC.ChainID() + require.LessOrEqual(t, chainID, uint64(255), "Aptos chain id must fit in uint8") + chainIDUint8, err := aptosfeature.ChainIDUint8(chainID) + require.NoError(t, err, "failed to convert Aptos chain id") + client, err := aptoslib.NewNodeClient(nodeURL, chainIDUint8) + require.NoError(t, err, "failed to create Aptos client") + + var receiverAddr aptoslib.AccountAddress + err = receiverAddr.ParseStringRelaxed(receiverHex) + require.NoError(t, err, "failed to parse Aptos receiver address") + + dataFeeds := aptosdatafeeds.Bind(receiverAddr, client) + feedID := aptosBenchmarkFeedID() + feedIDHex := hex.EncodeToString(feedID) + + require.Eventually(t, func() bool { + feeds, bErr := dataFeeds.Registry().GetFeeds(&aptosbind.CallOpts{}) + if bErr != nil || len(feeds) == 0 { + return false + } + for _, feed := range feeds { + if hex.EncodeToString(feed.FeedId) != feedIDHex { + continue + } + if feed.Feed.Benchmark == nil { + return false + } + return feed.Feed.Benchmark.Uint64() == expectedBenchmark + } + return false + }, 2*time.Minute, 3*time.Second, "expected benchmark value %d not observed onchain for receiver %s", expectedBenchmark, receiverHex) +} + +func normalizeTxHash(input string) string { + s := strings.TrimSpace(strings.ToLower(input)) + if s == "" { + return "" + } + if strings.HasPrefix(s, "0x") { + return s + } + return "0x" + s +} + +func normalizeTxHashLikeHex(input string) string { + s := strings.TrimSpace(strings.ToLower(input)) + s = strings.TrimPrefix(s, "0x") + s = strings.TrimLeft(s, "0") + if s == "" { + return "0x0" + } + return "0x" + s +} + +func deployAptosDataFeedsReceiverForWrite( + t *testing.T, + tenv *configuration.TestEnvironment, + aptosChain blockchains.Blockchain, + primaryForwarderHex string, + feedID []byte, +) string { + t.Helper() + + aptosBC, ok := aptosChain.(*blockchains_aptos.Blockchain) + require.True(t, ok, "expected aptos blockchain type") + nodeURL := aptosBC.CtfOutput().Nodes[0].ExternalHTTPUrl + require.NotEmpty(t, nodeURL, "Aptos node URL is required for receiver deployment") + nodeURL, err := aptosfeature.NormalizeNodeURL(nodeURL) + require.NoError(t, err, "failed to normalize Aptos node URL for receiver deployment") + containerName := aptosBC.CtfOutput().ContainerName + + chainID := aptosBC.ChainID() + require.LessOrEqual(t, chainID, uint64(255), "Aptos chain id must fit in uint8") + chainIDUint8, err := aptosfeature.ChainIDUint8(chainID) + require.NoError(t, err, "failed to convert Aptos chain id") + client, err := aptoslib.NewNodeClient(nodeURL, chainIDUint8) + require.NoError(t, err, "failed to create Aptos client") + + deployer, err := aptosDeployerAccount() + require.NoError(t, err, "failed to create Aptos deployer account") + + require.NoError( + t, + aptosfeature.FundAccountBestEffort(t.Context(), framework.L, client, nodeURL, containerName, deployer.AccountAddress(), aptosWorkerMinBalanceOctas, aptosWorkerFundingAmountOctas), + "failed to fund Aptos deployer account", + ) + require.NoError( + t, + aptosfeature.WaitForAccountVisible(t.Context(), client, deployer.AccountAddress(), 45*time.Second), + "Aptos deployer account must be visible before deploy", + ) + + var primaryForwarderAddr aptoslib.AccountAddress + err = primaryForwarderAddr.ParseStringRelaxed(primaryForwarderHex) + require.NoError(t, err, "failed to parse primary forwarder address") + + owner := deployer.AccountAddress() + secondaryAddress, secondaryTx, _, err := aptosplatformsecondary.DeployToObject(deployer, client, owner) + require.NoError(t, err, "failed to deploy Aptos secondary platform package") + require.NoError(t, aptosfeature.WaitForTransactionSuccess(client, secondaryTx.Hash, "platform_secondary deployment")) + + dataFeedsAddress, dataFeedsTx, dataFeeds, err := aptosdatafeeds.DeployToObject( + deployer, + client, + owner, + primaryForwarderAddr, + owner, + secondaryAddress, + ) + require.NoError(t, err, "failed to deploy Aptos data feeds receiver package") + require.NoError(t, aptosfeature.WaitForTransactionSuccess(client, dataFeedsTx.Hash, "data_feeds deployment")) + + workflowOwner := workflowRegistryOwnerBytes(t, tenv) + tx, err := dataFeeds.Registry().SetWorkflowConfig( + &aptosbind.TransactOpts{Signer: deployer}, + [][]byte{workflowOwner}, + [][]byte{}, + ) + require.NoError(t, err, "failed to set data feeds workflow config") + require.NoError(t, aptosfeature.WaitForTransactionSuccess(client, tx.Hash, "data_feeds set_workflow_config")) + + // Configure the feed that the write workflow will update. + // Without this, registry::perform_update emits WriteSkippedFeedNotSet and benchmark remains unchanged. + tx, err = dataFeeds.Registry().SetFeeds( + &aptosbind.TransactOpts{Signer: deployer}, + [][]byte{feedID}, + []string{"CRE-BENCHMARK"}, + []byte{0x99}, + ) + require.NoError(t, err, "failed to set data feeds feed config") + require.NoError(t, aptosfeature.WaitForTransactionSuccess(client, tx.Hash, "data_feeds set_feeds")) + + return dataFeedsAddress.StringLong() +} + +func aptosDeployerAccount() (*aptoslib.Account, error) { + const defaultAptosDeployerKey = "d477c65f88ed9e6d4ec6e2014755c3cfa3e0c44e521d0111a02868c5f04c41d4" + keyHex := strings.TrimSpace(os.Getenv("CRE_APTOS_DEPLOYER_PRIVATE_KEY")) + if keyHex == "" { + keyHex = defaultAptosDeployerKey + } + if keyHex == "" { + return nil, errors.New("empty Aptos deployer key") + } + keyHex = strings.TrimPrefix(keyHex, "0x") + var privateKey aptoscrypto.Ed25519PrivateKey + if err := privateKey.FromHex(keyHex); err != nil { + return nil, fmt.Errorf("parse Aptos deployer private key: %w", err) + } + return aptoslib.NewAccountFromSigner(&privateKey) +} + +func ensureAptosWriteWorkersFunded(t *testing.T, aptosChain blockchains.Blockchain, writeDon *crelib.Don) { + t.Helper() + + aptosBC, ok := aptosChain.(*blockchains_aptos.Blockchain) + require.True(t, ok, "expected aptos blockchain type") + + nodeURL := aptosBC.CtfOutput().Nodes[0].ExternalHTTPUrl + require.NotEmpty(t, nodeURL, "Aptos node URL is required for worker funding") + nodeURL, err := aptosfeature.NormalizeNodeURL(nodeURL) + require.NoError(t, err, "failed to normalize Aptos node URL for worker funding") + + chainID := aptosBC.ChainID() + require.LessOrEqual(t, chainID, uint64(255), "Aptos chain id must fit in uint8") + chainIDUint8, err := aptosfeature.ChainIDUint8(chainID) + require.NoError(t, err, "failed to convert Aptos chain id") + client, err := aptoslib.NewNodeClient(nodeURL, chainIDUint8) + require.NoError(t, err, "failed to create Aptos client") + + containerName := aptosBC.CtfOutput().ContainerName + workers, workerErr := writeDon.Workers() + require.NoError(t, workerErr, "failed to list Aptos write DON workers for funding") + require.NotEmpty(t, workers, "Aptos write DON workers list is empty") + + for _, worker := range workers { + addresses, fetchErr := crelib.AptosAccountsForNode(t.Context(), worker) + require.NoError(t, fetchErr, "failed to fetch Aptos key for worker %q", worker.Name) + require.NotEmpty(t, addresses, "missing Aptos key for worker %q", worker.Name) + for _, rawAddress := range addresses { + rawAddress = strings.TrimSpace(rawAddress) + if rawAddress == "" { + continue + } + + var account aptoslib.AccountAddress + parseErr := account.ParseStringRelaxed(rawAddress) + require.NoError(t, parseErr, "failed to parse Aptos worker account for worker %q", worker.Name) + + require.NoError( + t, + aptosfeature.FundAccountBestEffort(t.Context(), framework.L, client, nodeURL, containerName, account, aptosWorkerMinBalanceOctas, aptosWorkerFundingAmountOctas), + "failed to fund Aptos worker account %s for worker %q", + account.StringLong(), + worker.Name, + ) + require.NoError( + t, + aptosfeature.WaitForAccountVisible(t.Context(), client, account, 45*time.Second), + "Aptos worker account %s must be visible/funded before write workflow for worker %q", + account.StringLong(), + worker.Name, + ) + } + } +} + +func workflowRegistryOwnerBytes(t *testing.T, tenv *configuration.TestEnvironment) []byte { + t.Helper() + registryChain, ok := tenv.CreEnvironment.Blockchains[0].(*blockchains_evm.Blockchain) + require.True(t, ok, "registry chain must be EVM") + rootOwner := registryChain.SethClient.MustGetRootKeyAddress() + return common.HexToAddress(rootOwner.Hex()).Bytes() +} + +func buildAptosDataFeedsBenchmarkPayloadFor(feedID []byte, benchmark uint64) []byte { + // ABI-like benchmark payload expected by data_feeds::registry::parse_raw_report + // [offset=32][count=1][feed_id(32)][report(64)] + const ( + offsetToArray = uint64(32) + reportCount = uint64(1) + timestamp = uint64(1700000000) + ) + + report := make([]byte, 64) + writeU256BE(report[0:32], timestamp) + writeU256BE(report[32:64], benchmark) + + out := make([]byte, 0, 160) + out = appendU256BE(out, offsetToArray) + out = appendU256BE(out, reportCount) + out = append(out, feedID...) + out = append(out, report...) + return out +} + +func aptosBenchmarkFeedID() []byte { + feedID := make([]byte, 32) + feedID[31] = 1 + return feedID +} + +func aptosRoundtripFeedID() []byte { + feedID := make([]byte, 32) + feedID[31] = 2 + return feedID +} + +func appendU256BE(dst []byte, v uint64) []byte { + buf := make([]byte, 32) + binary.BigEndian.PutUint64(buf[24:], v) + return append(dst, buf...) +} + +func writeU256BE(dst []byte, v uint64) { + binary.BigEndian.PutUint64(dst[24:], v) +} diff --git a/system-tests/tests/test-helpers/before_suite.go b/system-tests/tests/test-helpers/before_suite.go index c1f0e0938bc..dd397986816 100644 --- a/system-tests/tests/test-helpers/before_suite.go +++ b/system-tests/tests/test-helpers/before_suite.go @@ -294,7 +294,7 @@ func GetTestConfig(t *testing.T, configPath string) *ttypes.TestConfig { return &ttypes.TestConfig{ RelativePathToRepoRoot: relativePathToRepoRoot, EnvironmentDirPath: environmentDirPath, - EnvironmentConfigPath: filepath.Join(environmentDirPath, configPath), // change to your desired config, if you want to use another topology + EnvironmentConfigPath: filepath.Join(environmentDirPath, configPath), EnvironmentStateFile: filepath.Join(environmentDirPath, envconfig.StateDirname, envconfig.LocalCREStateFilename), ChipIngressGRPCPort: chipingressset.DEFAULT_CHIP_INGRESS_GRPC_PORT, } @@ -303,7 +303,6 @@ func GetTestConfig(t *testing.T, configPath string) *ttypes.TestConfig { func getEnvironmentConfig(t *testing.T) *envconfig.Config { t.Helper() - // we call our own Load function because it executes a couple of crucial extra input transformations in := &envconfig.Config{} err := in.Load(os.Getenv("CTF_CONFIGS")) require.NoError(t, err, "couldn't load environment state") @@ -336,18 +335,13 @@ func setConfigurationIfMissing(configName string) error { func createEnvironmentIfNotExists(ctx context.Context, relativePathToRepoRoot, environmentDir string, flags ...string) error { if !envconfig.LocalCREStateFileExists(relativePathToRepoRoot) { - framework.L.Info().Str("CTF_CONFIGS", os.Getenv("CTF_CONFIGS")).Str("local CRE state file", envconfig.MustLocalCREStateFileAbsPath(relativePathToRepoRoot)).Msg("Local CRE state file does not exist, starting environment...") - - args := []string{"run", ".", "env", "start"} - args = append(args, flags...) - - cmd := exec.CommandContext(ctx, "go", args...) - cmd.Dir = environmentDir - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmdErr := cmd.Run() - if cmdErr != nil { - return errors.Wrap(cmdErr, "failed to start environment") + framework.L.Info(). + Str("CTF_CONFIGS", os.Getenv("CTF_CONFIGS")). + Str("local CRE state file", envconfig.MustLocalCREStateFileAbsPath(relativePathToRepoRoot)). + Msg("Local CRE state file does not exist, starting environment...") + + if err := startEnvironment(ctx, environmentDir, flags...); err != nil { + return err } } @@ -397,3 +391,17 @@ func setCldfEVMDeployerKey(env *cldf.Environment, chainSelector uint64, deployer env.BlockChains = cldf_chain.NewBlockChainsFromSlice(chainCopies) return nil } + +func startEnvironment(ctx context.Context, environmentDir string, flags ...string) error { + args := []string{"run", ".", "env", "start"} + args = append(args, flags...) + + cmd := exec.CommandContext(ctx, "go", args...) + cmd.Dir = environmentDir + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return errors.Wrap(err, "failed to start environment") + } + return nil +} diff --git a/system-tests/tests/test-helpers/t_helpers.go b/system-tests/tests/test-helpers/t_helpers.go index 257647f227f..f7c3af806ec 100644 --- a/system-tests/tests/test-helpers/t_helpers.go +++ b/system-tests/tests/test-helpers/t_helpers.go @@ -47,6 +47,8 @@ import ( evmread_negative_config "github.com/smartcontractkit/chainlink/system-tests/tests/regression/cre/evm/evmread-negative/config" evmwrite_negative_config "github.com/smartcontractkit/chainlink/system-tests/tests/regression/cre/evm/evmwrite-negative/config" logtrigger_negative_config "github.com/smartcontractkit/chainlink/system-tests/tests/regression/cre/evm/logtrigger-negative/config" + aptoswrite_config "github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptoswrite/config" + aptoswriteroundtrip_config "github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/config" evmread_config "github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/evm/evmread/config" logtrigger_config "github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/evm/logtrigger/config" solwrite_config "github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/solana/solwrite/config" @@ -287,6 +289,9 @@ type WorkflowConfig interface { None | portypes.WorkflowConfig | porV2types.WorkflowConfig | + AptosReadWorkflowConfig | + aptoswrite_config.Config | + aptoswriteroundtrip_config.Config | crontypes.WorkflowConfig | HTTPWorkflowConfig | consensus_negative_config.Config | @@ -310,6 +315,12 @@ type HTTPWorkflowConfig struct { URL string `json:"url"` } +type AptosReadWorkflowConfig struct { + ChainSelector uint64 `yaml:"chainSelector"` + WorkflowName string `yaml:"workflowName"` + ExpectedCoinName string `yaml:"expectedCoinName"` +} + // WorkflowRegistrationConfig holds configuration for workflow registration type WorkflowRegistrationConfig struct { WorkflowName string @@ -393,6 +404,24 @@ func workflowConfigFactory[T WorkflowConfig](t *testing.T, testLogger zerolog.Lo require.NoError(t, configErr, "failed to create PoR v2 workflow config file") testLogger.Info().Msg("PoR v2 workflow config file created.") + case *AptosReadWorkflowConfig: + workflowCfgFilePath, configErr := CreateWorkflowYamlConfigFile(workflowName, cfg) + workflowConfigFilePath = workflowCfgFilePath + require.NoError(t, configErr, "failed to create aptos read workflow config file") + testLogger.Info().Msg("Aptos read workflow config file created.") + + case *aptoswrite_config.Config: + workflowCfgFilePath, configErr := CreateWorkflowYamlConfigFile(workflowName, cfg) + workflowConfigFilePath = workflowCfgFilePath + require.NoError(t, configErr, "failed to create aptos write workflow config file") + testLogger.Info().Msg("Aptos write workflow config file created.") + + case *aptoswriteroundtrip_config.Config: + workflowCfgFilePath, configErr := CreateWorkflowYamlConfigFile(workflowName, cfg) + workflowConfigFilePath = workflowCfgFilePath + require.NoError(t, configErr, "failed to create aptos write roundtrip workflow config file") + testLogger.Info().Msg("Aptos write roundtrip workflow config file created.") + case *HTTPWorkflowConfig: workflowCfgFilePath, configErr := createHTTPWorkflowConfigFile(workflowName, cfg, outputDir) workflowConfigFilePath = workflowCfgFilePath From 0256fbb3547d48b65eff8c7ae7fa5ba3a0aacd2d Mon Sep 17 00:00:00 2001 From: cawthorne Date: Wed, 18 Mar 2026 13:12:43 +0000 Subject: [PATCH 02/34] cre: surface aptos account bootstrap errors --- system-tests/lib/cre/don.go | 21 +++++++++++++----- system-tests/lib/cre/don_test.go | 38 ++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 system-tests/lib/cre/don_test.go diff --git a/system-tests/lib/cre/don.go b/system-tests/lib/cre/don.go index 188bfd63b7f..57aae63ec55 100644 --- a/system-tests/lib/cre/don.go +++ b/system-tests/lib/cre/don.go @@ -426,11 +426,6 @@ func NewNode(ctx context.Context, name string, nodeMetadata *NodeMetadata, ctfNo } } - aptosAccounts, aptosErr := chainlinkClient.MustReadAptosAccounts() - if aptosErr == nil { - node.Addresses.AptosAddresses = aptosAccounts - } - return node, nil } @@ -591,7 +586,21 @@ func AptosAccountsForNode(_ context.Context, n *Node) ([]string, error) { if len(n.Addresses.AptosAddresses) > 0 { return append([]string(nil), n.Addresses.AptosAddresses...), nil } - return nil, fmt.Errorf("missing cached aptos addresses for node %s", n.Name) + if n.Clients.RestClient == nil { + return nil, fmt.Errorf("missing cached aptos addresses for node %s and node has no rest client", n.Name) + } + + accounts, err := n.Clients.RestClient.MustReadAptosAccounts() + if err != nil { + return nil, fmt.Errorf("fetch aptos accounts for node %s: %w", n.Name, err) + } + if len(accounts) == 0 { + return nil, fmt.Errorf("no aptos accounts found for node %s", n.Name) + } + + n.Addresses.AptosAddresses = append([]string(nil), accounts...) + + return append([]string(nil), n.Addresses.AptosAddresses...), nil } // AcceptJob accepts the job proposal for the given job proposal spec diff --git a/system-tests/lib/cre/don_test.go b/system-tests/lib/cre/don_test.go new file mode 100644 index 00000000000..2918e1603ca --- /dev/null +++ b/system-tests/lib/cre/don_test.go @@ -0,0 +1,38 @@ +package cre + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestAptosAccountsForNode_ReturnsCachedAddresses(t *testing.T) { + t.Parallel() + + node := &Node{ + Name: "node-1", + Addresses: Addresses{ + AptosAddresses: []string{"0x1", "0x2"}, + }, + } + + addresses, err := AptosAccountsForNode(context.Background(), node) + require.NoError(t, err) + require.Equal(t, []string{"0x1", "0x2"}, addresses) + + addresses[0] = "0xdead" + require.Equal(t, []string{"0x1", "0x2"}, node.Addresses.AptosAddresses) +} + +func TestAptosAccountsForNode_RequiresClientWhenCacheMissing(t *testing.T) { + t.Parallel() + + node := &Node{ + Name: "node-1", + } + + _, err := AptosAccountsForNode(context.Background(), node) + require.Error(t, err) + require.ErrorContains(t, err, "missing cached aptos addresses for node node-1 and node has no rest client") +} From ac0276e8fc2eb993c7933e2e3718275d9a7d6a0b Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 19 Mar 2026 12:26:45 +0000 Subject: [PATCH 03/34] plugins: narrow private capability refs --- plugins/plugins.private.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/plugins.private.yaml b/plugins/plugins.private.yaml index d51cd2635de..05b49902fa0 100644 --- a/plugins/plugins.private.yaml +++ b/plugins/plugins.private.yaml @@ -23,7 +23,7 @@ plugins: installPath: "." consensus: - moduleURI: "github.com/smartcontractkit/capabilities/consensus" - gitRef: "v0.0.2-0.20260317221214-ef3252b7b433" + gitRef: "bab47549446cf8a47093b983419dbd3f06b40329" installPath: "." workflowevent: - enabled: false @@ -48,7 +48,7 @@ plugins: installPath: "." aptos: - moduleURI: "github.com/smartcontractkit/capabilities/chain_capabilities/aptos" - gitRef: "v0.0.0-20260317221214-ef3252b7b433" + gitRef: "bab47549446cf8a47093b983419dbd3f06b40329" installPath: "." mock: - moduleURI: "github.com/smartcontractkit/capabilities/mock" From 36600ae56be22df25660cc545eff4d43ae872168 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 19 Mar 2026 13:03:53 +0000 Subject: [PATCH 04/34] jobs: clarify aptos oracle-factory comment --- deployment/cre/jobs/propose_job_spec.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/deployment/cre/jobs/propose_job_spec.go b/deployment/cre/jobs/propose_job_spec.go index 7afed023ca6..dba8b30e6ec 100644 --- a/deployment/cre/jobs/propose_job_spec.go +++ b/deployment/cre/jobs/propose_job_spec.go @@ -334,8 +334,7 @@ func requiresOracleFactory(template job_types.JobSpecTemplate, job pkg.StandardC return true } - // Aptos worker jobs now use the ReadContract template path. - // Preserve prior behavior from the dedicated Aptos template by enabling oracle - // factory generation whenever an Aptos chain selector is present. - return template == job_types.ReadContract && job.ChainSelectorAptos > 0 + // Aptos ReadContract jobs need oracle-factory generation so we can add the + // Aptos OCR key bundle to the multi-chain signing strategy. + return template == job_types.ReadContract && job.ChainSelectorAptos != 0 } From 95af06543f069186466d085db09b7ba88b75f4c6 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 19 Mar 2026 14:49:37 +0000 Subject: [PATCH 05/34] cre: move aptos transmitters into pre-start metadata --- core/cmd/shell_local.go | 17 +++ core/config/toml/types.go | 37 +++++ core/services/chainlink/config.go | 4 + core/services/chainlink/config_general.go | 4 + .../chainlink/config_imported_aptos_key.go | 21 +++ system-tests/lib/cre/contracts/keystone.go | 2 +- system-tests/lib/cre/don.go | 10 +- system-tests/lib/cre/don/secrets/secrets.go | 51 +++++++ .../lib/cre/don/secrets/secrets_test.go | 40 ++++++ system-tests/lib/cre/don_test.go | 21 +++ system-tests/lib/cre/environment/dons.go | 3 + .../lib/cre/environment/environment.go | 29 ---- system-tests/lib/cre/features/aptos/aptos.go | 126 +++++++----------- .../lib/cre/features/aptos/aptos_test.go | 32 ++--- system-tests/lib/cre/types.go | 19 +++ system-tests/lib/crypto/aptos.go | 49 +++++++ 16 files changed, 335 insertions(+), 130 deletions(-) create mode 100644 core/services/chainlink/config_imported_aptos_key.go create mode 100644 system-tests/lib/cre/don/secrets/secrets_test.go create mode 100644 system-tests/lib/crypto/aptos.go diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index ee7009f9bde..0eafff1cd13 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -30,6 +30,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/custmsg" "github.com/smartcontractkit/chainlink-common/pkg/logger/otelzap" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink-evm/pkg/assets" @@ -467,6 +468,10 @@ func (s *Shell) runNode(c *cli.Context) error { } } + type importedAptosKeyConfig interface { + ImportedAptosKey() coreconfig.ImportableKey + } + if s.Config.P2P().Enabled() { if s.Config.ImportedP2PKey().JSON() != "" { lggr.Debugf("Importing p2p key %s", s.Config.ImportedP2PKey().JSON()) @@ -514,6 +519,18 @@ func (s *Shell) runNode(c *cli.Context) error { } } if s.Config.AptosEnabled() { + if cfg, ok := s.Config.(importedAptosKeyConfig); ok { + if k := cfg.ImportedAptosKey(); k != nil && k.JSON() != "" { + lggr.Debug("Importing aptos key") + _, err2 := app.GetKeyStore().Aptos().Import(rootCtx, []byte(k.JSON()), k.Password()) + if errors.Is(err2, keystore.ErrKeyExists) { + lggr.Debugf("Aptos key already exists %s", k.JSON()) + } else if err2 != nil { + return s.errorOut(fmt.Errorf("error importing aptos key: %w", err2)) + } + } + } + err2 := app.GetKeyStore().Aptos().EnsureKey(rootCtx) if err2 != nil { return fmt.Errorf("failed to ensure aptos key: %w", err2) diff --git a/core/config/toml/types.go b/core/config/toml/types.go index 74984ec5db9..e47f7c16b83 100644 --- a/core/config/toml/types.go +++ b/core/config/toml/types.go @@ -146,6 +146,7 @@ type Secrets struct { Threshold ThresholdKeyShareSecrets `toml:",omitempty"` EVM EthKeys `toml:",omitempty"` // choose EVM as the TOML field name to align with relayer config convention Solana SolKeys `toml:",omitempty"` // choose Solana as the TOML field name to align with relayer config convention + Aptos AptosKey `toml:",omitempty"` P2PKey P2PKey `toml:",omitempty"` DKGRecipientKey DKGRecipientKey `toml:",omitempty"` @@ -164,6 +165,11 @@ type SolKey struct { Password *models.Secret } +type AptosKey struct { + JSON *models.Secret + Password *models.Secret +} + func (s *SolKeys) SetFrom(f *SolKeys) error { err := s.validateMerge(f) if err != nil { @@ -245,6 +251,37 @@ func (e *SolKey) ValidateConfig() (err error) { return err } +func (p *AptosKey) SetFrom(f *AptosKey) (err error) { + err = p.validateMerge(f) + if err != nil { + return err + } + if v := f.JSON; v != nil { + p.JSON = v + } + if v := f.Password; v != nil { + p.Password = v + } + return nil +} + +func (p *AptosKey) validateMerge(f *AptosKey) (err error) { + if p.JSON != nil && f.JSON != nil { + err = errors.Join(err, configutils.ErrOverride{Name: "JSON"}) + } + if p.Password != nil && f.Password != nil { + err = errors.Join(err, configutils.ErrOverride{Name: "Password"}) + } + return err +} + +func (p *AptosKey) ValidateConfig() (err error) { + if (p.JSON != nil) != (p.Password != nil) { + err = errors.Join(err, configutils.ErrInvalid{Name: "AptosKey", Value: p.JSON, Msg: "all fields must be nil or non-nil"}) + } + return err +} + type EthKeys struct { Keys []*EthKey } diff --git a/core/services/chainlink/config.go b/core/services/chainlink/config.go index 020f74a7f57..160beb95e30 100644 --- a/core/services/chainlink/config.go +++ b/core/services/chainlink/config.go @@ -417,6 +417,10 @@ func (s *Secrets) SetFrom(f *Secrets) (err error) { err = errors.Join(err, commonconfig.NamedMultiErrorList(err2, "Solana")) } + if err2 := s.Aptos.SetFrom(&f.Aptos); err2 != nil { + err = errors.Join(err, commonconfig.NamedMultiErrorList(err2, "Aptos")) + } + if err2 := s.DKGRecipientKey.SetFrom(&f.DKGRecipientKey); err2 != nil { err = errors.Join(err, commonconfig.NamedMultiErrorList(err2, "DKGRecipientKey")) } diff --git a/core/services/chainlink/config_general.go b/core/services/chainlink/config_general.go index 38a50faacfd..fc0f2a0d1ea 100644 --- a/core/services/chainlink/config_general.go +++ b/core/services/chainlink/config_general.go @@ -565,6 +565,10 @@ func (g *generalConfig) ImportedSolKeys() coreconfig.ImportableChainKeyLister { return &importedSolKeyConfigs{s: g.secrets.Solana} } +func (g *generalConfig) ImportedAptosKey() coreconfig.ImportableKey { + return &importedAptosKeyConfig{s: g.secrets.Aptos} +} + func (g *generalConfig) ImportedDKGRecipientKey() coreconfig.ImportableKey { return &importedDKGRecipientKeyConfig{s: g.secrets.DKGRecipientKey} } diff --git a/core/services/chainlink/config_imported_aptos_key.go b/core/services/chainlink/config_imported_aptos_key.go new file mode 100644 index 00000000000..cadf5bb1b43 --- /dev/null +++ b/core/services/chainlink/config_imported_aptos_key.go @@ -0,0 +1,21 @@ +package chainlink + +import "github.com/smartcontractkit/chainlink/v2/core/config/toml" + +type importedAptosKeyConfig struct { + s toml.AptosKey +} + +func (t *importedAptosKeyConfig) JSON() string { + if t.s.JSON == nil { + return "" + } + return string(*t.s.JSON) +} + +func (t *importedAptosKeyConfig) Password() string { + if t.s.Password == nil { + return "" + } + return string(*t.s.Password) +} diff --git a/system-tests/lib/cre/contracts/keystone.go b/system-tests/lib/cre/contracts/keystone.go index 81d70044527..2abc52ee379 100644 --- a/system-tests/lib/cre/contracts/keystone.go +++ b/system-tests/lib/cre/contracts/keystone.go @@ -396,7 +396,7 @@ func toDons(input cre.ConfigureCapabilityRegistryInput) (*dons, error) { capabilities = append(capabilities, enabledCapabilities...) } - // add capabilities that were passed directly via the input (from the PostDONStartup of features) + // add capabilities that were passed directly via feature startup hooks if input.DONCapabilityWithConfigs != nil && input.DONCapabilityWithConfigs[donMetadata.ID] != nil { capabilities = append(capabilities, input.DONCapabilityWithConfigs[donMetadata.ID]...) } diff --git a/system-tests/lib/cre/don.go b/system-tests/lib/cre/don.go index 57aae63ec55..13f65fd3379 100644 --- a/system-tests/lib/cre/don.go +++ b/system-tests/lib/cre/don.go @@ -426,6 +426,10 @@ func NewNode(ctx context.Context, name string, nodeMetadata *NodeMetadata, ctfNo } } + if account := nodeMetadata.AptosAccount(); account != "" { + node.Addresses.AptosAddresses = []string{account} + } + return node, nil } @@ -437,7 +441,7 @@ type JobDistributorDetails struct { type Addresses struct { AdminAddress string `toml:"admin_address" json:"admin_address"` // address used to pay for transactions, applicable only for worker nodes MultiAddress string `toml:"multi_address" json:"multi_address"` // multi address used by OCR2, applicable only for bootstrap nodes - AptosAddresses []string `toml:"aptos_addresses" json:"aptos_addresses"` // Aptos public addresses cached from the node key API + AptosAddresses []string `toml:"aptos_addresses" json:"aptos_addresses"` // Aptos public addresses cached from node metadata or the node key API } type NodeClients struct { @@ -586,6 +590,10 @@ func AptosAccountsForNode(_ context.Context, n *Node) ([]string, error) { if len(n.Addresses.AptosAddresses) > 0 { return append([]string(nil), n.Addresses.AptosAddresses...), nil } + if n.Keys != nil && n.Keys.AptosAccount() != "" { + n.Addresses.AptosAddresses = []string{n.Keys.AptosAccount()} + return append([]string(nil), n.Addresses.AptosAddresses...), nil + } if n.Clients.RestClient == nil { return nil, fmt.Errorf("missing cached aptos addresses for node %s and node has no rest client", n.Name) } diff --git a/system-tests/lib/cre/don/secrets/secrets.go b/system-tests/lib/cre/don/secrets/secrets.go index bc98c8aadf8..44d6f2f7c46 100644 --- a/system-tests/lib/cre/don/secrets/secrets.go +++ b/system-tests/lib/cre/don/secrets/secrets.go @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/smdkg/dkgocr/dkgocrtypes" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/aptoskey" "github.com/smartcontractkit/chainlink-common/keystore/corekeys/p2pkey" "github.com/smartcontractkit/chainlink/system-tests/lib/crypto" ) @@ -18,6 +19,7 @@ import ( type nodeSecret struct { EthKeys nodeEthKeyWrapper `toml:"EVM"` SolKeys nodeSolKeyWrapper `toml:"Solana"` + AptosKey nodeAptosKey `toml:"Aptos"` P2PKey nodeP2PKey `toml:"P2PKey"` DKGRecipientKey nodeDKGRecipientKey `toml:"DKGRecipientKey"` @@ -42,6 +44,11 @@ type nodeP2PKey struct { Password string `toml:"Password"` } +type nodeAptosKey struct { + JSON string `toml:"JSON"` + Password string `toml:"Password"` +} + type nodeDKGRecipientKey struct { JSON string `toml:"JSON"` Password string `toml:"Password"` @@ -61,6 +68,7 @@ type NodeKeys struct { CSAKey *crypto.CSAKey EVM map[uint64]*crypto.EVMKey Solana map[string]*crypto.SolKey + Aptos *crypto.AptosKey P2PKey *crypto.P2PKey DKGKey *crypto.DKGRecipientKey OCR2BundleIDs map[ChainFamily]string @@ -73,6 +81,13 @@ func (n NodeKeys) PeerID() string { return n.P2PKey.PeerID.String() } +func (n NodeKeys) AptosAccount() string { + if n.Aptos == nil { + return "" + } + return n.Aptos.Account +} + func (n *NodeKeys) ToNodeSecretsTOML() (string, error) { ns := nodeSecret{} @@ -83,6 +98,13 @@ func (n *NodeKeys) ToNodeSecretsTOML() (string, error) { } } + if n.Aptos != nil { + ns.AptosKey = nodeAptosKey{ + JSON: string(n.Aptos.EncryptedJSON), + Password: n.Aptos.Password, + } + } + if n.DKGKey != nil { ns.DKGRecipientKey = nodeDKGRecipientKey{ JSON: string(n.DKGKey.EncryptedJSON), @@ -125,6 +147,7 @@ type secrets struct { EVM ethKeys `toml:",omitempty"` // choose EVM as the TOML field name to align with relayer config convention P2PKey p2PKey `toml:",omitempty"` Solana solKeys `toml:",omitempty"` + Aptos aptosKey `toml:",omitempty"` DKGRecipientKey dkgRecipientKey `toml:",omitempty"` } @@ -138,6 +161,11 @@ type dkgRecipientKey struct { Password *string } +type aptosKey struct { + JSON *string + Password *string +} + type ethKeys struct { Keys []*ethKey } @@ -260,6 +288,29 @@ func ImportNodeKeys(secretsToml string) (*NodeKeys, error) { PeerID: *p, } + if sSecrets.Aptos.JSON != nil { + if sSecrets.Aptos.Password == nil { + return nil, errors.New("aptos key password is nil") + } + + aptosKeyValue, err := aptoskey.FromEncryptedJSON([]byte(*sSecrets.Aptos.JSON), *sSecrets.Aptos.Password) + if err != nil { + return nil, errors.Wrap(err, "failed to decrypt aptos key from encrypted JSON") + } + + account, err := crypto.NormalizeAptosAccount(aptosKeyValue.Account()) + if err != nil { + return nil, errors.Wrap(err, "failed to normalize aptos account") + } + + keys.Aptos = &crypto.AptosKey{ + EncryptedJSON: []byte(*sSecrets.Aptos.JSON), + PublicKey: aptosKeyValue.PublicKeyStr(), + Account: account, + Password: *sSecrets.Aptos.Password, + } + } + if sSecrets.DKGRecipientKey.JSON != nil { keys.DKGKey = &crypto.DKGRecipientKey{ EncryptedJSON: []byte(*sSecrets.DKGRecipientKey.JSON), diff --git a/system-tests/lib/cre/don/secrets/secrets_test.go b/system-tests/lib/cre/don/secrets/secrets_test.go new file mode 100644 index 00000000000..bbc79b132c0 --- /dev/null +++ b/system-tests/lib/cre/don/secrets/secrets_test.go @@ -0,0 +1,40 @@ +package secrets + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/system-tests/lib/crypto" +) + +func TestNodeKeysAptosSecretsRoundTrip(t *testing.T) { + t.Parallel() + + aptosKey, err := crypto.NewAptosKey("dev-password") + require.NoError(t, err) + p2pKey, err := crypto.NewP2PKey("dev-password") + require.NoError(t, err) + dkgKey, err := crypto.NewDKGRecipientKey("dev-password") + require.NoError(t, err) + + keys := &NodeKeys{ + Aptos: aptosKey, + P2PKey: p2pKey, + DKGKey: dkgKey, + EVM: map[uint64]*crypto.EVMKey{}, + Solana: map[string]*crypto.SolKey{}, + } + + secretsTOML, err := keys.ToNodeSecretsTOML() + require.NoError(t, err) + + imported, err := ImportNodeKeys(secretsTOML) + require.NoError(t, err) + require.NotNil(t, imported.Aptos) + require.Equal(t, aptosKey.Account, imported.Aptos.Account) + require.Equal(t, aptosKey.PublicKey, imported.Aptos.PublicKey) + require.Equal(t, aptosKey.Password, imported.Aptos.Password) + require.Equal(t, p2pKey.PeerID, imported.P2PKey.PeerID) + require.Equal(t, dkgKey.PubKey, imported.DKGKey.PubKey) +} diff --git a/system-tests/lib/cre/don_test.go b/system-tests/lib/cre/don_test.go index 2918e1603ca..1ef236a3b28 100644 --- a/system-tests/lib/cre/don_test.go +++ b/system-tests/lib/cre/don_test.go @@ -5,6 +5,9 @@ import ( "testing" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/system-tests/lib/cre/don/secrets" + "github.com/smartcontractkit/chainlink/system-tests/lib/crypto" ) func TestAptosAccountsForNode_ReturnsCachedAddresses(t *testing.T) { @@ -36,3 +39,21 @@ func TestAptosAccountsForNode_RequiresClientWhenCacheMissing(t *testing.T) { require.Error(t, err) require.ErrorContains(t, err, "missing cached aptos addresses for node node-1 and node has no rest client") } + +func TestAptosAccountsForNode_ReturnsMetadataKeyWhenCacheMissing(t *testing.T) { + t.Parallel() + + node := &Node{ + Name: "node-1", + Keys: &secrets.NodeKeys{ + Aptos: &crypto.AptosKey{ + Account: "0x1", + }, + }, + } + + addresses, err := AptosAccountsForNode(context.Background(), node) + require.NoError(t, err) + require.Equal(t, []string{"0x1"}, addresses) + require.Equal(t, []string{"0x1"}, node.Addresses.AptosAddresses) +} diff --git a/system-tests/lib/cre/environment/dons.go b/system-tests/lib/cre/environment/dons.go index 07774bd2297..bb61dbd71b4 100644 --- a/system-tests/lib/cre/environment/dons.go +++ b/system-tests/lib/cre/environment/dons.go @@ -254,6 +254,9 @@ func nodeAddress(ctx context.Context, node *cre.Node, chainFamily string, bc blo } return solKey.PublicAddress.String(), nil case chainselectors.FamilyAptos: + if node.Keys != nil && node.Keys.AptosAccount() != "" { + return node.Keys.AptosAccount(), nil + } if len(node.Addresses.AptosAddresses) > 0 { return node.Addresses.AptosAddresses[0], nil } diff --git a/system-tests/lib/cre/environment/environment.go b/system-tests/lib/cre/environment/environment.go index f4779040dad..925a4e53faa 100644 --- a/system-tests/lib/cre/environment/environment.go +++ b/system-tests/lib/cre/environment/environment.go @@ -280,35 +280,6 @@ func SetupTestEnvironment( fmt.Print(libformat.PurpleText("%s", input.StageGen.WrapAndNext("DONs and Job Distributor started and linked in %.2f seconds", input.StageGen.Elapsed().Seconds()))) - fmt.Print(libformat.PurpleText("%s", input.StageGen.Wrap("Applying Features after DON startup"))) - for _, feature := range input.Features.List() { - for _, don := range dons.DonsWithFlag(feature.Flag()) { - testLogger.Info().Msgf("Executing PostDONStartup for feature %s for don '%s'", feature.Flag(), don.Name) - output, err := feature.PostDONStartup( - ctx, - testLogger, - don, - dons, - creEnvironment, - ) - if err != nil { - return nil, fmt.Errorf("failed to execute PostDONStartup for feature %s: %w", feature.Flag(), err) - } - if output != nil { - if donsCapabilities[don.ID] == nil { - donsCapabilities[don.ID] = []keystone_changeset.DONCapabilityWithConfig{} - } - donsCapabilities[don.ID] = append(donsCapabilities[don.ID], output.DONCapabilityWithConfig...) - maps.Copy(capabilityToOCR3Config, output.CapabilityToOCR3Config) - for capability, families := range output.CapabilityToExtraSignerFamilies { - capabilityToExtraSignerFamilies[capability] = append([]string(nil), families...) - } - } - testLogger.Info().Msgf("PostDONStartup for feature %s executed successfully", feature.Flag()) - } - } - fmt.Print(libformat.PurpleText("%s", input.StageGen.WrapAndNext("Features applied in %.2f seconds", input.StageGen.Elapsed().Seconds()))) - fmt.Print(libformat.PurpleText("%s", input.StageGen.Wrap("Creating Jobs with Job Distributor"))) gJobErr := gateway.CreateJobs(ctx, creEnvironment, dons, topology.GatewayServiceConfigs, input.GatewayWhitelistConfig) diff --git a/system-tests/lib/cre/features/aptos/aptos.go b/system-tests/lib/cre/features/aptos/aptos.go index 53332757d6f..6db9bd7f576 100644 --- a/system-tests/lib/cre/features/aptos/aptos.go +++ b/system-tests/lib/cre/features/aptos/aptos.go @@ -31,11 +31,9 @@ import ( "github.com/smartcontractkit/chainlink-protos/cre/go/values" "github.com/smartcontractkit/chainlink-testing-framework/framework" "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" - "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/cre/jobs" crejobops "github.com/smartcontractkit/chainlink/deployment/cre/jobs/operations" jobtypes "github.com/smartcontractkit/chainlink/deployment/cre/jobs/types" - "github.com/smartcontractkit/chainlink/deployment/cre/ocr3" "github.com/smartcontractkit/chainlink/deployment/cre/pkg/offchain" aptoschangeset "github.com/smartcontractkit/chainlink/deployment/data-feeds/changeset/aptos" keystone_changeset "github.com/smartcontractkit/chainlink/deployment/keystone/changeset" @@ -87,6 +85,8 @@ func CapabilityLabel(chainSelector uint64) string { return capabilityLabelPrefix + strconv.FormatUint(chainSelector, 10) } +// ForwarderAddress returns the Aptos forwarder address cached in the CRE +// datastore for the given chain selector. func ForwarderAddress(ds datastore.DataStore, chainSelector uint64) (string, bool) { key := datastore.NewAddressRefKey( chainSelector, @@ -101,6 +101,8 @@ func ForwarderAddress(ds datastore.DataStore, chainSelector uint64) (string, boo return ref.Address, true } +// MustForwarderAddress returns the cached Aptos forwarder address for the given +// chain selector and panics if it has not been recorded yet. func MustForwarderAddress(ds datastore.DataStore, chainSelector uint64) string { addr, ok := ForwarderAddress(ds, chainSelector) if !ok { @@ -126,65 +128,39 @@ func (a *Aptos) PreEnvStartup( forwardersByChainID := make(map[uint64]string, len(enabledChainIDs)) for _, chainID := range enabledChainIDs { - aptosChain, err := findAptosChainByChainID(creEnv.Blockchains, chainID) - if err != nil { - return nil, err + aptosChain, findErr := findAptosChainByChainID(creEnv.Blockchains, chainID) + if findErr != nil { + return nil, findErr } - forwarderAddress, err := ensureForwarder(ctx, testLogger, creEnv, aptosChain) - if err != nil { - return nil, err + forwarderAddress, ensureErr := ensureForwarder(ctx, testLogger, creEnv, aptosChain) + if ensureErr != nil { + return nil, ensureErr } forwardersByChainID[chainID] = forwarderAddress } - if err := patchNodeTOML(don, forwardersByChainID); err != nil { - return nil, err - } - - return &cre.PreEnvStartupOutput{}, nil -} - -func (a *Aptos) PostDONStartup( - ctx context.Context, - testLogger zerolog.Logger, - don *cre.Don, - _ *cre.Dons, - creEnv *cre.Environment, -) (*cre.PostDONStartupOutput, error) { - enabledChainIDs, err := don.GetEnabledChainIDsForCapability(flag) - if err != nil { - return nil, fmt.Errorf("could not find enabled chainIDs for '%s' in don '%s': %w", flag, don.Name, err) - } - if len(enabledChainIDs) == 0 { - return nil, nil + if patchErr := patchNodeTOML(don, forwardersByChainID); patchErr != nil { + return nil, patchErr } - workerNodeIDs, err := workerJDNodeIDs(don) + workers, err := don.Workers() if err != nil { return nil, err } - nodes, err := deployment.NodeInfo(workerNodeIDs, creEnv.CldfEnvironment.Offchain) + p2pToTransmitterMap, err := p2pToTransmitterMapForWorkers(workers) if err != nil { - return nil, fmt.Errorf("failed to get Aptos worker node info for DON %q: %w", don.Name, err) + return nil, fmt.Errorf("failed to collect Aptos worker transmitters for DON %q from metadata: %w", don.Name, err) } caps := make([]keystone_changeset.DONCapabilityWithConfig, 0, len(enabledChainIDs)) - ocrConfigs := make(map[string]*ocr3.OracleConfig, len(enabledChainIDs)) - capabilityToExtraSignerFamilies := make(map[string][]string, len(enabledChainIDs)) for _, chainID := range enabledChainIDs { aptosChain, err := findAptosChainByChainID(creEnv.Blockchains, chainID) if err != nil { return nil, err } - selector := aptosChain.ChainSelector() - labelledName := CapabilityLabel(selector) - - p2pToTransmitterMap, err := p2pToTransmitterMapForChainSelector(nodes, selector) - if err != nil { - return nil, fmt.Errorf("failed to collect Aptos p2p transmitter map for capability %s: %w", labelledName, err) - } - capabilityConfig, err := cre.ResolveCapabilityConfig(don, flag, cre.ChainCapabilityScope(chainID)) + labelledName := CapabilityLabel(aptosChain.ChainSelector()) + capabilityConfig, err := cre.ResolveCapabilityConfig(don.MustNodeSet(), flag, cre.ChainCapabilityScope(chainID)) if err != nil { return nil, fmt.Errorf("could not resolve capability config for '%s' on chain %d: %w", flag, chainID, err) } @@ -199,17 +175,12 @@ func (a *Aptos) PostDONStartup( Version: capabilityVersion, CapabilityType: 1, }, - Config: capConfig, - UseCapRegOCRConfig: true, + Config: capConfig, }) - ocrConfigs[labelledName] = crecontracts.DefaultChainCapabilityOCR3Config() - capabilityToExtraSignerFamilies[labelledName] = []string{chainselectors.FamilyAptos} } - return &cre.PostDONStartupOutput{ - DONCapabilityWithConfig: caps, - CapabilityToOCR3Config: ocrConfigs, - CapabilityToExtraSignerFamilies: capabilityToExtraSignerFamilies, + return &cre.PreEnvStartupOutput{ + DONCapabilityWithConfig: caps, }, nil } @@ -345,10 +316,9 @@ func (a *Aptos) PostEnvStartup( return nil } -// BuildCapabilityConfig builds the Aptos capability config using the same config -// split as runtime capabilities: method execution policy in MethodConfigs and -// Aptos-specific runtime inputs in SpecConfig. OCR contract config remains -// separate and is only attached through UseCapRegOCRConfig. +// BuildCapabilityConfig builds the Aptos capability config passed directly +// through the capability manager: method execution policy in MethodConfigs and +// Aptos-specific runtime inputs in SpecConfig. func BuildCapabilityConfig(values map[string]any, p2pToTransmitterMap map[string]string, localOnly bool) (*capabilitiespb.CapabilityConfig, error) { methodSettings, err := resolveMethodConfigSettings(values) if err != nil { @@ -528,6 +498,10 @@ func setForwarderAddress(cfg *corechainlink.Config, chainID, forwarderAddress st return fmt.Errorf("Aptos chain %s not found in node config", chainID) } +// ensureForwarder makes sure a forwarder exists for the Aptos chain selector and +// returns its address. In local Docker environments it will deploy the forwarder +// once and cache the resulting address in the CRE datastore; in non-Docker +// environments it only reuses an address that has already been injected. func ensureForwarder( ctx context.Context, testLogger zerolog.Logger, @@ -619,6 +593,8 @@ func ensureForwarder( return addr, nil } +// addForwarderToDataStore seals a new datastore snapshot with the Aptos +// forwarder address so later setup phases can reuse it without redeploying. func addForwarderToDataStore(creEnv *cre.Environment, chainSelector uint64, address string) error { memoryDatastore, err := crecontracts.NewDataStoreFromExisting(creEnv.CldfEnvironment.DataStore) if err != nil { @@ -640,6 +616,8 @@ func addForwarderToDataStore(creEnv *cre.Environment, chainSelector uint64, addr return nil } +// configureForwarders writes the final DON membership and signer set to each +// Aptos forwarder after the DON has started and contract DON IDs are known. func configureForwarders( ctx context.Context, testLogger zerolog.Logger, @@ -796,46 +774,33 @@ func donOraclePublicKeys(ctx context.Context, don *cre.Don) ([][]byte, error) { return oracles, nil } -func workerJDNodeIDs(don *cre.Don) ([]string, error) { - workers, err := don.Workers() - if err != nil { - return nil, err +func p2pToTransmitterMapForWorkers(workers []*cre.NodeMetadata) (map[string]string, error) { + if len(workers) == 0 { + return nil, pkgerrors.New("no DON worker nodes provided") } - nodeIDs := make([]string, 0, len(workers)) + p2pToTransmitterMap := make(map[string]string) for _, worker := range workers { - if worker.JobDistributorDetails.NodeID == "" { - return nil, fmt.Errorf("missing Job Distributor node id for worker %q in DON %q", worker.Name, don.Name) + if worker.Keys == nil || worker.Keys.P2PKey == nil { + return nil, fmt.Errorf("missing P2P key for worker index %d", worker.Index) } - nodeIDs = append(nodeIDs, worker.JobDistributorDetails.NodeID) - } - return nodeIDs, nil -} - -func p2pToTransmitterMapForChainSelector(nodes deployment.Nodes, chainSelector uint64) (map[string]string, error) { - if len(nodes) == 0 { - return nil, pkgerrors.New("no DON worker nodes provided") - } - - p2pToTransmitterMap := make(map[string]string) - for _, node := range nodes { - ocrCfg, ok := node.OCRConfigForChainSelector(chainSelector) - if !ok { - continue + account := worker.AptosAccount() + if account == "" { + return nil, fmt.Errorf("missing Aptos account for worker index %d", worker.Index) } - transmitter, err := normalizeTransmitter(string(ocrCfg.TransmitAccount)) + transmitter, err := normalizeTransmitter(account) if err != nil { - return nil, fmt.Errorf("invalid Aptos transmitter for node %s: %w", node.Name, err) + return nil, fmt.Errorf("invalid Aptos transmitter for worker index %d: %w", worker.Index, err) } - peerKey := hex.EncodeToString(node.PeerID[:]) + peerKey := hex.EncodeToString(worker.Keys.P2PKey.PeerID[:]) p2pToTransmitterMap[peerKey] = transmitter } if len(p2pToTransmitterMap) == 0 { - return nil, fmt.Errorf("no Aptos OCR config/transmitters found for chain selector %d", chainSelector) + return nil, pkgerrors.New("no Aptos transmitters found for DON workers") } return p2pToTransmitterMap, nil @@ -981,6 +946,9 @@ func aptosDonIDUint32(donID uint64) (uint32, error) { return uint32(donID), nil } +// ensureAccountVisible best-effort funds an Aptos account and waits for the node +// API to acknowledge it. This smooths over localnet timing where deployer +// accounts can exist before the node API can query them reliably. func ensureAccountVisible( ctx context.Context, testLogger zerolog.Logger, diff --git a/system-tests/lib/cre/features/aptos/aptos_test.go b/system-tests/lib/cre/features/aptos/aptos_test.go index 42568360ddb..0714090a74b 100644 --- a/system-tests/lib/cre/features/aptos/aptos_test.go +++ b/system-tests/lib/cre/features/aptos/aptos_test.go @@ -8,14 +8,12 @@ import ( "github.com/stretchr/testify/require" - chainselectors "github.com/smartcontractkit/chain-selectors" - - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink-common/keystore/corekeys/p2pkey" capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" "github.com/smartcontractkit/chainlink-protos/cre/go/values" - "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/system-tests/lib/cre" + "github.com/smartcontractkit/chainlink/system-tests/lib/cre/don/secrets" + "github.com/smartcontractkit/chainlink/system-tests/lib/crypto" ) func TestSetRuntimeSpecConfig_ReplacesLegacyKey(t *testing.T) { @@ -156,28 +154,22 @@ func TestNormalizeTransmitter(t *testing.T) { require.Error(t, err) } -func TestP2PToTransmitterMapForChainSelector(t *testing.T) { - selector := uint64(4457093679053095497) - chainDetails, err := chainselectors.GetChainDetails(selector) - require.NoError(t, err) - +func TestP2PToTransmitterMapForWorkers(t *testing.T) { key := p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)) - transmitAccount := ocrtypes.Account("0xa") - - nodes := deployment.Nodes{ + workers := []*cre.NodeMetadata{ { - Name: "node-1", - PeerID: key.PeerID(), - SelToOCRConfig: map[chainselectors.ChainDetails]deployment.OCRConfig{ - chainDetails: { - PeerID: key.PeerID(), - TransmitAccount: transmitAccount, + Keys: &secrets.NodeKeys{ + P2PKey: &crypto.P2PKey{ + PeerID: key.PeerID(), + }, + Aptos: &crypto.AptosKey{ + Account: "0xa", }, }, }, } - got, err := p2pToTransmitterMapForChainSelector(nodes, selector) + got, err := p2pToTransmitterMapForWorkers(workers) require.NoError(t, err) peerID := key.PeerID() diff --git a/system-tests/lib/cre/types.go b/system-tests/lib/cre/types.go index 49c01189f21..33d0df23e18 100644 --- a/system-tests/lib/cre/types.go +++ b/system-tests/lib/cre/types.go @@ -567,6 +567,7 @@ func NewDonMetadata(c *NodeSet, id uint64, provider infra.Provider, capabilityCo Keys: NodeKeyInput{ EVMChainIDs: c.EVMChains(), SolanaChainIDs: c.SupportedSolChains, + AptosEnabled: HasFlag(c.Capabilities, WriteAptosCapability), Password: "dev-password", ImportedSecrets: nodeSpec.Node.TestSecretsOverrides, }, @@ -1147,6 +1148,13 @@ func (n *NodeMetadata) PeerID() string { return strings.TrimPrefix(n.Keys.PeerID(), "p2p_") } +func (n *NodeMetadata) AptosAccount() string { + if n.Keys == nil { + return "" + } + return n.Keys.AptosAccount() +} + const ( DefaultShardOrchestratorPort uint16 = 50051 DefaultArbiterPort uint16 = 9876 @@ -1426,6 +1434,7 @@ func (c *NodeSet) MaxFaultyNodes() (uint32, error) { type NodeKeyInput struct { EVMChainIDs []uint64 SolanaChainIDs []string + AptosEnabled bool Password string ImportedSecrets string // raw JSON string of secrets to import (usually from a previous run) @@ -1442,6 +1451,9 @@ func NewNodeKeys(input NodeKeyInput) (*secrets.NodeKeys, error) { if err != nil { return nil, errors.Wrap(err, "failed to parse imported secrets") } + if input.AptosEnabled && importedKeys.Aptos == nil { + return nil, errors.New("imported secrets are missing an Aptos key; regenerate node secrets with Aptos support") + } return importedKeys, nil } @@ -1475,6 +1487,13 @@ func NewNodeKeys(input NodeKeyInput) (*secrets.NodeKeys, error) { } out.Solana[chainID] = k } + if input.AptosEnabled { + k, err := crypto.NewAptosKey(input.Password) + if err != nil { + return nil, fmt.Errorf("failed to generate Aptos key: %w", err) + } + out.Aptos = k + } return out, nil } diff --git a/system-tests/lib/crypto/aptos.go b/system-tests/lib/crypto/aptos.go new file mode 100644 index 00000000000..a3c76b42768 --- /dev/null +++ b/system-tests/lib/crypto/aptos.go @@ -0,0 +1,49 @@ +package crypto + +import ( + "fmt" + + aptossdk "github.com/aptos-labs/aptos-go-sdk" + + "github.com/smartcontractkit/chainlink-common/keystore" + "github.com/smartcontractkit/chainlink-common/keystore/corekeys/aptoskey" +) + +type AptosKey struct { + EncryptedJSON []byte + PublicKey string + Account string + Password string +} + +func NewAptosKey(password string) (*AptosKey, error) { + key, err := aptoskey.New() + if err != nil { + return nil, fmt.Errorf("failed to create aptos key: %w", err) + } + + enc, err := key.ToEncryptedJSON(password, keystore.DefaultScryptParams) + if err != nil { + return nil, fmt.Errorf("failed to encrypt aptos key: %w", err) + } + + account, err := NormalizeAptosAccount(key.Account()) + if err != nil { + return nil, fmt.Errorf("failed to normalize aptos account: %w", err) + } + + return &AptosKey{ + EncryptedJSON: enc, + PublicKey: key.PublicKeyStr(), + Account: account, + Password: password, + }, nil +} + +func NormalizeAptosAccount(raw string) (string, error) { + var addr aptossdk.AccountAddress + if err := addr.ParseStringRelaxed(raw); err != nil { + return "", err + } + return addr.StringLong(), nil +} From 2fa9d3bf6fd7532d1cfd34c9d5863e411aabeb30 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 19 Mar 2026 15:09:55 +0000 Subject: [PATCH 06/34] cre: pass aptos config directly in local setup --- .../cre/features/consensus/v1/consensus.go | 2 +- .../cre/features/consensus/v2/consensus.go | 2 +- system-tests/lib/cre/features/cron/cron.go | 2 +- .../features/custom_compute/custom_compute.go | 2 +- .../lib/cre/features/don_time/don_time.go | 2 +- system-tests/lib/cre/features/evm/v1/evm.go | 2 +- system-tests/lib/cre/features/evm/v2/evm.go | 2 +- .../cre/features/http_action/http_action.go | 2 +- .../cre/features/http_trigger/http_trigger.go | 2 +- .../log_event_trigger/log_event_trigger.go | 2 +- system-tests/lib/cre/features/mock/mock.go | 2 +- .../features/read_contract/read_contract.go | 2 +- .../lib/cre/features/solana/v2/solana.go | 2 +- system-tests/lib/cre/features/vault/vault.go | 2 +- .../features/web_api_target/web_api_target.go | 2 +- .../web_api_trigger/web_api_trigger.go | 2 +- system-tests/lib/cre/types.go | 29 ------------------- 17 files changed, 16 insertions(+), 45 deletions(-) diff --git a/system-tests/lib/cre/features/consensus/v1/consensus.go b/system-tests/lib/cre/features/consensus/v1/consensus.go index ecd60137194..27111084a9f 100644 --- a/system-tests/lib/cre/features/consensus/v1/consensus.go +++ b/system-tests/lib/cre/features/consensus/v1/consensus.go @@ -31,7 +31,7 @@ import ( const flag = cre.ConsensusCapability -type Consensus struct{ cre.NoopPostDONStartup } +type Consensus struct{} func (c *Consensus) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/consensus/v2/consensus.go b/system-tests/lib/cre/features/consensus/v2/consensus.go index a74f034f390..207e2968b4f 100644 --- a/system-tests/lib/cre/features/consensus/v2/consensus.go +++ b/system-tests/lib/cre/features/consensus/v2/consensus.go @@ -34,7 +34,7 @@ import ( const flag = cre.ConsensusCapabilityV2 const consensusLabelledName = "consensus" -type Consensus struct{ cre.NoopPostDONStartup } +type Consensus struct{} func (c *Consensus) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/cron/cron.go b/system-tests/lib/cre/features/cron/cron.go index e98b6b08e6d..4d64b45be22 100644 --- a/system-tests/lib/cre/features/cron/cron.go +++ b/system-tests/lib/cre/features/cron/cron.go @@ -14,7 +14,7 @@ import ( const flag = cre.CronCapability -type Cron struct{ cre.NoopPostDONStartup } +type Cron struct{} func (c *Cron) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/custom_compute/custom_compute.go b/system-tests/lib/cre/features/custom_compute/custom_compute.go index d33747055de..b8184149d8d 100644 --- a/system-tests/lib/cre/features/custom_compute/custom_compute.go +++ b/system-tests/lib/cre/features/custom_compute/custom_compute.go @@ -28,7 +28,7 @@ import ( const flag = cre.CustomComputeCapability -type CustomCompute struct{ cre.NoopPostDONStartup } +type CustomCompute struct{} func (o *CustomCompute) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/don_time/don_time.go b/system-tests/lib/cre/features/don_time/don_time.go index dc31974af18..711fee093f5 100644 --- a/system-tests/lib/cre/features/don_time/don_time.go +++ b/system-tests/lib/cre/features/don_time/don_time.go @@ -28,7 +28,7 @@ const flag = cre.DONTimeCapability const donTimeLabelledName = "dontime" -type DONTime struct{ cre.NoopPostDONStartup } +type DONTime struct{} func (o *DONTime) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/evm/v1/evm.go b/system-tests/lib/cre/features/evm/v1/evm.go index 71d288f6b4f..c1fae2fcdd2 100644 --- a/system-tests/lib/cre/features/evm/v1/evm.go +++ b/system-tests/lib/cre/features/evm/v1/evm.go @@ -42,7 +42,7 @@ import ( const flag = cre.WriteEVMCapability -type EVM struct{ cre.NoopPostDONStartup } +type EVM struct{} func (o *EVM) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/evm/v2/evm.go b/system-tests/lib/cre/features/evm/v2/evm.go index 10374fec232..b0dfb80fed2 100644 --- a/system-tests/lib/cre/features/evm/v2/evm.go +++ b/system-tests/lib/cre/features/evm/v2/evm.go @@ -50,7 +50,7 @@ const ( requestTimeout = 30 * time.Second ) -type EVM struct{ cre.NoopPostDONStartup } +type EVM struct{} func (o *EVM) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/http_action/http_action.go b/system-tests/lib/cre/features/http_action/http_action.go index 7aed84a13cf..348509b41d4 100644 --- a/system-tests/lib/cre/features/http_action/http_action.go +++ b/system-tests/lib/cre/features/http_action/http_action.go @@ -29,7 +29,7 @@ import ( const flag = cre.HTTPActionCapability -type HTTPAction struct{ cre.NoopPostDONStartup } +type HTTPAction struct{} func (o *HTTPAction) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/http_trigger/http_trigger.go b/system-tests/lib/cre/features/http_trigger/http_trigger.go index 25702abf453..7a8436bf9e1 100644 --- a/system-tests/lib/cre/features/http_trigger/http_trigger.go +++ b/system-tests/lib/cre/features/http_trigger/http_trigger.go @@ -29,7 +29,7 @@ import ( const flag = cre.HTTPTriggerCapability -type HTTPTrigger struct{ cre.NoopPostDONStartup } +type HTTPTrigger struct{} func (o *HTTPTrigger) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/log_event_trigger/log_event_trigger.go b/system-tests/lib/cre/features/log_event_trigger/log_event_trigger.go index 0a00edc16de..eed2d258aab 100644 --- a/system-tests/lib/cre/features/log_event_trigger/log_event_trigger.go +++ b/system-tests/lib/cre/features/log_event_trigger/log_event_trigger.go @@ -26,7 +26,7 @@ import ( const flag = cre.LogEventTriggerCapability -type LogEventTrigger struct{ cre.NoopPostDONStartup } +type LogEventTrigger struct{} func (o *LogEventTrigger) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/mock/mock.go b/system-tests/lib/cre/features/mock/mock.go index 1250bf3bddc..4166243f7ff 100644 --- a/system-tests/lib/cre/features/mock/mock.go +++ b/system-tests/lib/cre/features/mock/mock.go @@ -26,7 +26,7 @@ import ( const flag = cre.MockCapability -type Mock struct{ cre.NoopPostDONStartup } +type Mock struct{} func (o *Mock) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/read_contract/read_contract.go b/system-tests/lib/cre/features/read_contract/read_contract.go index 5a7760c33b7..7edfa515710 100644 --- a/system-tests/lib/cre/features/read_contract/read_contract.go +++ b/system-tests/lib/cre/features/read_contract/read_contract.go @@ -29,7 +29,7 @@ import ( const flag = cre.ReadContractCapability -type ReadContract struct{ cre.NoopPostDONStartup } +type ReadContract struct{} func (o *ReadContract) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/solana/v2/solana.go b/system-tests/lib/cre/features/solana/v2/solana.go index 6730e4a435d..e333f061aab 100644 --- a/system-tests/lib/cre/features/solana/v2/solana.go +++ b/system-tests/lib/cre/features/solana/v2/solana.go @@ -64,7 +64,7 @@ type SolChain interface { SolChainID() string } -type Solana struct{ cre.NoopPostDONStartup } +type Solana struct{} func (s *Solana) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/vault/vault.go b/system-tests/lib/cre/features/vault/vault.go index 0766c12d9b2..9eefa2db649 100644 --- a/system-tests/lib/cre/features/vault/vault.go +++ b/system-tests/lib/cre/features/vault/vault.go @@ -50,7 +50,7 @@ const ( ContractQualifier = "vault" ) -type Vault struct{ cre.NoopPostDONStartup } +type Vault struct{} func (o *Vault) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/web_api_target/web_api_target.go b/system-tests/lib/cre/features/web_api_target/web_api_target.go index ca6067501b8..ff94e1a39e9 100644 --- a/system-tests/lib/cre/features/web_api_target/web_api_target.go +++ b/system-tests/lib/cre/features/web_api_target/web_api_target.go @@ -28,7 +28,7 @@ import ( const flag = cre.WebAPITargetCapability -type WebAPITarget struct{ cre.NoopPostDONStartup } +type WebAPITarget struct{} func (o *WebAPITarget) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/features/web_api_trigger/web_api_trigger.go b/system-tests/lib/cre/features/web_api_trigger/web_api_trigger.go index 99ea848148c..d0cf033e0aa 100644 --- a/system-tests/lib/cre/features/web_api_trigger/web_api_trigger.go +++ b/system-tests/lib/cre/features/web_api_trigger/web_api_trigger.go @@ -25,7 +25,7 @@ import ( const flag = cre.WebAPITriggerCapability -type WebAPITrigger struct{ cre.NoopPostDONStartup } +type WebAPITrigger struct{} func (o *WebAPITrigger) Flag() cre.CapabilityFlag { return flag diff --git a/system-tests/lib/cre/types.go b/system-tests/lib/cre/types.go index 33d0df23e18..39ffdc39b86 100644 --- a/system-tests/lib/cre/types.go +++ b/system-tests/lib/cre/types.go @@ -1654,25 +1654,6 @@ type Feature interface { dons *Dons, creEnv *Environment, ) error - PostDONStartup( - ctx context.Context, - testLogger zerolog.Logger, - don *Don, - dons *Dons, - creEnv *Environment, - ) (*PostDONStartupOutput, error) -} - -type NoopPostDONStartup struct{} - -func (NoopPostDONStartup) PostDONStartup( - context.Context, - zerolog.Logger, - *Don, - *Dons, - *Environment, -) (*PostDONStartupOutput, error) { - return nil, nil } type PreEnvStartupOutput struct { @@ -1684,13 +1665,3 @@ type PreEnvStartupOutput struct { // EVM is always included. CapabilityToExtraSignerFamilies map[string][]string } - -type PostDONStartupOutput struct { - DONCapabilityWithConfig []keystone_changeset.DONCapabilityWithConfig - // keyed by LabelledName - CapabilityToOCR3Config map[string]*ocr3.OracleConfig - // keyed by LabelledName. Non-EVM chain families whose signing keys should be - // included in OCR3 config signers for that capability (e.g. ["solana"]). - // EVM is always included. - CapabilityToExtraSignerFamilies map[string][]string -} From 6382cf90551c985625ebd9f2046e1bd8228fe7f0 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 19 Mar 2026 15:19:35 +0000 Subject: [PATCH 07/34] aptos: drop container funding fallback --- .../environment/blockchains/aptos/aptos.go | 40 +++++-------------- 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/system-tests/lib/cre/environment/blockchains/aptos/aptos.go b/system-tests/lib/cre/environment/blockchains/aptos/aptos.go index 332c847275a..c30436afb6a 100644 --- a/system-tests/lib/cre/environment/blockchains/aptos/aptos.go +++ b/system-tests/lib/cre/environment/blockchains/aptos/aptos.go @@ -18,7 +18,6 @@ import ( cldf_chain "github.com/smartcontractkit/chainlink-deployments-framework/chain" cldf_aptos "github.com/smartcontractkit/chainlink-deployments-framework/chain/aptos" - "github.com/smartcontractkit/chainlink-testing-framework/framework" "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains" "github.com/smartcontractkit/chainlink/system-tests/lib/infra" @@ -136,41 +135,22 @@ func (a *Blockchain) Fund(ctx context.Context, address string, amount uint64) er return fmt.Errorf("cannot fund Aptos address %q: parse error: %w", address, parseErr) } - // Fast path: use the faucet URL surfaced by CTF. Keep node-URL derivation only as - // a compatibility fallback for older cached outputs that predate that field. - if faucetURL, ferr := a.faucetURL(); ferr == nil { - if faucetClient, cErr := aptoslib.NewFaucetClient(client, faucetURL); cErr == nil { - if fundErr := faucetClient.Fund(account, amount); fundErr == nil { - if waitErr := waitForAptosAccountVisible(ctx, client, account, 15*time.Second); waitErr == nil { - a.testLogger.Info().Msgf("Funded Aptos account %s via host faucet (%d octas)", account.StringLong(), amount) - return nil - } - } - } - } - - containerName := strings.TrimSpace(a.ctfOutput.ContainerName) - if containerName == "" { - return fmt.Errorf("failed to fund Aptos address %s via host faucet and no container fallback available", address) + faucetURL, err := a.faucetURL() + if err != nil { + return fmt.Errorf("failed to derive Aptos faucet URL for %s: %w", address, err) } - - dc, err := framework.NewDockerClient() + faucetClient, err := aptoslib.NewFaucetClient(client, faucetURL) if err != nil { - return fmt.Errorf("failed to create docker client for Aptos funding fallback: %w", err) + return fmt.Errorf("failed to create Aptos faucet client for %s: %w", address, err) } - _, execErr := dc.ExecContainerWithContext(ctx, containerName, []string{ - "aptos", "account", "fund-with-faucet", - "--account", account.StringLong(), - "--amount", strconv.FormatUint(amount, 10), - }) - if execErr != nil { - return fmt.Errorf("failed to fund Aptos address %s via container faucet fallback: %w", address, execErr) + if err := faucetClient.Fund(account, amount); err != nil { + return fmt.Errorf("failed to fund Aptos address %s via host faucet: %w", address, err) } - if waitErr := waitForAptosAccountVisible(ctx, client, account, 20*time.Second); waitErr != nil { - return fmt.Errorf("aptos funding fallback completed but account still not visible: %w", waitErr) + if err := waitForAptosAccountVisible(ctx, client, account, 15*time.Second); err != nil { + return fmt.Errorf("aptos funding request completed but account is still not visible: %w", err) } - a.testLogger.Info().Msgf("Funded Aptos account %s via container faucet fallback (%d octas)", account.StringLong(), amount) + a.testLogger.Info().Msgf("Funded Aptos account %s via host faucet (%d octas)", account.StringLong(), amount) return nil } From 0c9326224048d9f3cda410aefeaeced2b4b579b4 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 19 Mar 2026 15:31:56 +0000 Subject: [PATCH 08/34] cre: rename ocr extra signer helper --- system-tests/lib/cre/features/consensus/v2/consensus.go | 2 +- system-tests/lib/cre/features/evm/v2/evm.go | 2 +- ...{ocr_signer_families.go => ocr_extra_signer_families.go} | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) rename system-tests/lib/cre/{ocr_signer_families.go => ocr_extra_signer_families.go} (82%) diff --git a/system-tests/lib/cre/features/consensus/v2/consensus.go b/system-tests/lib/cre/features/consensus/v2/consensus.go index 207e2968b4f..1936400a657 100644 --- a/system-tests/lib/cre/features/consensus/v2/consensus.go +++ b/system-tests/lib/cre/features/consensus/v2/consensus.go @@ -66,7 +66,7 @@ func (c *Consensus) PreEnvStartup( consensusLabelledName: contracts.DefaultOCR3Config(), }, CapabilityToExtraSignerFamilies: cre.CapabilityToExtraSignerFamilies( - cre.NonEVMOCRSignerFamilies(creEnv.Blockchains), + cre.OCRExtraSignerFamilies(creEnv.Blockchains), consensusLabelledName, ), }, nil diff --git a/system-tests/lib/cre/features/evm/v2/evm.go b/system-tests/lib/cre/features/evm/v2/evm.go index b0dfb80fed2..4cb06e319fb 100644 --- a/system-tests/lib/cre/features/evm/v2/evm.go +++ b/system-tests/lib/cre/features/evm/v2/evm.go @@ -137,7 +137,7 @@ func (o *EVM) PreEnvStartup( DONCapabilityWithConfig: capabilities, CapabilityToOCR3Config: capabilityToOCR3Config, CapabilityToExtraSignerFamilies: cre.CapabilityToExtraSignerFamilies( - cre.NonEVMOCRSignerFamilies(creEnv.Blockchains), + cre.OCRExtraSignerFamilies(creEnv.Blockchains), capabilityLabels..., ), }, nil diff --git a/system-tests/lib/cre/ocr_signer_families.go b/system-tests/lib/cre/ocr_extra_signer_families.go similarity index 82% rename from system-tests/lib/cre/ocr_signer_families.go rename to system-tests/lib/cre/ocr_extra_signer_families.go index d143c2df75c..ba9e22255dd 100644 --- a/system-tests/lib/cre/ocr_signer_families.go +++ b/system-tests/lib/cre/ocr_extra_signer_families.go @@ -8,9 +8,9 @@ import ( "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains" ) -// NonEVMOCRSignerFamilies returns the non-EVM OCR signer families present in the -// environment. EVM is always included separately by OCR config generation. -func NonEVMOCRSignerFamilies(blockchains []blockchains.Blockchain) []string { +// OCRExtraSignerFamilies returns the additional signer families that should be +// included in OCR3 config generation beyond the default EVM signer family. +func OCRExtraSignerFamilies(blockchains []blockchains.Blockchain) []string { familiesSet := make(map[string]struct{}) for _, blockchain := range blockchains { switch { From 0f9de7c92d166a29111d73494e55df7cee16748a Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 19 Mar 2026 15:53:03 +0000 Subject: [PATCH 09/34] cre: tolerate empty imported aptos secrets --- system-tests/lib/cre/don/secrets/secrets.go | 17 +++++- .../lib/cre/don/secrets/secrets_test.go | 25 ++++++++ system-tests/lib/cre/types_nodekeys_test.go | 58 +++++++++++++++++++ 3 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 system-tests/lib/cre/types_nodekeys_test.go diff --git a/system-tests/lib/cre/don/secrets/secrets.go b/system-tests/lib/cre/don/secrets/secrets.go index 44d6f2f7c46..905fb197054 100644 --- a/system-tests/lib/cre/don/secrets/secrets.go +++ b/system-tests/lib/cre/don/secrets/secrets.go @@ -3,6 +3,7 @@ package secrets import ( "encoding/hex" "encoding/json" + "strings" "github.com/ethereum/go-ethereum/common" "github.com/gagliardetto/solana-go" @@ -288,12 +289,24 @@ func ImportNodeKeys(secretsToml string) (*NodeKeys, error) { PeerID: *p, } + if sSecrets.Aptos.JSON != nil { + aptosJSON := strings.TrimSpace(*sSecrets.Aptos.JSON) + if aptosJSON == "" { + sSecrets.Aptos.JSON = nil + sSecrets.Aptos.Password = nil + } + } + if sSecrets.Aptos.JSON != nil { if sSecrets.Aptos.Password == nil { return nil, errors.New("aptos key password is nil") } + aptosPassword := strings.TrimSpace(*sSecrets.Aptos.Password) + if aptosPassword == "" { + return nil, errors.New("aptos key password is empty") + } - aptosKeyValue, err := aptoskey.FromEncryptedJSON([]byte(*sSecrets.Aptos.JSON), *sSecrets.Aptos.Password) + aptosKeyValue, err := aptoskey.FromEncryptedJSON([]byte(*sSecrets.Aptos.JSON), aptosPassword) if err != nil { return nil, errors.Wrap(err, "failed to decrypt aptos key from encrypted JSON") } @@ -307,7 +320,7 @@ func ImportNodeKeys(secretsToml string) (*NodeKeys, error) { EncryptedJSON: []byte(*sSecrets.Aptos.JSON), PublicKey: aptosKeyValue.PublicKeyStr(), Account: account, - Password: *sSecrets.Aptos.Password, + Password: aptosPassword, } } diff --git a/system-tests/lib/cre/don/secrets/secrets_test.go b/system-tests/lib/cre/don/secrets/secrets_test.go index bbc79b132c0..7b2744d3e7c 100644 --- a/system-tests/lib/cre/don/secrets/secrets_test.go +++ b/system-tests/lib/cre/don/secrets/secrets_test.go @@ -38,3 +38,28 @@ func TestNodeKeysAptosSecretsRoundTrip(t *testing.T) { require.Equal(t, p2pKey.PeerID, imported.P2PKey.PeerID) require.Equal(t, dkgKey.PubKey, imported.DKGKey.PubKey) } + +func TestImportNodeKeys_IgnoresEmptyAptosSecret(t *testing.T) { + t.Parallel() + + p2pKey, err := crypto.NewP2PKey("dev-password") + require.NoError(t, err) + dkgKey, err := crypto.NewDKGRecipientKey("dev-password") + require.NoError(t, err) + + keys := &NodeKeys{ + P2PKey: p2pKey, + DKGKey: dkgKey, + EVM: map[uint64]*crypto.EVMKey{}, + Solana: map[string]*crypto.SolKey{}, + } + + secretsTOML, err := keys.ToNodeSecretsTOML() + require.NoError(t, err) + + imported, err := ImportNodeKeys(secretsTOML) + require.NoError(t, err) + require.Nil(t, imported.Aptos) + require.Equal(t, p2pKey.PeerID, imported.P2PKey.PeerID) + require.Equal(t, dkgKey.PubKey, imported.DKGKey.PubKey) +} diff --git a/system-tests/lib/cre/types_nodekeys_test.go b/system-tests/lib/cre/types_nodekeys_test.go new file mode 100644 index 00000000000..5a7f6a4f4ac --- /dev/null +++ b/system-tests/lib/cre/types_nodekeys_test.go @@ -0,0 +1,58 @@ +package cre + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/system-tests/lib/cre/don/secrets" + "github.com/smartcontractkit/chainlink/system-tests/lib/crypto" +) + +func TestNewNodeKeys_IgnoresEmptyImportedAptosSecretWhenAptosDisabled(t *testing.T) { + t.Parallel() + + p2pKey, err := crypto.NewP2PKey("dev-password") + require.NoError(t, err) + dkgKey, err := crypto.NewDKGRecipientKey("dev-password") + require.NoError(t, err) + + baseSecrets, err := (&secrets.NodeKeys{ + P2PKey: p2pKey, + DKGKey: dkgKey, + EVM: map[uint64]*crypto.EVMKey{}, + Solana: map[string]*crypto.SolKey{}, + }).ToNodeSecretsTOML() + require.NoError(t, err) + + keys, err := NewNodeKeys(NodeKeyInput{ + ImportedSecrets: baseSecrets, + AptosEnabled: false, + }) + require.NoError(t, err) + require.Nil(t, keys.Aptos) + require.Equal(t, p2pKey.PeerID, keys.P2PKey.PeerID) +} + +func TestNewNodeKeys_RejectsMissingImportedAptosSecretWhenAptosEnabled(t *testing.T) { + t.Parallel() + + p2pKey, err := crypto.NewP2PKey("dev-password") + require.NoError(t, err) + dkgKey, err := crypto.NewDKGRecipientKey("dev-password") + require.NoError(t, err) + + baseSecrets, err := (&secrets.NodeKeys{ + P2PKey: p2pKey, + DKGKey: dkgKey, + EVM: map[uint64]*crypto.EVMKey{}, + Solana: map[string]*crypto.SolKey{}, + }).ToNodeSecretsTOML() + require.NoError(t, err) + + _, err = NewNodeKeys(NodeKeyInput{ + ImportedSecrets: baseSecrets, + AptosEnabled: true, + }) + require.ErrorContains(t, err, "missing an Aptos key") +} From 8a5739a7e638d7238f14e2a944271cba05df38da Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 19 Mar 2026 17:06:30 +0000 Subject: [PATCH 10/34] cre: fix rebased aptos local wiring --- system-tests/lib/cre/don.go | 16 +--------------- system-tests/lib/cre/don_test.go | 4 ++-- .../cre/environment/blockchains/aptos/aptos.go | 5 ----- system-tests/tests/go.mod | 14 +++++++++++--- system-tests/tests/go.sum | 8 ++++---- 5 files changed, 18 insertions(+), 29 deletions(-) diff --git a/system-tests/lib/cre/don.go b/system-tests/lib/cre/don.go index 13f65fd3379..2e9b583df18 100644 --- a/system-tests/lib/cre/don.go +++ b/system-tests/lib/cre/don.go @@ -594,21 +594,7 @@ func AptosAccountsForNode(_ context.Context, n *Node) ([]string, error) { n.Addresses.AptosAddresses = []string{n.Keys.AptosAccount()} return append([]string(nil), n.Addresses.AptosAddresses...), nil } - if n.Clients.RestClient == nil { - return nil, fmt.Errorf("missing cached aptos addresses for node %s and node has no rest client", n.Name) - } - - accounts, err := n.Clients.RestClient.MustReadAptosAccounts() - if err != nil { - return nil, fmt.Errorf("fetch aptos accounts for node %s: %w", n.Name, err) - } - if len(accounts) == 0 { - return nil, fmt.Errorf("no aptos accounts found for node %s", n.Name) - } - - n.Addresses.AptosAddresses = append([]string(nil), accounts...) - - return append([]string(nil), n.Addresses.AptosAddresses...), nil + return nil, fmt.Errorf("missing cached aptos addresses for node %s", n.Name) } // AcceptJob accepts the job proposal for the given job proposal spec diff --git a/system-tests/lib/cre/don_test.go b/system-tests/lib/cre/don_test.go index 1ef236a3b28..69fa7e09af8 100644 --- a/system-tests/lib/cre/don_test.go +++ b/system-tests/lib/cre/don_test.go @@ -28,7 +28,7 @@ func TestAptosAccountsForNode_ReturnsCachedAddresses(t *testing.T) { require.Equal(t, []string{"0x1", "0x2"}, node.Addresses.AptosAddresses) } -func TestAptosAccountsForNode_RequiresClientWhenCacheMissing(t *testing.T) { +func TestAptosAccountsForNode_RequiresCachedMetadataWhenCacheMissing(t *testing.T) { t.Parallel() node := &Node{ @@ -37,7 +37,7 @@ func TestAptosAccountsForNode_RequiresClientWhenCacheMissing(t *testing.T) { _, err := AptosAccountsForNode(context.Background(), node) require.Error(t, err) - require.ErrorContains(t, err, "missing cached aptos addresses for node node-1 and node has no rest client") + require.ErrorContains(t, err, "missing cached aptos addresses for node node-1") } func TestAptosAccountsForNode_ReturnsMetadataKeyWhenCacheMissing(t *testing.T) { diff --git a/system-tests/lib/cre/environment/blockchains/aptos/aptos.go b/system-tests/lib/cre/environment/blockchains/aptos/aptos.go index c30436afb6a..c221d509b79 100644 --- a/system-tests/lib/cre/environment/blockchains/aptos/aptos.go +++ b/system-tests/lib/cre/environment/blockchains/aptos/aptos.go @@ -286,11 +286,6 @@ func aptosFaucetURLFromNodeURL(nodeURL string) (string, error) { } func (a *Blockchain) faucetURL() (string, error) { - if a.ctfOutput != nil && a.ctfOutput.NetworkSpecificData != nil && a.ctfOutput.NetworkSpecificData.AptosNetwork != nil { - if faucetURL := strings.TrimSpace(a.ctfOutput.NetworkSpecificData.AptosNetwork.FaucetURL); faucetURL != "" { - return faucetURL, nil - } - } if a.ctfOutput == nil || len(a.ctfOutput.Nodes) == 0 { return "", errors.New("missing chain nodes output") } diff --git a/system-tests/tests/go.mod b/system-tests/tests/go.mod index 1eb7c99ee81..3aafecf055d 100644 --- a/system-tests/tests/go.mod +++ b/system-tests/tests/go.mod @@ -23,6 +23,12 @@ replace github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/evm/e replace github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/evm/logtrigger => ./smoke/cre/evm/logtrigger +replace github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptosread => ./smoke/cre/aptos/aptosread + +replace github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptoswrite => ./smoke/cre/aptos/aptoswrite + +replace github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip => ./smoke/cre/aptos/aptoswriteroundtrip + replace github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/httpaction => ./smoke/cre/httpaction replace github.com/smartcontractkit/chainlink/system-tests/tests/regression/cre/consensus => ./regression/cre/consensus @@ -59,7 +65,7 @@ require ( github.com/smartcontractkit/chainlink-data-streams v0.1.13 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260119171452-39c98c3b33cd - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 github.com/smartcontractkit/chainlink-protos/ring/go v0.0.0-20260128151123-605e9540b706 github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260217043601-5cc966896c4f @@ -79,6 +85,8 @@ require ( github.com/smartcontractkit/chainlink/system-tests/tests/regression/cre/evm/evmwrite-negative v0.0.0-20251008094352-f74459c46e8c github.com/smartcontractkit/chainlink/system-tests/tests/regression/cre/evm/logtrigger-negative v0.0.0-00010101000000-000000000000 github.com/smartcontractkit/chainlink/system-tests/tests/regression/cre/http v0.0.0-20251008094352-f74459c46e8c + github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptoswrite v0.0.0-00010101000000-000000000000 + github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip v0.0.0-00010101000000-000000000000 github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/evm/evmread v0.0.0-20251008094352-f74459c46e8c github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/evm/logtrigger v0.0.0-00010101000000-000000000000 github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/evmread v0.0.0-20250917232237-c4ecf802c6f8 @@ -187,7 +195,7 @@ require ( github.com/alitto/pond/v2 v2.5.0 // indirect github.com/andybalholm/brotli v1.2.0 // indirect github.com/apache/arrow-go/v18 v18.4.0 // indirect - github.com/aptos-labs/aptos-go-sdk v1.12.1-0.20260318141106-21b6ef4ed363 // indirect + github.com/aptos-labs/aptos-go-sdk v1.12.1-0.20260318141106-21b6ef4ed363 github.com/armon/go-metrics v0.4.1 // indirect github.com/atombender/go-jsonschema v0.16.1-0.20240916205339-a74cd4e2851c // indirect github.com/avast/retry-go v3.0.0+incompatible // indirect @@ -580,7 +588,7 @@ require ( github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/smartcontractkit/ccip-contract-examples/chains/evm v0.0.0-20260129135848-c86808ba5cb9 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.1.0 // indirect - github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 // indirect + github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 github.com/smartcontractkit/chainlink-automation v0.8.1 // indirect github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 // indirect github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20251211140724-319861e514c4 diff --git a/system-tests/tests/go.sum b/system-tests/tests/go.sum index 4c7f5376d6d..a50ab00d0a6 100644 --- a/system-tests/tests/go.sum +++ b/system-tests/tests/go.sum @@ -1819,8 +1819,8 @@ github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0. github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396 h1:03tbcwjyIEjvHba1IWOj1sfThwebm2XNzyFHSuZtlWc= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c h1:m+XflniQiuMPvcKtiWpnsqpOiRNcONKrhF5zwpR2QJM= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 h1:q+VDPcxWrj5k9QizSYfUOSMnDH3Sd5HvbPguZOgfXTY= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= @@ -1877,8 +1877,8 @@ github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.202602181 github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20260218133534-cbd44da2856b/go.mod h1:ea1LESxlSSOgc2zZBqf1RTkXTMthHaspdqUHd7W4lF0= github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/evmread v0.0.0-20250917232237-c4ecf802c6f8 h1:ZhpUCMDFATsyS1B+6YaAxWYfh/WsVx9WWtYSOkl5V0g= github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/evmread v0.0.0-20250917232237-c4ecf802c6f8/go.mod h1:96T5PZe9IRPcuMTnS2I2VGAtyDdkL5U9aWUykLtAYb8= -github.com/smartcontractkit/cre-sdk-go v1.5.0 h1:kepW3QDKARrOOHjXwWAZ9j5KLk6bxLzvi6OMrLsFwVo= -github.com/smartcontractkit/cre-sdk-go v1.5.0/go.mod h1:yYrQFz1UH7hhRbPO0q4fgo1tfsJNd4yXnI3oCZE0RzM= +github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 h1:sY79Ue8wkzPbpo4tFvvGSQiTMiqBvgyL0FBJV2UIhWI= +github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373/go.mod h1:MP93PP7lxaFyW+RRNYcEdXHm/gJM/HPqRPUPOAfBH4w= github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad h1:lgHxTHuzJIF3Vj6LSMOnjhqKgRqYW+0MV2SExtCYL1Q= github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad/go.mod h1:T4zH9R8R8lVWKfU7tUvYz2o2jMv1OpGCdpY2j2QZXzU= github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs= From 08e9f65658e242b7f1cd6f8b106abeae57843764 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 19 Mar 2026 17:32:08 +0000 Subject: [PATCH 11/34] ci: fix tidy drift and consensus plugin pin --- core/scripts/go.mod | 2 -- core/scripts/go.sum | 2 -- plugins/plugins.private.yaml | 2 +- system-tests/lib/go.mod | 4 ++-- system-tests/tests/smoke/cre/aptos/aptosread/go.sum | 4 ---- system-tests/tests/smoke/cre/aptos/aptoswrite/go.sum | 4 ---- system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.sum | 4 ---- 7 files changed, 3 insertions(+), 19 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 30b8a8cb860..24cdaa6f42f 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -61,7 +61,6 @@ require ( github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/cron-based v0.0.0-20251020210257-0a6ec41648b4 github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based v0.0.0-20251020210257-0a6ec41648b4 github.com/smartcontractkit/chainlink/system-tests/lib v0.0.0-20251020210257-0a6ec41648b4 - github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v1.3.0 github.com/smartcontractkit/libocr v0.0.0-20260304194147-a03701e2c02e github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 @@ -521,7 +520,6 @@ require ( github.com/smartcontractkit/chainlink-ton v0.0.0-20260318210736-c3f360fd19a8 // indirect github.com/smartcontractkit/chainlink-ton/deployment v0.0.0-20260318210736-c3f360fd19a8 // indirect github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20260218133534-cbd44da2856b // indirect - github.com/smartcontractkit/cre-sdk-go v1.5.0 // indirect github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect github.com/smartcontractkit/mcms v0.38.2 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 78bdab43d0e..6c327b0b6a2 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1724,8 +1724,6 @@ github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.202602181 github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20260218133534-cbd44da2856b/go.mod h1:ea1LESxlSSOgc2zZBqf1RTkXTMthHaspdqUHd7W4lF0= github.com/smartcontractkit/cre-sdk-go v1.5.0 h1:kepW3QDKARrOOHjXwWAZ9j5KLk6bxLzvi6OMrLsFwVo= github.com/smartcontractkit/cre-sdk-go v1.5.0/go.mod h1:yYrQFz1UH7hhRbPO0q4fgo1tfsJNd4yXnI3oCZE0RzM= -github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v1.3.0 h1:qBZ4y6qlTOynSpU1QAi2Fgr3tUZQ332b6hit9EVZqkk= -github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v1.3.0/go.mod h1:Rzhy75vD3FqQo/SV6lypnxIwjWac6IOWzI5BYj3tYMU= github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad h1:lgHxTHuzJIF3Vj6LSMOnjhqKgRqYW+0MV2SExtCYL1Q= github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad/go.mod h1:T4zH9R8R8lVWKfU7tUvYz2o2jMv1OpGCdpY2j2QZXzU= github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs= diff --git a/plugins/plugins.private.yaml b/plugins/plugins.private.yaml index 05b49902fa0..2960d11a7bc 100644 --- a/plugins/plugins.private.yaml +++ b/plugins/plugins.private.yaml @@ -23,7 +23,7 @@ plugins: installPath: "." consensus: - moduleURI: "github.com/smartcontractkit/capabilities/consensus" - gitRef: "bab47549446cf8a47093b983419dbd3f06b40329" + gitRef: "4bc25dd3e53308c15caa4f34a60d39dee2a6400c" installPath: "." workflowevent: - enabled: false diff --git a/system-tests/lib/go.mod b/system-tests/lib/go.mod index 72372ded968..c996afc9e69 100644 --- a/system-tests/lib/go.mod +++ b/system-tests/lib/go.mod @@ -16,6 +16,7 @@ require ( github.com/Masterminds/semver/v3 v3.4.0 github.com/alitto/pond/v2 v2.5.0 github.com/andybalholm/brotli v1.2.0 + github.com/aptos-labs/aptos-go-sdk v1.12.1-0.20260318141106-21b6ef4ed363 github.com/cockroachdb/errors v1.11.3 github.com/cosmos/gogoproto v1.7.0 github.com/docker/docker v28.5.2+incompatible @@ -31,6 +32,7 @@ require ( github.com/scylladb/go-reflectx v1.0.1 github.com/sethvargo/go-retry v0.3.0 github.com/smartcontractkit/chain-selectors v1.0.97 + github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-common v0.10.1-0.20260319155722-325b0156b188 github.com/smartcontractkit/chainlink-common/keystore v1.0.2 @@ -94,7 +96,6 @@ require ( github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect github.com/apache/arrow-go/v18 v18.3.1 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect - github.com/aptos-labs/aptos-go-sdk v1.12.1-0.20260318141106-21b6ef4ed363 // indirect github.com/atombender/go-jsonschema v0.16.1-0.20240916205339-a74cd4e2851c // indirect github.com/avast/retry-go v3.0.0+incompatible // indirect github.com/avast/retry-go/v4 v4.7.0 // indirect @@ -447,7 +448,6 @@ require ( github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/smartcontractkit/ccip-contract-examples/chains/evm v0.0.0-20260129135848-c86808ba5cb9 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.1.0 // indirect - github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 // indirect github.com/smartcontractkit/chainlink-automation v0.8.1 // indirect github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 // indirect github.com/smartcontractkit/chainlink-ccip/ccv/chains/evm v0.0.0-20260313162934-73fcb2020b93 // indirect diff --git a/system-tests/tests/smoke/cre/aptos/aptosread/go.sum b/system-tests/tests/smoke/cre/aptos/aptosread/go.sum index 22417e77c98..314c081af43 100644 --- a/system-tests/tests/smoke/cre/aptos/aptosread/go.sum +++ b/system-tests/tests/smoke/cre/aptos/aptosread/go.sum @@ -8,12 +8,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260317131216-1b30a2aeee6a h1:xVDm2UqUwhAMFwXGOm7sGD97+g9IhUMDioi917GMltI= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260317131216-1b30a2aeee6a/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c h1:m+XflniQiuMPvcKtiWpnsqpOiRNcONKrhF5zwpR2QJM= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= -github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260317133250-2edd562283ed h1:u6eLUgwf3bAEa75R0wYZxmXCr7momhl3yOSIogAufdU= -github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260317133250-2edd562283ed/go.mod h1:L/02KvMl4ZtFc16LvBZQcvX4b0pCU1lQtcsZLyWMvFE= github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 h1:sY79Ue8wkzPbpo4tFvvGSQiTMiqBvgyL0FBJV2UIhWI= github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373/go.mod h1:MP93PP7lxaFyW+RRNYcEdXHm/gJM/HPqRPUPOAfBH4w= github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed h1:sShKvyFh1MNBXW5cxau/U2IB4dTdYGah/n5d9G0gOnA= diff --git a/system-tests/tests/smoke/cre/aptos/aptoswrite/go.sum b/system-tests/tests/smoke/cre/aptos/aptoswrite/go.sum index 22417e77c98..314c081af43 100644 --- a/system-tests/tests/smoke/cre/aptos/aptoswrite/go.sum +++ b/system-tests/tests/smoke/cre/aptos/aptoswrite/go.sum @@ -8,12 +8,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260317131216-1b30a2aeee6a h1:xVDm2UqUwhAMFwXGOm7sGD97+g9IhUMDioi917GMltI= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260317131216-1b30a2aeee6a/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c h1:m+XflniQiuMPvcKtiWpnsqpOiRNcONKrhF5zwpR2QJM= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= -github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260317133250-2edd562283ed h1:u6eLUgwf3bAEa75R0wYZxmXCr7momhl3yOSIogAufdU= -github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260317133250-2edd562283ed/go.mod h1:L/02KvMl4ZtFc16LvBZQcvX4b0pCU1lQtcsZLyWMvFE= github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 h1:sY79Ue8wkzPbpo4tFvvGSQiTMiqBvgyL0FBJV2UIhWI= github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373/go.mod h1:MP93PP7lxaFyW+RRNYcEdXHm/gJM/HPqRPUPOAfBH4w= github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed h1:sShKvyFh1MNBXW5cxau/U2IB4dTdYGah/n5d9G0gOnA= diff --git a/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.sum b/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.sum index 22417e77c98..314c081af43 100644 --- a/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.sum +++ b/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.sum @@ -8,12 +8,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260317131216-1b30a2aeee6a h1:xVDm2UqUwhAMFwXGOm7sGD97+g9IhUMDioi917GMltI= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260317131216-1b30a2aeee6a/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c h1:m+XflniQiuMPvcKtiWpnsqpOiRNcONKrhF5zwpR2QJM= github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= -github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260317133250-2edd562283ed h1:u6eLUgwf3bAEa75R0wYZxmXCr7momhl3yOSIogAufdU= -github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260317133250-2edd562283ed/go.mod h1:L/02KvMl4ZtFc16LvBZQcvX4b0pCU1lQtcsZLyWMvFE= github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 h1:sY79Ue8wkzPbpo4tFvvGSQiTMiqBvgyL0FBJV2UIhWI= github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373/go.mod h1:MP93PP7lxaFyW+RRNYcEdXHm/gJM/HPqRPUPOAfBH4w= github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed h1:sShKvyFh1MNBXW5cxau/U2IB4dTdYGah/n5d9G0gOnA= From bfb4880064387a2b8128e1ae658f2faa6ccd781d Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 19 Mar 2026 18:10:14 +0000 Subject: [PATCH 12/34] aptos: provide cli fallback for forwarder deploy --- system-tests/lib/cre/features/aptos/aptos.go | 84 ++++++++++++++++++ .../lib/cre/features/aptos/aptos_test.go | 88 +++++++++++++++++++ 2 files changed, 172 insertions(+) diff --git a/system-tests/lib/cre/features/aptos/aptos.go b/system-tests/lib/cre/features/aptos/aptos.go index 6db9bd7f576..e31c076ee7e 100644 --- a/system-tests/lib/cre/features/aptos/aptos.go +++ b/system-tests/lib/cre/features/aptos/aptos.go @@ -7,6 +7,9 @@ import ( stderrors "errors" "fmt" "net/url" + "os" + osexec "os/exec" + "path/filepath" "strconv" "strings" "text/template" @@ -69,6 +72,9 @@ const ( var forwarderContractVersion = semver.MustParse("1.0.0") +var aptosLookPath = osexec.LookPath +var aptosContainerImage = aptosContainerImageFromDocker + type Aptos struct{} type methodConfigSettings struct { @@ -545,6 +551,12 @@ func ensureForwarder( Msg("Aptos deployer account not confirmed visible yet; proceeding with deploy retries") } + restoreAptosCLI, err := prepareAptosCLI(ctx, containerName) + if err != nil { + return "", fmt.Errorf("failed to prepare Aptos CLI for forwarder deploy on chain selector %d: %w", chain.ChainSelector(), err) + } + defer restoreAptosCLI() + var deployedAddress string var pendingTxHash string var lastDeployErr error @@ -593,6 +605,78 @@ func ensureForwarder( return addr, nil } +// prepareAptosCLI makes the host aptos CLI available for Move package +// compilation. Local CRE runners do not always have aptos installed, so fall +// back to a thin wrapper that runs the CLI from the existing Aptos container +// image with the current working directory bind-mounted. +func prepareAptosCLI(ctx context.Context, containerName string) (func(), error) { + if _, err := aptosLookPath("aptos"); err == nil { + return func() {}, nil + } + + containerName = strings.TrimSpace(containerName) + if containerName == "" { + return nil, pkgerrors.New("aptos CLI not found on PATH and no Aptos container is available for fallback") + } + + image, err := aptosContainerImage(ctx, containerName) + if err != nil { + return nil, err + } + + wrapperDir, err := os.MkdirTemp("", "aptos-cli-wrapper-*") + if err != nil { + return nil, fmt.Errorf("create Aptos CLI wrapper directory: %w", err) + } + + wrapperPath := filepath.Join(wrapperDir, "aptos") + script := fmt.Sprintf(`#!/bin/sh +set -eu +pwd_path="$(pwd -P)" +exec docker run --rm \ + -v "$pwd_path:$pwd_path" \ + -w "$pwd_path" \ + --entrypoint aptos \ + %q "$@" +`, image) + if err := os.WriteFile(wrapperPath, []byte(script), 0o755); err != nil { + _ = os.RemoveAll(wrapperDir) + return nil, fmt.Errorf("write Aptos CLI wrapper script: %w", err) + } + + oldPath := os.Getenv("PATH") + if oldPath == "" { + if err := os.Setenv("PATH", wrapperDir); err != nil { + _ = os.RemoveAll(wrapperDir) + return nil, fmt.Errorf("prepend Aptos CLI wrapper to PATH: %w", err) + } + } else { + if err := os.Setenv("PATH", wrapperDir+string(os.PathListSeparator)+oldPath); err != nil { + _ = os.RemoveAll(wrapperDir) + return nil, fmt.Errorf("prepend Aptos CLI wrapper to PATH: %w", err) + } + } + + return func() { + _ = os.Setenv("PATH", oldPath) + _ = os.RemoveAll(wrapperDir) + }, nil +} + +func aptosContainerImageFromDocker(ctx context.Context, containerName string) (string, error) { + out, err := osexec.CommandContext(ctx, "docker", "inspect", "--format", "{{.Config.Image}}", containerName).CombinedOutput() + if err != nil { + return "", fmt.Errorf("inspect Aptos container image for %q: %w (%s)", containerName, err, strings.TrimSpace(string(out))) + } + + image := strings.TrimSpace(string(out)) + if image == "" { + return "", fmt.Errorf("inspect Aptos container image for %q: empty image reference", containerName) + } + + return image, nil +} + // addForwarderToDataStore seals a new datastore snapshot with the Aptos // forwarder address so later setup phases can reuse it without redeploying. func addForwarderToDataStore(creEnv *cre.Environment, chainSelector uint64, address string) error { diff --git a/system-tests/lib/cre/features/aptos/aptos_test.go b/system-tests/lib/cre/features/aptos/aptos_test.go index 0714090a74b..b057c14f7a7 100644 --- a/system-tests/lib/cre/features/aptos/aptos_test.go +++ b/system-tests/lib/cre/features/aptos/aptos_test.go @@ -1,8 +1,12 @@ package aptos import ( + "context" "encoding/hex" "math/big" + "os" + "path/filepath" + "strings" "testing" "time" @@ -241,3 +245,87 @@ func TestResolveMethodConfigSettings_InvalidTransmissionSchedule(t *testing.T) { }) require.Error(t, err) } + +func TestPrepareAptosCLI_UsesHostBinaryWhenAvailable(t *testing.T) { + t.Setenv("PATH", "/usr/bin") + + originalLookPath := aptosLookPath + originalContainerImage := aptosContainerImage + aptosLookPath = func(file string) (string, error) { + require.Equal(t, "aptos", file) + return "/usr/bin/aptos", nil + } + aptosContainerImage = func(context.Context, string) (string, error) { + t.Fatal("container fallback should not be used when host aptos exists") + return "", nil + } + t.Cleanup(func() { + aptosLookPath = originalLookPath + aptosContainerImage = originalContainerImage + }) + + restore, err := prepareAptosCLI(context.Background(), "aptos-node") + require.NoError(t, err) + require.Equal(t, "/usr/bin", os.Getenv("PATH")) + + restore() + require.Equal(t, "/usr/bin", os.Getenv("PATH")) +} + +func TestPrepareAptosCLI_BuildsContainerWrapperWhenHostBinaryMissing(t *testing.T) { + t.Setenv("PATH", "/usr/bin") + + originalLookPath := aptosLookPath + originalContainerImage := aptosContainerImage + aptosLookPath = func(file string) (string, error) { + require.Equal(t, "aptos", file) + return "", os.ErrNotExist + } + aptosContainerImage = func(ctx context.Context, containerName string) (string, error) { + require.Equal(t, "aptos-node", containerName) + return "ghcr.io/example/aptos:latest", nil + } + t.Cleanup(func() { + aptosLookPath = originalLookPath + aptosContainerImage = originalContainerImage + }) + + restore, err := prepareAptosCLI(context.Background(), "aptos-node") + require.NoError(t, err) + t.Cleanup(restore) + + pathParts := strings.Split(os.Getenv("PATH"), string(os.PathListSeparator)) + require.Len(t, pathParts, 2) + require.Equal(t, "/usr/bin", pathParts[1]) + + wrapperPath := filepath.Join(pathParts[0], "aptos") + content, err := os.ReadFile(wrapperPath) + require.NoError(t, err) + require.Contains(t, string(content), `--entrypoint aptos \`) + require.Contains(t, string(content), `"ghcr.io/example/aptos:latest" "$@"`) + + restore() + require.Equal(t, "/usr/bin", os.Getenv("PATH")) + _, err = os.Stat(wrapperPath) + require.ErrorIs(t, err, os.ErrNotExist) +} + +func TestPrepareAptosCLI_RequiresContainerWhenHostBinaryMissing(t *testing.T) { + originalLookPath := aptosLookPath + originalContainerImage := aptosContainerImage + aptosLookPath = func(string) (string, error) { + return "", os.ErrNotExist + } + aptosContainerImage = func(context.Context, string) (string, error) { + t.Fatal("container image lookup should not be used without a container name") + return "", nil + } + t.Cleanup(func() { + aptosLookPath = originalLookPath + aptosContainerImage = originalContainerImage + }) + + restore, err := prepareAptosCLI(context.Background(), "") + require.Nil(t, restore) + require.ErrorContains(t, err, "aptos CLI not found on PATH") +} From 6321a3e4308934555842a9c7d0214cb64ef23e20 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 19 Mar 2026 19:43:19 +0000 Subject: [PATCH 13/34] aptos: reuse cli fallback in smoke deploys --- system-tests/lib/cre/features/aptos/aptos.go | 13 ++++++++++++- .../tests/smoke/cre/v2_aptos_capability_test.go | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/system-tests/lib/cre/features/aptos/aptos.go b/system-tests/lib/cre/features/aptos/aptos.go index e31c076ee7e..48577960b7b 100644 --- a/system-tests/lib/cre/features/aptos/aptos.go +++ b/system-tests/lib/cre/features/aptos/aptos.go @@ -634,15 +634,20 @@ func prepareAptosCLI(ctx context.Context, containerName string) (func(), error) set -eu pwd_path="$(pwd -P)" exec docker run --rm \ + --user "$(id -u):$(id -g)" \ -v "$pwd_path:$pwd_path" \ -w "$pwd_path" \ --entrypoint aptos \ %q "$@" `, image) - if err := os.WriteFile(wrapperPath, []byte(script), 0o755); err != nil { + if err := os.WriteFile(wrapperPath, []byte(script), 0o600); err != nil { _ = os.RemoveAll(wrapperDir) return nil, fmt.Errorf("write Aptos CLI wrapper script: %w", err) } + if err := os.Chmod(wrapperPath, 0o700); err != nil { + _ = os.RemoveAll(wrapperDir) + return nil, fmt.Errorf("mark Aptos CLI wrapper script executable: %w", err) + } oldPath := os.Getenv("PATH") if oldPath == "" { @@ -663,6 +668,12 @@ exec docker run --rm \ }, nil } +// PrepareAptosCLI ensures the aptos CLI is available for local smoke tests and +// setup phases that compile Move packages on the host. +func PrepareAptosCLI(ctx context.Context, containerName string) (func(), error) { + return prepareAptosCLI(ctx, containerName) +} + func aptosContainerImageFromDocker(ctx context.Context, containerName string) (string, error) { out, err := osexec.CommandContext(ctx, "docker", "inspect", "--format", "{{.Config.Image}}", containerName).CombinedOutput() if err != nil { diff --git a/system-tests/tests/smoke/cre/v2_aptos_capability_test.go b/system-tests/tests/smoke/cre/v2_aptos_capability_test.go index f2c63fa4537..dcef366c1aa 100644 --- a/system-tests/tests/smoke/cre/v2_aptos_capability_test.go +++ b/system-tests/tests/smoke/cre/v2_aptos_capability_test.go @@ -578,6 +578,10 @@ func deployAptosDataFeedsReceiverForWrite( require.NoError(t, err, "failed to parse primary forwarder address") owner := deployer.AccountAddress() + restoreAptosCLI, err := aptosfeature.PrepareAptosCLI(t.Context(), containerName) + require.NoError(t, err, "failed to prepare Aptos CLI for local package deploys") + t.Cleanup(restoreAptosCLI) + secondaryAddress, secondaryTx, _, err := aptosplatformsecondary.DeployToObject(deployer, client, owner) require.NoError(t, err, "failed to deploy Aptos secondary platform package") require.NoError(t, aptosfeature.WaitForTransactionSuccess(client, secondaryTx.Hash, "platform_secondary deployment")) From 9a6e76f70cf63eb681da54113615b65901a1712b Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 19 Mar 2026 21:54:00 +0000 Subject: [PATCH 14/34] ci: install aptos cli for cre aptos suite --- .github/workflows/cre-system-tests.yaml | 29 ++++++ system-tests/lib/cre/features/aptos/aptos.go | 95 ------------------- .../lib/cre/features/aptos/aptos_test.go | 88 ----------------- .../smoke/cre/v2_aptos_capability_test.go | 4 - 4 files changed, 29 insertions(+), 187 deletions(-) diff --git a/.github/workflows/cre-system-tests.yaml b/.github/workflows/cre-system-tests.yaml index b9e44a9b936..988028dc9d8 100644 --- a/.github/workflows/cre-system-tests.yaml +++ b/.github/workflows/cre-system-tests.yaml @@ -213,6 +213,35 @@ jobs: chmod +x bin/ctf echo "::endgroup::" + - name: Install Aptos CLI + if: ${{ matrix.tests.test_name == 'Test_CRE_V2_Aptos_Suite' }} + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + APTOS_CLI_TAG: "aptos-cli-v7.8.0" + run: | + echo "::startgroup::Install Aptos CLI" + bin_dir="$HOME/.local/bin" + mkdir -p "$bin_dir" + + gh release download "${APTOS_CLI_TAG}" \ + --pattern "aptos-cli-*-Ubuntu-24.04-x86_64.zip" \ + --clobber \ + --repo aptos-labs/aptos-core \ + -O aptos-cli.zip + + unzip -o aptos-cli.zip -d aptos-cli-extract >/dev/null + aptos_path="$(find aptos-cli-extract -type f -name aptos | head -n1)" + if [[ -z "$aptos_path" ]]; then + echo "failed to locate aptos binary in release archive" + exit 1 + fi + + install -m 0755 "$aptos_path" "$bin_dir/aptos" + echo "$bin_dir" >> "$GITHUB_PATH" + "$bin_dir/aptos" --version + echo "::endgroup::" + - name: Start local CRE${{ matrix.tests.cre_version }} shell: bash id: start-local-cre diff --git a/system-tests/lib/cre/features/aptos/aptos.go b/system-tests/lib/cre/features/aptos/aptos.go index 48577960b7b..6db9bd7f576 100644 --- a/system-tests/lib/cre/features/aptos/aptos.go +++ b/system-tests/lib/cre/features/aptos/aptos.go @@ -7,9 +7,6 @@ import ( stderrors "errors" "fmt" "net/url" - "os" - osexec "os/exec" - "path/filepath" "strconv" "strings" "text/template" @@ -72,9 +69,6 @@ const ( var forwarderContractVersion = semver.MustParse("1.0.0") -var aptosLookPath = osexec.LookPath -var aptosContainerImage = aptosContainerImageFromDocker - type Aptos struct{} type methodConfigSettings struct { @@ -551,12 +545,6 @@ func ensureForwarder( Msg("Aptos deployer account not confirmed visible yet; proceeding with deploy retries") } - restoreAptosCLI, err := prepareAptosCLI(ctx, containerName) - if err != nil { - return "", fmt.Errorf("failed to prepare Aptos CLI for forwarder deploy on chain selector %d: %w", chain.ChainSelector(), err) - } - defer restoreAptosCLI() - var deployedAddress string var pendingTxHash string var lastDeployErr error @@ -605,89 +593,6 @@ func ensureForwarder( return addr, nil } -// prepareAptosCLI makes the host aptos CLI available for Move package -// compilation. Local CRE runners do not always have aptos installed, so fall -// back to a thin wrapper that runs the CLI from the existing Aptos container -// image with the current working directory bind-mounted. -func prepareAptosCLI(ctx context.Context, containerName string) (func(), error) { - if _, err := aptosLookPath("aptos"); err == nil { - return func() {}, nil - } - - containerName = strings.TrimSpace(containerName) - if containerName == "" { - return nil, pkgerrors.New("aptos CLI not found on PATH and no Aptos container is available for fallback") - } - - image, err := aptosContainerImage(ctx, containerName) - if err != nil { - return nil, err - } - - wrapperDir, err := os.MkdirTemp("", "aptos-cli-wrapper-*") - if err != nil { - return nil, fmt.Errorf("create Aptos CLI wrapper directory: %w", err) - } - - wrapperPath := filepath.Join(wrapperDir, "aptos") - script := fmt.Sprintf(`#!/bin/sh -set -eu -pwd_path="$(pwd -P)" -exec docker run --rm \ - --user "$(id -u):$(id -g)" \ - -v "$pwd_path:$pwd_path" \ - -w "$pwd_path" \ - --entrypoint aptos \ - %q "$@" -`, image) - if err := os.WriteFile(wrapperPath, []byte(script), 0o600); err != nil { - _ = os.RemoveAll(wrapperDir) - return nil, fmt.Errorf("write Aptos CLI wrapper script: %w", err) - } - if err := os.Chmod(wrapperPath, 0o700); err != nil { - _ = os.RemoveAll(wrapperDir) - return nil, fmt.Errorf("mark Aptos CLI wrapper script executable: %w", err) - } - - oldPath := os.Getenv("PATH") - if oldPath == "" { - if err := os.Setenv("PATH", wrapperDir); err != nil { - _ = os.RemoveAll(wrapperDir) - return nil, fmt.Errorf("prepend Aptos CLI wrapper to PATH: %w", err) - } - } else { - if err := os.Setenv("PATH", wrapperDir+string(os.PathListSeparator)+oldPath); err != nil { - _ = os.RemoveAll(wrapperDir) - return nil, fmt.Errorf("prepend Aptos CLI wrapper to PATH: %w", err) - } - } - - return func() { - _ = os.Setenv("PATH", oldPath) - _ = os.RemoveAll(wrapperDir) - }, nil -} - -// PrepareAptosCLI ensures the aptos CLI is available for local smoke tests and -// setup phases that compile Move packages on the host. -func PrepareAptosCLI(ctx context.Context, containerName string) (func(), error) { - return prepareAptosCLI(ctx, containerName) -} - -func aptosContainerImageFromDocker(ctx context.Context, containerName string) (string, error) { - out, err := osexec.CommandContext(ctx, "docker", "inspect", "--format", "{{.Config.Image}}", containerName).CombinedOutput() - if err != nil { - return "", fmt.Errorf("inspect Aptos container image for %q: %w (%s)", containerName, err, strings.TrimSpace(string(out))) - } - - image := strings.TrimSpace(string(out)) - if image == "" { - return "", fmt.Errorf("inspect Aptos container image for %q: empty image reference", containerName) - } - - return image, nil -} - // addForwarderToDataStore seals a new datastore snapshot with the Aptos // forwarder address so later setup phases can reuse it without redeploying. func addForwarderToDataStore(creEnv *cre.Environment, chainSelector uint64, address string) error { diff --git a/system-tests/lib/cre/features/aptos/aptos_test.go b/system-tests/lib/cre/features/aptos/aptos_test.go index b057c14f7a7..0714090a74b 100644 --- a/system-tests/lib/cre/features/aptos/aptos_test.go +++ b/system-tests/lib/cre/features/aptos/aptos_test.go @@ -1,12 +1,8 @@ package aptos import ( - "context" "encoding/hex" "math/big" - "os" - "path/filepath" - "strings" "testing" "time" @@ -245,87 +241,3 @@ func TestResolveMethodConfigSettings_InvalidTransmissionSchedule(t *testing.T) { }) require.Error(t, err) } - -func TestPrepareAptosCLI_UsesHostBinaryWhenAvailable(t *testing.T) { - t.Setenv("PATH", "/usr/bin") - - originalLookPath := aptosLookPath - originalContainerImage := aptosContainerImage - aptosLookPath = func(file string) (string, error) { - require.Equal(t, "aptos", file) - return "/usr/bin/aptos", nil - } - aptosContainerImage = func(context.Context, string) (string, error) { - t.Fatal("container fallback should not be used when host aptos exists") - return "", nil - } - t.Cleanup(func() { - aptosLookPath = originalLookPath - aptosContainerImage = originalContainerImage - }) - - restore, err := prepareAptosCLI(context.Background(), "aptos-node") - require.NoError(t, err) - require.Equal(t, "/usr/bin", os.Getenv("PATH")) - - restore() - require.Equal(t, "/usr/bin", os.Getenv("PATH")) -} - -func TestPrepareAptosCLI_BuildsContainerWrapperWhenHostBinaryMissing(t *testing.T) { - t.Setenv("PATH", "/usr/bin") - - originalLookPath := aptosLookPath - originalContainerImage := aptosContainerImage - aptosLookPath = func(file string) (string, error) { - require.Equal(t, "aptos", file) - return "", os.ErrNotExist - } - aptosContainerImage = func(ctx context.Context, containerName string) (string, error) { - require.Equal(t, "aptos-node", containerName) - return "ghcr.io/example/aptos:latest", nil - } - t.Cleanup(func() { - aptosLookPath = originalLookPath - aptosContainerImage = originalContainerImage - }) - - restore, err := prepareAptosCLI(context.Background(), "aptos-node") - require.NoError(t, err) - t.Cleanup(restore) - - pathParts := strings.Split(os.Getenv("PATH"), string(os.PathListSeparator)) - require.Len(t, pathParts, 2) - require.Equal(t, "/usr/bin", pathParts[1]) - - wrapperPath := filepath.Join(pathParts[0], "aptos") - content, err := os.ReadFile(wrapperPath) - require.NoError(t, err) - require.Contains(t, string(content), `--entrypoint aptos \`) - require.Contains(t, string(content), `"ghcr.io/example/aptos:latest" "$@"`) - - restore() - require.Equal(t, "/usr/bin", os.Getenv("PATH")) - _, err = os.Stat(wrapperPath) - require.ErrorIs(t, err, os.ErrNotExist) -} - -func TestPrepareAptosCLI_RequiresContainerWhenHostBinaryMissing(t *testing.T) { - originalLookPath := aptosLookPath - originalContainerImage := aptosContainerImage - aptosLookPath = func(string) (string, error) { - return "", os.ErrNotExist - } - aptosContainerImage = func(context.Context, string) (string, error) { - t.Fatal("container image lookup should not be used without a container name") - return "", nil - } - t.Cleanup(func() { - aptosLookPath = originalLookPath - aptosContainerImage = originalContainerImage - }) - - restore, err := prepareAptosCLI(context.Background(), "") - require.Nil(t, restore) - require.ErrorContains(t, err, "aptos CLI not found on PATH") -} diff --git a/system-tests/tests/smoke/cre/v2_aptos_capability_test.go b/system-tests/tests/smoke/cre/v2_aptos_capability_test.go index dcef366c1aa..f2c63fa4537 100644 --- a/system-tests/tests/smoke/cre/v2_aptos_capability_test.go +++ b/system-tests/tests/smoke/cre/v2_aptos_capability_test.go @@ -578,10 +578,6 @@ func deployAptosDataFeedsReceiverForWrite( require.NoError(t, err, "failed to parse primary forwarder address") owner := deployer.AccountAddress() - restoreAptosCLI, err := aptosfeature.PrepareAptosCLI(t.Context(), containerName) - require.NoError(t, err, "failed to prepare Aptos CLI for local package deploys") - t.Cleanup(restoreAptosCLI) - secondaryAddress, secondaryTx, _, err := aptosplatformsecondary.DeployToObject(deployer, client, owner) require.NoError(t, err, "failed to deploy Aptos secondary platform package") require.NoError(t, aptosfeature.WaitForTransactionSuccess(client, secondaryTx.Hash, "platform_secondary deployment")) From c76d8355c797e23bca8594971caa14e25b926315 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Fri, 20 Mar 2026 14:00:06 +0000 Subject: [PATCH 15/34] cre: tighten aptos local setup and key wiring --- .../configs/workflow-gateway-don-aptos.toml | 11 +- .../environment/environment/environment.go | 10 +- deployment/cre/jobs/propose_job_spec.go | 2 +- deployment/cre/jobs/types/job_spec.go | 5 +- deployment/cre/jobs/types/job_spec_test.go | 14 +- system-tests/lib/cre/contracts/keystone.go | 8 +- system-tests/lib/cre/don.go | 64 +++-- system-tests/lib/cre/don/config/config.go | 2 +- system-tests/lib/cre/don_test.go | 72 +++-- .../environment/blockchains/aptos/aptos.go | 29 +- .../blockchains/aptos/aptos_test.go | 36 +++ .../lib/cre/environment/config/config.go | 4 +- system-tests/lib/cre/environment/dons.go | 5 +- system-tests/lib/cre/features/aptos/aptos.go | 270 +++--------------- .../lib/cre/features/aptos/aptos_test.go | 29 -- .../features/read_contract/read_contract.go | 13 +- .../read_contract/read_contract_test.go | 39 ++- system-tests/lib/cre/types.go | 19 +- system-tests/lib/cre/types_nodekeys_test.go | 4 +- .../smoke/cre/v2_aptos_capability_test.go | 156 +++++----- .../tests/test-helpers/before_suite.go | 3 +- 21 files changed, 350 insertions(+), 445 deletions(-) create mode 100644 system-tests/lib/cre/environment/blockchains/aptos/aptos_test.go diff --git a/core/scripts/cre/environment/configs/workflow-gateway-don-aptos.toml b/core/scripts/cre/environment/configs/workflow-gateway-don-aptos.toml index 37a3a5acd18..db91c3d170f 100644 --- a/core/scripts/cre/environment/configs/workflow-gateway-don-aptos.toml +++ b/core/scripts/cre/environment/configs/workflow-gateway-don-aptos.toml @@ -16,12 +16,6 @@ # change to your version image = "job-distributor:0.22.1" -[fake] - port = 8171 - -[fake_http] - port = 8666 - #[s3provider] # # use all defaults # port = 9000 @@ -39,8 +33,8 @@ http_port_range_start = 10100 supported_evm_chains = [1337] - env_vars = { CL_EVM_CMD = "", HOME = "/tmp", CL_CRE_SETTINGS_DEFAULT = '{"PerWorkflow":{"CapabilityCallTimeout":"5m0s","ChainAllowed":{"Default":"false","Values":{"1337":"true","4457093679053095497":"true"}},"ChainWrite":{"EVM":{"GasLimit":{"Default":"5000000","Values":{"1337":"10000000"}}}}}}' } - capabilities = ["ocr3", "custom-compute", "web-api-trigger", "cron", "http-action", "http-trigger", "consensus", "don-time", "write-evm-1337", "read-contract-1337", "read-contract-4", "write-aptos-4", "evm-1337"] + env_vars = { CL_CRE_SETTINGS_DEFAULT = '{"PerWorkflow":{"CapabilityCallTimeout":"5m0s","ChainAllowed":{"Default":"false","Values":{"1337":"true","4457093679053095497":"true"}},"ChainWrite":{"EVM":{"GasLimit":{"Default":"5000000","Values":{"1337":"10000000"}}}}}}' } + capabilities = ["cron", "consensus", "read-contract-4", "write-aptos-4"] registry_based_launch_allowlist = ["cron-trigger@1.0.0"] [nodesets.db] @@ -63,7 +57,6 @@ override_mode = "each" http_port_range_start = 10300 - env_vars = { CL_EVM_CMD = "", HOME = "/tmp" } supported_evm_chains = [1337] [nodesets.db] diff --git a/core/scripts/cre/environment/environment/environment.go b/core/scripts/cre/environment/environment/environment.go index ce29343e41d..14be3834c22 100644 --- a/core/scripts/cre/environment/environment/environment.go +++ b/core/scripts/cre/environment/environment/environment.go @@ -336,8 +336,16 @@ func startCmd() *cobra.Command { } features := feature_set.New() + extraAllowedPorts := append([]int(nil), extraAllowedGatewayPorts...) + if in.Fake != nil { + extraAllowedPorts = append(extraAllowedPorts, in.Fake.Port) + } + if in.FakeHTTP != nil { + extraAllowedPorts = append(extraAllowedPorts, in.FakeHTTP.Port) + } + gatewayWhitelistConfig := gateway.WhitelistConfig{ - ExtraAllowedPorts: append(extraAllowedGatewayPorts, in.Fake.Port, in.FakeHTTP.Port), + ExtraAllowedPorts: extraAllowedPorts, ExtraAllowedIPsCIDR: []string{"0.0.0.0/0"}, } output, startErr := StartCLIEnvironment(cmdContext, relativePathToRepoRoot, in, nil, features, nil, envDependencies, gatewayWhitelistConfig) diff --git a/deployment/cre/jobs/propose_job_spec.go b/deployment/cre/jobs/propose_job_spec.go index dba8b30e6ec..c714f75ec18 100644 --- a/deployment/cre/jobs/propose_job_spec.go +++ b/deployment/cre/jobs/propose_job_spec.go @@ -91,7 +91,7 @@ func (u ProposeJobSpec) Apply(e cldf.Environment, input ProposeJobSpecInput) (cl switch input.Template { // This will hold all standard capabilities jobs as we add support for them. case job_types.EVM, job_types.Cron, job_types.HTTPTrigger, job_types.HTTPAction, job_types.ConfidentialHTTP, job_types.Consensus, job_types.WebAPITrigger, job_types.WebAPITarget, job_types.CustomCompute, job_types.LogEventTrigger, job_types.ReadContract, job_types.Solana: - job, err := input.Inputs.ToStandardCapabilityJob(input.JobName, false) + job, err := input.Inputs.ToStandardCapabilityJob(input.JobName) if err != nil { return cldf.ChangesetOutput{}, fmt.Errorf("failed to convert inputs to standard capability job: %w", err) } diff --git a/deployment/cre/jobs/types/job_spec.go b/deployment/cre/jobs/types/job_spec.go index ed03ba6a336..94bf847197c 100644 --- a/deployment/cre/jobs/types/job_spec.go +++ b/deployment/cre/jobs/types/job_spec.go @@ -30,10 +30,9 @@ func (j JobSpecInput) UnmarshalFrom(source any) error { return yaml.Unmarshal(bytes, &j) } -func (j JobSpecInput) ToStandardCapabilityJob(jobName string, generateOracleFactory bool) (pkg.StandardCapabilityJob, error) { +func (j JobSpecInput) ToStandardCapabilityJob(jobName string) (pkg.StandardCapabilityJob, error) { out := pkg.StandardCapabilityJob{ - JobName: jobName, - GenerateOracleFactory: generateOracleFactory, + JobName: jobName, } err := j.UnmarshalTo(&out) if err != nil { diff --git a/deployment/cre/jobs/types/job_spec_test.go b/deployment/cre/jobs/types/job_spec_test.go index 1cacb68e02f..1ad9ae9a960 100644 --- a/deployment/cre/jobs/types/job_spec_test.go +++ b/deployment/cre/jobs/types/job_spec_test.go @@ -34,7 +34,7 @@ func TestJobSpecInput_ToStandardCapabilityJob(t *testing.T) { }, } - job, err := input.ToStandardCapabilityJob(jobName, false) + job, err := input.ToStandardCapabilityJob(jobName) require.NoError(t, err) assert.Equal(t, jobName, job.JobName) assert.Equal(t, "run", job.Command) @@ -56,7 +56,7 @@ func TestJobSpecInput_ToStandardCapabilityJob(t *testing.T) { "externalJobID": "123", "oracleFactory": pkg.OracleFactory{}, } - _, err := input.ToStandardCapabilityJob(jobName, false) + _, err := input.ToStandardCapabilityJob(jobName) require.Error(t, err) assert.Contains(t, err.Error(), "command is required") }) @@ -68,7 +68,7 @@ func TestJobSpecInput_ToStandardCapabilityJob(t *testing.T) { "externalJobID": "123", "oracleFactory": pkg.OracleFactory{}, } - _, err := input.ToStandardCapabilityJob(jobName, false) + _, err := input.ToStandardCapabilityJob(jobName) require.Error(t, err) assert.Contains(t, err.Error(), "command is required and must be a string") }) @@ -80,7 +80,7 @@ func TestJobSpecInput_ToStandardCapabilityJob(t *testing.T) { "externalJobID": "123", "oracleFactory": pkg.OracleFactory{}, } - _, err := input.ToStandardCapabilityJob(jobName, false) + _, err := input.ToStandardCapabilityJob(jobName) require.NoError(t, err) }) @@ -91,7 +91,7 @@ func TestJobSpecInput_ToStandardCapabilityJob(t *testing.T) { "externalJobID": "123", "oracleFactory": pkg.OracleFactory{}, } - _, err := input.ToStandardCapabilityJob(jobName, false) + _, err := input.ToStandardCapabilityJob(jobName) require.Error(t, err) assert.Contains(t, err.Error(), "cannot unmarshal !!map into string") }) @@ -103,7 +103,7 @@ func TestJobSpecInput_ToStandardCapabilityJob(t *testing.T) { "externalJobID": struct{}{}, "oracleFactory": pkg.OracleFactory{}, } - _, err := input.ToStandardCapabilityJob(jobName, false) + _, err := input.ToStandardCapabilityJob(jobName) require.Error(t, err) assert.Contains(t, err.Error(), "cannot unmarshal !!map into string") }) @@ -115,7 +115,7 @@ func TestJobSpecInput_ToStandardCapabilityJob(t *testing.T) { "externalJobID": "123", "oracleFactory": "not a factory", } - _, err := input.ToStandardCapabilityJob(jobName, false) + _, err := input.ToStandardCapabilityJob(jobName) require.Error(t, err) assert.Contains(t, err.Error(), "cannot unmarshal !!str") }) diff --git a/system-tests/lib/cre/contracts/keystone.go b/system-tests/lib/cre/contracts/keystone.go index 2abc52ee379..a9cd9496c01 100644 --- a/system-tests/lib/cre/contracts/keystone.go +++ b/system-tests/lib/cre/contracts/keystone.go @@ -214,11 +214,11 @@ func (d *dons) mustToV2ConfigureInput(chainSelector uint64, contractAddress stri for i, nop := range don.Nops { nopName := nop.Name - ns, err := deployment.NodeInfo(nop.Nodes, d.offChain) - if err != nil { - panic(err) - } if _, exists := nopMap[nopName]; !exists { + ns, err := deployment.NodeInfo(nop.Nodes, d.offChain) + if err != nil { + panic(err) + } nopMap[nopName] = capabilities_registry_v2.CapabilitiesRegistryNodeOperatorParams{ Admin: adminAddrs[i], Name: nopName, diff --git a/system-tests/lib/cre/don.go b/system-tests/lib/cre/don.go index 2e9b583df18..0449a9c6d2a 100644 --- a/system-tests/lib/cre/don.go +++ b/system-tests/lib/cre/don.go @@ -3,6 +3,7 @@ package cre import ( "context" "fmt" + "net/http" "net/url" "slices" "strconv" @@ -426,10 +427,6 @@ func NewNode(ctx context.Context, name string, nodeMetadata *NodeMetadata, ctfNo } } - if account := nodeMetadata.AptosAccount(); account != "" { - node.Addresses.AptosAddresses = []string{account} - } - return node, nil } @@ -439,9 +436,8 @@ type JobDistributorDetails struct { } type Addresses struct { - AdminAddress string `toml:"admin_address" json:"admin_address"` // address used to pay for transactions, applicable only for worker nodes - MultiAddress string `toml:"multi_address" json:"multi_address"` // multi address used by OCR2, applicable only for bootstrap nodes - AptosAddresses []string `toml:"aptos_addresses" json:"aptos_addresses"` // Aptos public addresses cached from node metadata or the node key API + AdminAddress string `toml:"admin_address" json:"admin_address"` // address used to pay for transactions, applicable only for worker nodes + MultiAddress string `toml:"multi_address" json:"multi_address"` // multi address used by OCR2, applicable only for bootstrap nodes } type NodeClients struct { @@ -496,11 +492,11 @@ func createJDChainConfigs(ctx context.Context, n *Node, supportedChains []blockc account = accounts[0] } case chainselectors.FamilyAptos: - accounts, err := AptosAccountsForNode(ctx, n) - if err != nil { - return fmt.Errorf("failed to fetch aptos account address for node %s: %w", n.Name, err) + aptosAccount, aptosErr := aptosAccountForNode(ctx, n) + if aptosErr != nil { + return fmt.Errorf("failed to fetch aptos account address for node %s: %w", n.Name, aptosErr) } - account = accounts[0] + account = aptosAccount // Deployment parsing prefers AccountAddressPublicKey for Aptos chain configs. // Mirror transmitter into this field so OCRConfigForChainSelector always resolves it. accountAddrPubKey = account @@ -586,15 +582,47 @@ func createJDChainConfigs(ctx context.Context, n *Node, supportedChains []blockc return nil } -func AptosAccountsForNode(_ context.Context, n *Node) ([]string, error) { - if len(n.Addresses.AptosAddresses) > 0 { - return append([]string(nil), n.Addresses.AptosAddresses...), nil - } +func aptosAccountForNode(ctx context.Context, n *Node) (string, error) { if n.Keys != nil && n.Keys.AptosAccount() != "" { - n.Addresses.AptosAddresses = []string{n.Keys.AptosAccount()} - return append([]string(nil), n.Addresses.AptosAddresses...), nil + return n.Keys.AptosAccount(), nil + } + + var runtimeKeys struct { + Data []struct { + Attributes struct { + Account string `json:"account"` + PublicKey string `json:"publicKey"` + } `json:"attributes"` + } `json:"data"` + } + resp, err := n.Clients.RestClient.APIClient.R(). + SetContext(ctx). + SetResult(&runtimeKeys). + Get("/v2/keys/aptos") + if err != nil { + return "", fmt.Errorf("failed to read Aptos keys from node API: %w", err) + } + if resp.StatusCode() != http.StatusOK { + return "", fmt.Errorf("aptos keys endpoint returned status %d", resp.StatusCode()) } - return nil, fmt.Errorf("missing cached aptos addresses for node %s", n.Name) + if len(runtimeKeys.Data) == 0 { + return "", fmt.Errorf("no Aptos keys found on node %s", n.Name) + } + + account, err := crypto.NormalizeAptosAccount(runtimeKeys.Data[0].Attributes.Account) + if err != nil { + return "", fmt.Errorf("invalid Aptos account returned by node API: %w", err) + } + + if n.Keys != nil { + if n.Keys.Aptos == nil { + n.Keys.Aptos = &crypto.AptosKey{} + } + n.Keys.Aptos.Account = account + n.Keys.Aptos.PublicKey = runtimeKeys.Data[0].Attributes.PublicKey + } + + return account, nil } // AcceptJob accepts the job proposal for the given job proposal spec diff --git a/system-tests/lib/cre/don/config/config.go b/system-tests/lib/cre/don/config/config.go index ab19fc46f2d..4c992ce2dee 100644 --- a/system-tests/lib/cre/don/config/config.go +++ b/system-tests/lib/cre/don/config/config.go @@ -543,7 +543,7 @@ func addWorkerNodeConfig( } gateways := []coretoml.ConnectorGateway{} - if topology != nil && len(topology.GatewayConnectors.Configurations) > 0 { + if topology != nil && topology.GatewayConnectors != nil && len(topology.GatewayConnectors.Configurations) > 0 { for _, gateway := range topology.GatewayConnectors.Configurations { gateways = append(gateways, coretoml.ConnectorGateway{ ID: ptr.Ptr(gateway.AuthGatewayID), diff --git a/system-tests/lib/cre/don_test.go b/system-tests/lib/cre/don_test.go index 69fa7e09af8..77b86c29c31 100644 --- a/system-tests/lib/cre/don_test.go +++ b/system-tests/lib/cre/don_test.go @@ -2,58 +2,74 @@ package cre import ( "context" + "net/http" + "net/http/httptest" + "sync/atomic" "testing" + "github.com/go-resty/resty/v2" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-testing-framework/framework/clclient" "github.com/smartcontractkit/chainlink/system-tests/lib/cre/don/secrets" - "github.com/smartcontractkit/chainlink/system-tests/lib/crypto" + crecrypto "github.com/smartcontractkit/chainlink/system-tests/lib/crypto" ) -func TestAptosAccountsForNode_ReturnsCachedAddresses(t *testing.T) { +func TestAptosAccountForNode_UsesMetadataKeyWithoutCallingNodeAPI(t *testing.T) { t.Parallel() - node := &Node{ - Name: "node-1", - Addresses: Addresses{ - AptosAddresses: []string{"0x1", "0x2"}, - }, - } + var hits atomic.Int32 + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + hits.Add(1) + http.NotFound(w, r) + })) + t.Cleanup(server.Close) - addresses, err := AptosAccountsForNode(context.Background(), node) + expected, err := crecrypto.NormalizeAptosAccount("0x1") require.NoError(t, err) - require.Equal(t, []string{"0x1", "0x2"}, addresses) - - addresses[0] = "0xdead" - require.Equal(t, []string{"0x1", "0x2"}, node.Addresses.AptosAddresses) -} - -func TestAptosAccountsForNode_RequiresCachedMetadataWhenCacheMissing(t *testing.T) { - t.Parallel() node := &Node{ Name: "node-1", + Keys: &secrets.NodeKeys{ + Aptos: &crecrypto.AptosKey{Account: expected}, + }, + Clients: NodeClients{ + RestClient: &clclient.ChainlinkClient{APIClient: resty.New().SetBaseURL(server.URL)}, + }, } - _, err := AptosAccountsForNode(context.Background(), node) - require.Error(t, err) - require.ErrorContains(t, err, "missing cached aptos addresses for node node-1") + account, err := aptosAccountForNode(context.Background(), node) + require.NoError(t, err) + require.Equal(t, expected, account) + require.Zero(t, hits.Load(), "node API must not be called when metadata already has the Aptos key") } -func TestAptosAccountsForNode_ReturnsMetadataKeyWhenCacheMissing(t *testing.T) { +func TestAptosAccountForNode_FallsBackToNodeAPIAndCachesKey(t *testing.T) { t.Parallel() + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, "/v2/keys/aptos", r.URL.Path) + w.Header().Set("Content-Type", "application/json") + _, err := w.Write([]byte(`{"data":[{"attributes":{"account":"0x1","publicKey":"0xabc123"}}]}`)) + require.NoError(t, err) + })) + t.Cleanup(server.Close) + node := &Node{ Name: "node-1", - Keys: &secrets.NodeKeys{ - Aptos: &crypto.AptosKey{ - Account: "0x1", - }, + Keys: &secrets.NodeKeys{}, + Clients: NodeClients{ + RestClient: &clclient.ChainlinkClient{APIClient: resty.New().SetBaseURL(server.URL)}, }, } - addresses, err := AptosAccountsForNode(context.Background(), node) + account, err := aptosAccountForNode(context.Background(), node) + require.NoError(t, err) + + expected, err := crecrypto.NormalizeAptosAccount("0x1") require.NoError(t, err) - require.Equal(t, []string{"0x1"}, addresses) - require.Equal(t, []string{"0x1"}, node.Addresses.AptosAddresses) + require.Equal(t, expected, account) + require.NotNil(t, node.Keys.Aptos) + require.Equal(t, expected, node.Keys.Aptos.Account) + require.Equal(t, "0xabc123", node.Keys.Aptos.PublicKey) } diff --git a/system-tests/lib/cre/environment/blockchains/aptos/aptos.go b/system-tests/lib/cre/environment/blockchains/aptos/aptos.go index c221d509b79..aa8acbb645e 100644 --- a/system-tests/lib/cre/environment/blockchains/aptos/aptos.go +++ b/system-tests/lib/cre/environment/blockchains/aptos/aptos.go @@ -58,7 +58,7 @@ func (a *Blockchain) NodeURL() (string, error) { if a.ctfOutput == nil || len(a.ctfOutput.Nodes) == 0 { return "", fmt.Errorf("no nodes found for Aptos chain %s-%d", a.ChainFamily(), a.chainID) } - return aptosNodeURLWithV1(a.ctfOutput.Nodes[0].ExternalHTTPUrl) + return NormalizeNodeURL(a.ctfOutput.Nodes[0].ExternalHTTPUrl) } func (a *Blockchain) NodeClient() (*aptoslib.NodeClient, error) { @@ -268,6 +268,10 @@ func aptosNodeURLWithV1(rawURL string) (string, error) { return u.String(), nil } +func NormalizeNodeURL(rawURL string) (string, error) { + return aptosNodeURLWithV1(rawURL) +} + func aptosFaucetURLFromNodeURL(nodeURL string) (string, error) { u, err := url.Parse(nodeURL) if err != nil { @@ -285,15 +289,19 @@ func aptosFaucetURLFromNodeURL(nodeURL string) (string, error) { return u.String(), nil } +func FaucetURLFromNodeURL(nodeURL string) (string, error) { + return aptosFaucetURLFromNodeURL(nodeURL) +} + func (a *Blockchain) faucetURL() (string, error) { if a.ctfOutput == nil || len(a.ctfOutput.Nodes) == 0 { return "", errors.New("missing chain nodes output") } - nodeURL, err := aptosNodeURLWithV1(a.ctfOutput.Nodes[0].ExternalHTTPUrl) + nodeURL, err := NormalizeNodeURL(a.ctfOutput.Nodes[0].ExternalHTTPUrl) if err != nil { return "", err } - return aptosFaucetURLFromNodeURL(nodeURL) + return FaucetURLFromNodeURL(nodeURL) } func waitForAptosAccountVisible(ctx context.Context, client *aptoslib.NodeClient, account aptoslib.AccountAddress, timeout time.Duration) error { @@ -325,3 +333,18 @@ func aptosChainIDUint8(chainID uint64) (uint8, error) { return uint8(chainID), nil } + +func ChainIDUint8(chainID uint64) (uint8, error) { + return aptosChainIDUint8(chainID) +} + +func WaitForTransactionSuccess(client *aptoslib.NodeClient, txHash, label string) error { + tx, err := client.WaitForTransaction(txHash) + if err != nil { + return fmt.Errorf("failed waiting for Aptos tx %s: %w", label, err) + } + if !tx.Success { + return fmt.Errorf("aptos tx failed: %s vm_status=%s", label, tx.VmStatus) + } + return nil +} diff --git a/system-tests/lib/cre/environment/blockchains/aptos/aptos_test.go b/system-tests/lib/cre/environment/blockchains/aptos/aptos_test.go new file mode 100644 index 00000000000..246e1904f6c --- /dev/null +++ b/system-tests/lib/cre/environment/blockchains/aptos/aptos_test.go @@ -0,0 +1,36 @@ +package aptos + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestNormalizeNodeURL(t *testing.T) { + t.Run("adds v1 when path is empty", func(t *testing.T) { + got, err := NormalizeNodeURL("http://127.0.0.1:8080") + require.NoError(t, err) + require.Equal(t, "http://127.0.0.1:8080/v1", got) + }) + + t.Run("preserves v1 path", func(t *testing.T) { + got, err := NormalizeNodeURL("http://127.0.0.1:8080/v1") + require.NoError(t, err) + require.Equal(t, "http://127.0.0.1:8080/v1", got) + }) +} + +func TestFaucetURLFromNodeURL(t *testing.T) { + got, err := FaucetURLFromNodeURL("http://127.0.0.1:8080/v1") + require.NoError(t, err) + require.Equal(t, "http://127.0.0.1:8081", got) +} + +func TestChainIDUint8(t *testing.T) { + got, err := ChainIDUint8(4) + require.NoError(t, err) + require.Equal(t, uint8(4), got) + + _, err = ChainIDUint8(256) + require.Error(t, err) +} diff --git a/system-tests/lib/cre/environment/config/config.go b/system-tests/lib/cre/environment/config/config.go index 1339c7891e2..b31df9e1b6b 100644 --- a/system-tests/lib/cre/environment/config/config.go +++ b/system-tests/lib/cre/environment/config/config.go @@ -61,8 +61,8 @@ type Config struct { NodeSets []*cre.NodeSet `toml:"nodesets" validate:"required"` JD *jd.Input `toml:"jd" validate:"required"` Infra *infra.Provider `toml:"infra" validate:"required"` - Fake *fake.Input `toml:"fake" validate:"required"` - FakeHTTP *fake.Input `toml:"fake_http" validate:"required"` + Fake *fake.Input `toml:"fake"` + FakeHTTP *fake.Input `toml:"fake_http"` S3ProviderInput *s3provider.Input `toml:"s3provider"` CapabilityConfigs map[string]cre.CapabilityConfig `toml:"capability_configs"` // capability flag -> capability config Addresses []string `toml:"addresses"` diff --git a/system-tests/lib/cre/environment/dons.go b/system-tests/lib/cre/environment/dons.go index bb61dbd71b4..e1bdbb6856c 100644 --- a/system-tests/lib/cre/environment/dons.go +++ b/system-tests/lib/cre/environment/dons.go @@ -257,10 +257,7 @@ func nodeAddress(ctx context.Context, node *cre.Node, chainFamily string, bc blo if node.Keys != nil && node.Keys.AptosAccount() != "" { return node.Keys.AptosAccount(), nil } - if len(node.Addresses.AptosAddresses) > 0 { - return node.Addresses.AptosAddresses[0], nil - } - return "", nil // Skip nodes without cached Aptos keys + return "", nil // Skip nodes without Aptos keys for this chain default: return "", fmt.Errorf("unsupported chain family %s", chainFamily) } diff --git a/system-tests/lib/cre/features/aptos/aptos.go b/system-tests/lib/cre/features/aptos/aptos.go index 6db9bd7f576..6f8322b69f7 100644 --- a/system-tests/lib/cre/features/aptos/aptos.go +++ b/system-tests/lib/cre/features/aptos/aptos.go @@ -6,7 +6,6 @@ import ( "encoding/hex" stderrors "errors" "fmt" - "net/url" "strconv" "strings" "text/template" @@ -29,8 +28,6 @@ import ( "github.com/smartcontractkit/chainlink-deployments-framework/datastore" kcr "github.com/smartcontractkit/chainlink-evm/gethwrappers/keystone/generated/capabilities_registry_1_1_0" "github.com/smartcontractkit/chainlink-protos/cre/go/values" - "github.com/smartcontractkit/chainlink-testing-framework/framework" - "github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain" "github.com/smartcontractkit/chainlink/deployment/cre/jobs" crejobops "github.com/smartcontractkit/chainlink/deployment/cre/jobs/operations" jobtypes "github.com/smartcontractkit/chainlink/deployment/cre/jobs/types" @@ -85,32 +82,6 @@ func CapabilityLabel(chainSelector uint64) string { return capabilityLabelPrefix + strconv.FormatUint(chainSelector, 10) } -// ForwarderAddress returns the Aptos forwarder address cached in the CRE -// datastore for the given chain selector. -func ForwarderAddress(ds datastore.DataStore, chainSelector uint64) (string, bool) { - key := datastore.NewAddressRefKey( - chainSelector, - datastore.ContractType(forwarderContractType), - forwarderContractVersion, - forwarderQualifier, - ) - ref, err := ds.Addresses().Get(key) - if err != nil { - return "", false - } - return ref.Address, true -} - -// MustForwarderAddress returns the cached Aptos forwarder address for the given -// chain selector and panics if it has not been recorded yet. -func MustForwarderAddress(ds datastore.DataStore, chainSelector uint64) string { - addr, ok := ForwarderAddress(ds, chainSelector) - if !ok { - panic(fmt.Sprintf("missing Aptos forwarder address for chain selector %d", chainSelector)) - } - return addr -} - func (a *Aptos) PreEnvStartup( ctx context.Context, testLogger zerolog.Logger, @@ -164,7 +135,7 @@ func (a *Aptos) PreEnvStartup( if err != nil { return nil, fmt.Errorf("could not resolve capability config for '%s' on chain %d: %w", flag, chainID, err) } - capConfig, err := BuildCapabilityConfig(capabilityConfig.Values, p2pToTransmitterMap, false) + capConfig, err := BuildCapabilityConfig(capabilityConfig.Values, p2pToTransmitterMap, don.HasOnlyLocalCapabilities()) if err != nil { return nil, fmt.Errorf("failed to build Aptos capability config for capability %s: %w", labelledName, err) } @@ -250,7 +221,7 @@ func (a *Aptos) PostEnvStartup( return pkgerrors.Wrap(tmplErr, "failed to parse Aptos config template") } - forwarderAddress := MustForwarderAddress(creEnv.CldfEnvironment.DataStore, aptosChain.ChainSelector()) + forwarderAddress := mustForwarderAddress(creEnv.CldfEnvironment.DataStore, aptosChain.ChainSelector()) templateData := map[string]string{ "ChainID": strconv.FormatUint(chainID, 10), "CREForwarderAddress": forwarderAddress, @@ -316,6 +287,28 @@ func (a *Aptos) PostEnvStartup( return nil } +func forwarderAddress(ds datastore.DataStore, chainSelector uint64) (string, bool) { + key := datastore.NewAddressRefKey( + chainSelector, + datastore.ContractType(forwarderContractType), + forwarderContractVersion, + forwarderQualifier, + ) + ref, err := ds.Addresses().Get(key) + if err != nil { + return "", false + } + return ref.Address, true +} + +func mustForwarderAddress(ds datastore.DataStore, chainSelector uint64) string { + addr, ok := forwarderAddress(ds, chainSelector) + if !ok { + panic(fmt.Sprintf("missing Aptos forwarder address for chain selector %d", chainSelector)) + } + return addr +} + // BuildCapabilityConfig builds the Aptos capability config passed directly // through the capability manager: method execution policy in MethodConfigs and // Aptos-specific runtime inputs in SpecConfig. @@ -508,7 +501,7 @@ func ensureForwarder( creEnv *cre.Environment, chain *aptoschain.Blockchain, ) (string, error) { - if addr, ok := ForwarderAddress(creEnv.CldfEnvironment.DataStore, chain.ChainSelector()); ok { + if addr, ok := forwarderAddress(creEnv.CldfEnvironment.DataStore, chain.ChainSelector()); ok { return addr, nil } if !creEnv.Provider.IsDocker() { @@ -533,16 +526,14 @@ func ensureForwarder( } owner := deployerAccount.AccountAddress() - containerName := "" - if output := chain.CtfOutput(); output != nil { - containerName = output.ContainerName - } - if ensureErr := ensureAccountVisible(ctx, testLogger, client, nodeURL, owner, chain.ChainSelector(), containerName); ensureErr != nil { - testLogger.Warn(). - Uint64("chainSelector", chain.ChainSelector()). - Str("nodeURL", nodeURL). - Err(ensureErr). - Msg("Aptos deployer account not confirmed visible yet; proceeding with deploy retries") + if _, accountErr := client.Account(owner); accountErr != nil { + if fundErr := chain.Fund(ctx, owner.StringLong(), 100_000_000); fundErr != nil { + testLogger.Warn(). + Uint64("chainSelector", chain.ChainSelector()). + Str("nodeURL", nodeURL). + Err(fundErr). + Msg("Aptos deployer account not confirmed visible yet; proceeding with deploy retries") + } } var deployedAddress string @@ -667,20 +658,17 @@ func configureForwarders( } deployerAddress := deployerAccount.AccountAddress() - containerName := "" - if output := aptosChain.CtfOutput(); output != nil { - containerName = output.ContainerName - } - - if err := ensureAccountVisible(ctx, testLogger, client, nodeURL, deployerAddress, aptosChain.ChainSelector(), containerName); err != nil { - testLogger.Warn(). - Uint64("chainSelector", aptosChain.ChainSelector()). - Str("nodeURL", nodeURL). - Err(err). - Msg("Aptos deployer account not confirmed visible yet; proceeding with forwarder set_config retries") + if _, accountErr := client.Account(deployerAddress); accountErr != nil { + if fundErr := aptosChain.Fund(ctx, deployerAddress.StringLong(), 100_000_000); fundErr != nil { + testLogger.Warn(). + Uint64("chainSelector", aptosChain.ChainSelector()). + Str("nodeURL", nodeURL). + Err(fundErr). + Msg("Aptos deployer account not confirmed visible yet; proceeding with forwarder set_config retries") + } } - forwarderHex := MustForwarderAddress(creEnv.CldfEnvironment.DataStore, aptosChain.ChainSelector()) + forwarderHex := mustForwarderAddress(creEnv.CldfEnvironment.DataStore, aptosChain.ChainSelector()) var forwarderAddr aptossdk.AccountAddress if err := forwarderAddr.ParseStringRelaxed(forwarderHex); err != nil { return fmt.Errorf("invalid Aptos forwarder address for chain selector %d: %w", aptosChain.ChainSelector(), err) @@ -785,7 +773,7 @@ func p2pToTransmitterMapForWorkers(workers []*cre.NodeMetadata) (map[string]stri return nil, fmt.Errorf("missing P2P key for worker index %d", worker.Index) } - account := worker.AptosAccount() + account := worker.Keys.AptosAccount() if account == "" { return nil, fmt.Errorf("missing Aptos account for worker index %d", worker.Index) } @@ -888,57 +876,6 @@ func findAptosChainByChainID(chains []creblockchains.Blockchain, chainID uint64) return nil, fmt.Errorf("Aptos blockchain for chain id %d not found", chainID) } -func normalizeNodeURL(rawURL string) (string, error) { - u, err := url.Parse(rawURL) - if err != nil { - return "", err - } - if u.Scheme == "" || u.Host == "" { - return "", fmt.Errorf("aptos node URL %q must include scheme and host", rawURL) - } - path := strings.TrimRight(u.Path, "/") - if path == "" || path != "/v1" { - u.Path = "/v1" - } - return u.String(), nil -} - -func NormalizeNodeURL(rawURL string) (string, error) { - return normalizeNodeURL(rawURL) -} - -func faucetURLFromNodeURL(nodeURL string) (string, error) { - parsed, err := url.Parse(nodeURL) - if err != nil { - return "", err - } - host := parsed.Hostname() - if host == "" { - return "", fmt.Errorf("aptos node URL %q has empty host", nodeURL) - } - parsed.Host = fmt.Sprintf("%s:%s", host, blockchain.DefaultAptosFaucetPort) - parsed.Path = "" - parsed.RawPath = "" - parsed.RawQuery = "" - parsed.Fragment = "" - return parsed.String(), nil -} - -func FaucetURLFromNodeURL(nodeURL string) (string, error) { - return faucetURLFromNodeURL(nodeURL) -} - -func aptosChainIDUint8(chainID uint64) (uint8, error) { - if chainID > 255 { - return 0, fmt.Errorf("aptos chain id %d does not fit in uint8", chainID) - } - return uint8(chainID), nil -} - -func ChainIDUint8(chainID uint64) (uint8, error) { - return aptosChainIDUint8(chainID) -} - func aptosDonIDUint32(donID uint64) (uint32, error) { if donID > uint64(^uint32(0)) { return 0, fmt.Errorf("don id %d exceeds u32", donID) @@ -946,127 +883,6 @@ func aptosDonIDUint32(donID uint64) (uint32, error) { return uint32(donID), nil } -// ensureAccountVisible best-effort funds an Aptos account and waits for the node -// API to acknowledge it. This smooths over localnet timing where deployer -// accounts can exist before the node API can query them reliably. -func ensureAccountVisible( - ctx context.Context, - testLogger zerolog.Logger, - client *aptossdk.NodeClient, - nodeURL string, - address aptossdk.AccountAddress, - chainSelector uint64, - containerName string, -) error { - if err := FundAccountBestEffort(ctx, testLogger, client, nodeURL, containerName, address, 0, 100_000_000); err == nil { - return nil - } - - testLogger.Warn(). - Uint64("chainSelector", chainSelector). - Str("nodeURL", nodeURL). - Str("account", address.StringLong()). - Msg("Aptos account not confirmed visible after funding attempts") - return fmt.Errorf("aptos account %s not visible yet on %s", address.StringLong(), nodeURL) -} - -func waitForAccountVisible(ctx context.Context, client *aptossdk.NodeClient, address aptossdk.AccountAddress) error { - var lastErr error - err := retry.Do(ctx, retry.WithMaxDuration(20*time.Second, retry.NewFibonacci(250*time.Millisecond)), func(context.Context) error { - if _, err := client.Account(address); err != nil { - lastErr = err - return retry.RetryableError(err) - } - return nil - }) - if err != nil { - if lastErr != nil { - return lastErr - } - return err - } - return nil -} - -func WaitForAccountVisible(ctx context.Context, client *aptossdk.NodeClient, address aptossdk.AccountAddress, timeout time.Duration) error { - waitCtx, cancel := context.WithTimeout(ctx, timeout) - defer cancel() - return waitForAccountVisible(waitCtx, client, address) -} - -func fundAccountInContainer(ctx context.Context, containerName, address string, amount uint64) error { - dc, err := framework.NewDockerClient() - if err != nil { - return fmt.Errorf("failed to create docker client: %w", err) - } - cmd := []string{ - "aptos", "account", "fund-with-faucet", - "--account", address, - "--amount", strconv.FormatUint(amount, 10), - } - if _, err = dc.ExecContainerWithContext(ctx, containerName, cmd); err != nil { - return fmt.Errorf("failed to execute aptos faucet funding command in container %s: %w", containerName, err) - } - return nil -} - -func FundAccountInContainer(ctx context.Context, containerName, address string, amount uint64) error { - return fundAccountInContainer(ctx, containerName, address, amount) -} - -func FundAccountBestEffort( - ctx context.Context, - testLogger zerolog.Logger, - client *aptossdk.NodeClient, - nodeURL string, - containerName string, - address aptossdk.AccountAddress, - minBalance uint64, - fundingAmount uint64, -) error { - if _, err := client.Account(address); err == nil { - if minBalance == 0 { - return nil - } - if balance, balErr := client.AccountAPTBalance(address); balErr == nil && balance >= minBalance { - return nil - } - } - - if faucetURL, err := faucetURLFromNodeURL(nodeURL); err == nil { - if faucetClient, err := aptossdk.NewFaucetClient(client, faucetURL); err == nil { - if fundErr := faucetClient.Fund(address, fundingAmount); fundErr != nil { - testLogger.Warn(). - Err(fundErr). - Str("faucet_url", faucetURL). - Str("account", address.StringLong()). - Msg("Aptos host faucet funding failed") - } else if waitErr := WaitForAccountVisible(ctx, client, address, 8*time.Second); waitErr == nil { - return nil - } - } - } - - if strings.TrimSpace(containerName) == "" { - return fmt.Errorf("aptos account %s not visible after host funding attempts", address.StringLong()) - } - if err := fundAccountInContainer(ctx, containerName, address.StringLong(), fundingAmount); err != nil { - return err - } - return WaitForAccountVisible(ctx, client, address, 8*time.Second) -} - -func WaitForTransactionSuccess(client *aptossdk.NodeClient, txHash, label string) error { - tx, err := client.WaitForTransaction(txHash) - if err != nil { - return fmt.Errorf("failed waiting for Aptos tx %s: %w", label, err) - } - if !tx.Success { - return fmt.Errorf("aptos tx failed: %s vm_status=%s", label, tx.VmStatus) - } - return nil -} - func parseOCR2OnchainPublicKey(hexValue string) ([]byte, error) { trimmed := strings.TrimPrefix(strings.TrimSpace(hexValue), "ocr2on_aptos_") decoded, err := hex.DecodeString(trimmed) diff --git a/system-tests/lib/cre/features/aptos/aptos_test.go b/system-tests/lib/cre/features/aptos/aptos_test.go index 0714090a74b..95bbf282ba0 100644 --- a/system-tests/lib/cre/features/aptos/aptos_test.go +++ b/system-tests/lib/cre/features/aptos/aptos_test.go @@ -179,35 +179,6 @@ func TestP2PToTransmitterMapForWorkers(t *testing.T) { }, got) } -func TestNormalizeNodeURL(t *testing.T) { - t.Run("adds v1 when path is empty", func(t *testing.T) { - got, err := NormalizeNodeURL("http://127.0.0.1:8080") - require.NoError(t, err) - require.Equal(t, "http://127.0.0.1:8080/v1", got) - }) - - t.Run("preserves v1 path", func(t *testing.T) { - got, err := NormalizeNodeURL("http://127.0.0.1:8080/v1") - require.NoError(t, err) - require.Equal(t, "http://127.0.0.1:8080/v1", got) - }) -} - -func TestFaucetURLFromNodeURL(t *testing.T) { - got, err := FaucetURLFromNodeURL("http://127.0.0.1:8080/v1") - require.NoError(t, err) - require.Equal(t, "http://127.0.0.1:8081", got) -} - -func TestChainIDUint8(t *testing.T) { - got, err := ChainIDUint8(4) - require.NoError(t, err) - require.Equal(t, uint8(4), got) - - _, err = ChainIDUint8(256) - require.Error(t, err) -} - func TestResolveMethodConfigSettings_Defaults(t *testing.T) { settings, err := resolveMethodConfigSettings(nil) require.NoError(t, err) diff --git a/system-tests/lib/cre/features/read_contract/read_contract.go b/system-tests/lib/cre/features/read_contract/read_contract.go index 7edfa515710..03334817659 100644 --- a/system-tests/lib/cre/features/read_contract/read_contract.go +++ b/system-tests/lib/cre/features/read_contract/read_contract.go @@ -123,10 +123,6 @@ type blockchainOutput interface { ChainFamily() string } -type familyMatcher interface { - IsFamily(chainFamily string) bool -} - const configTemplate = `{"chainId":{{printf "%d" .ChainID}},"network":"{{.NetworkFamily}}"}` func (o *ReadContract) PostEnvStartup( @@ -159,7 +155,10 @@ func (o *ReadContract) PostEnvStartup( if findErr != nil { return findErr } - if shouldSkipPostEnvStartup(don, blockchainOutput) { + // Aptos write owns the Aptos ReadContract worker jobs because it needs the + // Aptos-specific OCR/bootstrap inputs that the generic read-contract path + // does not supply. Skip the duplicate generic proposal on those DONs. + if blockchainOutput.IsFamily(blockchain.FamilyAptos) && don.HasFlag(cre.WriteAptosCapability) { continue } @@ -248,7 +247,3 @@ func findBlockchainByChainID(creEnv *cre.Environment, chainID uint64) (creblockc return nil, fmt.Errorf("could not find blockchain for read-contract chainID %d", chainID) } - -func shouldSkipPostEnvStartup(don *cre.Don, bc familyMatcher) bool { - return bc.IsFamily(blockchain.FamilyAptos) && don.HasFlag(cre.WriteAptosCapability) -} diff --git a/system-tests/lib/cre/features/read_contract/read_contract_test.go b/system-tests/lib/cre/features/read_contract/read_contract_test.go index 2f41c13c530..ece08b19057 100644 --- a/system-tests/lib/cre/features/read_contract/read_contract_test.go +++ b/system-tests/lib/cre/features/read_contract/read_contract_test.go @@ -8,29 +8,38 @@ import ( chainselectors "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink/system-tests/lib/cre" + aptosfeature "github.com/smartcontractkit/chainlink/system-tests/lib/cre/features/aptos" ) -type familyMatcherStub struct { - family string +type blockchainOutputStub struct { + chainSelector uint64 + chainFamily string } -func (s familyMatcherStub) IsFamily(chainFamily string) bool { - return s.family == chainFamily +func (s blockchainOutputStub) ChainSelector() uint64 { + return s.chainSelector } -func TestShouldSkipPostEnvStartup(t *testing.T) { - t.Run("skips aptos when write aptos feature owns the don", func(t *testing.T) { - don := &cre.Don{Flags: []cre.CapabilityFlag{cre.ReadContractCapability, cre.WriteAptosCapability}} - require.True(t, shouldSkipPostEnvStartup(don, familyMatcherStub{family: chainselectors.FamilyAptos})) - }) +func (s blockchainOutputStub) ChainFamily() string { + return s.chainFamily +} - t.Run("does not skip aptos for read-only dons", func(t *testing.T) { - don := &cre.Don{Flags: []cre.CapabilityFlag{cre.ReadContractCapability}} - require.False(t, shouldSkipPostEnvStartup(don, familyMatcherStub{family: chainselectors.FamilyAptos})) +func TestAptosCapabilityLabel(t *testing.T) { + bc := blockchainOutputStub{chainSelector: 1, chainFamily: chainselectors.FamilyAptos} + + t.Run("skips aptos when write aptos feature owns the don", func(t *testing.T) { + don := &cre.DonMetadata{Flags: []string{cre.ReadContractCapability, cre.WriteAptosCapability}} + label, skip, err := aptosCapabilityLabel(don, bc) + require.NoError(t, err) + require.Empty(t, label) + require.True(t, skip) }) - t.Run("does not skip non-aptos chains", func(t *testing.T) { - don := &cre.Don{Flags: []cre.CapabilityFlag{cre.ReadContractCapability, cre.WriteAptosCapability}} - require.False(t, shouldSkipPostEnvStartup(don, familyMatcherStub{family: chainselectors.FamilyEVM})) + t.Run("uses aptos label for read-only dons", func(t *testing.T) { + don := &cre.DonMetadata{Flags: []string{cre.ReadContractCapability}} + label, skip, err := aptosCapabilityLabel(don, bc) + require.NoError(t, err) + require.Equal(t, aptosfeature.CapabilityLabel(1), label) + require.False(t, skip) }) } diff --git a/system-tests/lib/cre/types.go b/system-tests/lib/cre/types.go index 39ffdc39b86..efc0ca18aa4 100644 --- a/system-tests/lib/cre/types.go +++ b/system-tests/lib/cre/types.go @@ -562,12 +562,16 @@ type DonMetadata struct { func NewDonMetadata(c *NodeSet, id uint64, provider infra.Provider, capabilityConfigs map[CapabilityFlag]CapabilityConfig) (*DonMetadata, error) { cfgs := make([]NodeMetadataConfig, len(c.NodeSpecs)) + aptosChainIDs, err := c.GetEnabledChainIDsForCapability(WriteAptosCapability) + if err != nil { + return nil, fmt.Errorf("failed to resolve Aptos chain ids for node metadata: %w", err) + } for i, nodeSpec := range c.NodeSpecs { cfg := NodeMetadataConfig{ Keys: NodeKeyInput{ EVMChainIDs: c.EVMChains(), SolanaChainIDs: c.SupportedSolChains, - AptosEnabled: HasFlag(c.Capabilities, WriteAptosCapability), + AptosChainIDs: aptosChainIDs, Password: "dev-password", ImportedSecrets: nodeSpec.Node.TestSecretsOverrides, }, @@ -1148,13 +1152,6 @@ func (n *NodeMetadata) PeerID() string { return strings.TrimPrefix(n.Keys.PeerID(), "p2p_") } -func (n *NodeMetadata) AptosAccount() string { - if n.Keys == nil { - return "" - } - return n.Keys.AptosAccount() -} - const ( DefaultShardOrchestratorPort uint16 = 50051 DefaultArbiterPort uint16 = 9876 @@ -1434,7 +1431,7 @@ func (c *NodeSet) MaxFaultyNodes() (uint32, error) { type NodeKeyInput struct { EVMChainIDs []uint64 SolanaChainIDs []string - AptosEnabled bool + AptosChainIDs []uint64 Password string ImportedSecrets string // raw JSON string of secrets to import (usually from a previous run) @@ -1451,7 +1448,7 @@ func NewNodeKeys(input NodeKeyInput) (*secrets.NodeKeys, error) { if err != nil { return nil, errors.Wrap(err, "failed to parse imported secrets") } - if input.AptosEnabled && importedKeys.Aptos == nil { + if len(input.AptosChainIDs) > 0 && importedKeys.Aptos == nil { return nil, errors.New("imported secrets are missing an Aptos key; regenerate node secrets with Aptos support") } @@ -1487,7 +1484,7 @@ func NewNodeKeys(input NodeKeyInput) (*secrets.NodeKeys, error) { } out.Solana[chainID] = k } - if input.AptosEnabled { + if len(input.AptosChainIDs) > 0 { k, err := crypto.NewAptosKey(input.Password) if err != nil { return nil, fmt.Errorf("failed to generate Aptos key: %w", err) diff --git a/system-tests/lib/cre/types_nodekeys_test.go b/system-tests/lib/cre/types_nodekeys_test.go index 5a7f6a4f4ac..662a288fb04 100644 --- a/system-tests/lib/cre/types_nodekeys_test.go +++ b/system-tests/lib/cre/types_nodekeys_test.go @@ -27,7 +27,7 @@ func TestNewNodeKeys_IgnoresEmptyImportedAptosSecretWhenAptosDisabled(t *testing keys, err := NewNodeKeys(NodeKeyInput{ ImportedSecrets: baseSecrets, - AptosEnabled: false, + AptosChainIDs: nil, }) require.NoError(t, err) require.Nil(t, keys.Aptos) @@ -52,7 +52,7 @@ func TestNewNodeKeys_RejectsMissingImportedAptosSecretWhenAptosEnabled(t *testin _, err = NewNodeKeys(NodeKeyInput{ ImportedSecrets: baseSecrets, - AptosEnabled: true, + AptosChainIDs: []uint64{4}, }) require.ErrorContains(t, err, "missing an Aptos key") } diff --git a/system-tests/tests/smoke/cre/v2_aptos_capability_test.go b/system-tests/tests/smoke/cre/v2_aptos_capability_test.go index f2c63fa4537..a5597382271 100644 --- a/system-tests/tests/smoke/cre/v2_aptos_capability_test.go +++ b/system-tests/tests/smoke/cre/v2_aptos_capability_test.go @@ -6,12 +6,14 @@ import ( "encoding/hex" "errors" "fmt" + "net/http" "os" "regexp" "strings" "testing" "time" + "github.com/Masterminds/semver/v3" aptoslib "github.com/aptos-labs/aptos-go-sdk" aptoscrypto "github.com/aptos-labs/aptos-go-sdk/crypto" "github.com/ethereum/go-ethereum/common" @@ -28,10 +30,11 @@ import ( workflowevents "github.com/smartcontractkit/chainlink-protos/workflows/go/events" crelib "github.com/smartcontractkit/chainlink/system-tests/lib/cre" + crecontracts "github.com/smartcontractkit/chainlink/system-tests/lib/cre/contracts" "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains" blockchains_aptos "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains/aptos" blockchains_evm "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains/evm" - aptosfeature "github.com/smartcontractkit/chainlink/system-tests/lib/cre/features/aptos" + crecrypto "github.com/smartcontractkit/chainlink/system-tests/lib/crypto" aptoswrite_config "github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptoswrite/config" aptoswriteroundtrip_config "github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/config" t_helpers "github.com/smartcontractkit/chainlink/system-tests/tests/test-helpers" @@ -42,6 +45,8 @@ const aptosLocalMaxGasAmount uint64 = 200_000 const aptosWorkerFundingAmountOctas uint64 = 1_000_000_000_000 const aptosWorkerMinBalanceOctas uint64 = 100_000_000 +var aptosForwarderVersion = semver.MustParse("1.0.0") + // ExecuteAptosTest runs the Aptos CRE suite with the minimum CI scenarios that // still cover the end-to-end happy path and the expected-failure path. func ExecuteAptosTest(t *testing.T, tenv *configuration.TestEnvironment) { @@ -83,7 +88,10 @@ func executeAptosScenarios(t *testing.T, tenv *configuration.TestEnvironment, sc userLogsCh := make(chan *workflowevents.UserLogs, 1000) baseMessageCh := make(chan *commonevents.BaseMessage, 1000) - server := t_helpers.StartChipTestSink(t, t_helpers.GetLoggingPublishFn(lggr, userLogsCh, baseMessageCh, "./logs/aptos_capability_workflow_test.log")) + writeDon := findWriteAptosDonForChain(t, tenv, aptosChain.ChainID()) + assertAptosWorkerRuntimeKeysMatchMetadata(t, writeDon) + + server := t_helpers.StartChipTestSink(t, t_helpers.GetPublishFn(lggr, userLogsCh, baseMessageCh)) t.Cleanup(func() { server.Shutdown(t.Context()) close(userLogsCh) @@ -97,6 +105,45 @@ func executeAptosScenarios(t *testing.T, tenv *configuration.TestEnvironment, sc } } +func assertAptosWorkerRuntimeKeysMatchMetadata(t *testing.T, writeDon *crelib.Don) { + t.Helper() + + workers, err := writeDon.Workers() + require.NoError(t, err, "failed to list Aptos write DON workers") + require.NotEmpty(t, workers, "Aptos write DON workers list is empty") + + for _, worker := range workers { + require.NotNil(t, worker.Keys, "worker %q is missing metadata keys", worker.Name) + require.NotNil(t, worker.Keys.Aptos, "worker %q is missing metadata Aptos key", worker.Name) + + expectedAccount, err := crecrypto.NormalizeAptosAccount(worker.Keys.Aptos.Account) + require.NoError(t, err, "worker %q has invalid metadata Aptos account", worker.Name) + expectedPublicKey := normalizeHexValue(worker.Keys.Aptos.PublicKey) + require.NotEmpty(t, expectedPublicKey, "worker %q is missing metadata Aptos public key", worker.Name) + + var runtimeKeys struct { + Data []struct { + Attributes struct { + Account string `json:"account"` + PublicKey string `json:"publicKey"` + } `json:"attributes"` + } `json:"data"` + } + resp, err := worker.Clients.RestClient.APIClient.R(). + SetResult(&runtimeKeys). + Get("/v2/keys/aptos") + require.NoError(t, err, "failed to read runtime Aptos keys for worker %q", worker.Name) + require.Equal(t, http.StatusOK, resp.StatusCode(), "worker %q Aptos keys endpoint returned unexpected status", worker.Name) + require.Len(t, runtimeKeys.Data, 1, "worker %q must expose exactly one Aptos runtime key", worker.Name) + + runtimeKey := runtimeKeys.Data[0].Attributes + actualAccount, err := crecrypto.NormalizeAptosAccount(runtimeKey.Account) + require.NoError(t, err, "worker %q exposed invalid runtime Aptos account", worker.Name) + require.Equal(t, expectedAccount, actualAccount, "worker %q runtime Aptos account does not match metadata-generated account", worker.Name) + require.Equal(t, expectedPublicKey, normalizeHexValue(runtimeKey.PublicKey), "worker %q runtime Aptos public key does not match metadata-generated key", worker.Name) + } +} + // ExecuteAptosReadTest deploys a workflow that reads 0x1::coin::name() on Aptos local devnet // in a consensus read step and asserts the expected value. func ExecuteAptosReadTest( @@ -261,8 +308,7 @@ func prepareAptosWriteScenarioWithBenchmark( ) aptosWriteScenario { t.Helper() - forwarderHex, ok := aptosfeature.ForwarderAddress(tenv.CreEnvironment.CldfEnvironment.DataStore, aptosChain.ChainSelector()) - require.True(t, ok, "Aptos write test requires forwarder address in datastore for chainSelector=%d", aptosChain.ChainSelector()) + forwarderHex := aptosForwarderAddress(tenv, aptosChain.ChainSelector()) require.NotEmpty(t, forwarderHex, "Aptos write test requires forwarder address for chainSelector=%d", aptosChain.ChainSelector()) require.False(t, isZeroAptosAddress(forwarderHex), "Aptos write test requires non-zero forwarder address for chainSelector=%d", aptosChain.ChainSelector()) @@ -317,6 +363,16 @@ func isZeroAptosAddress(addr string) bool { return true } +func aptosForwarderAddress(tenv *configuration.TestEnvironment, chainSelector uint64) string { + return crecontracts.MustGetAddressFromDataStore( + tenv.CreEnvironment.CldfEnvironment.DataStore, + chainSelector, + "AptosForwarder", + aptosForwarderVersion, + "", + ) +} + var aptosTxHashInLogRe = regexp.MustCompile(`txHash=([^\s"]+)`) func waitForAptosWriteSuccessLogAndTxHash( @@ -406,12 +462,12 @@ func assertAptosWriteFailureTxOnChain(t *testing.T, aptosChain blockchains.Block nodeURL := bc.CtfOutput().Nodes[0].ExternalHTTPUrl require.NotEmpty(t, nodeURL, "Aptos node URL is required for onchain verification") - nodeURL, err := aptosfeature.NormalizeNodeURL(nodeURL) + nodeURL, err := blockchains_aptos.NormalizeNodeURL(nodeURL) require.NoError(t, err, "failed to normalize Aptos node URL for onchain verification") chainID := bc.ChainID() require.LessOrEqual(t, chainID, uint64(255), "Aptos chain id must fit in uint8") - chainIDUint8, err := aptosfeature.ChainIDUint8(chainID) + chainIDUint8, err := blockchains_aptos.ChainIDUint8(chainID) require.NoError(t, err, "failed to convert Aptos chain id") client, err := aptoslib.NewNodeClient(nodeURL, chainIDUint8) @@ -430,12 +486,12 @@ func assertAptosWriteTxOnChain(t *testing.T, aptosChain blockchains.Blockchain, nodeURL := bc.CtfOutput().Nodes[0].ExternalHTTPUrl require.NotEmpty(t, nodeURL, "Aptos node URL is required for onchain verification") - nodeURL, err := aptosfeature.NormalizeNodeURL(nodeURL) + nodeURL, err := blockchains_aptos.NormalizeNodeURL(nodeURL) require.NoError(t, err, "failed to normalize Aptos node URL for onchain verification") chainID := bc.ChainID() require.LessOrEqual(t, chainID, uint64(255), "Aptos chain id must fit in uint8") - chainIDUint8, err := aptosfeature.ChainIDUint8(chainID) + chainIDUint8, err := blockchains_aptos.ChainIDUint8(chainID) require.NoError(t, err, "failed to convert Aptos chain id") client, err := aptoslib.NewNodeClient(nodeURL, chainIDUint8) @@ -478,12 +534,12 @@ func assertAptosReceiverUpdatedOnChain( require.True(t, ok, "expected aptos blockchain type") nodeURL := aptosBC.CtfOutput().Nodes[0].ExternalHTTPUrl require.NotEmpty(t, nodeURL, "Aptos node URL is required for onchain verification") - nodeURL, err := aptosfeature.NormalizeNodeURL(nodeURL) + nodeURL, err := blockchains_aptos.NormalizeNodeURL(nodeURL) require.NoError(t, err, "failed to normalize Aptos node URL for onchain verification") chainID := aptosBC.ChainID() require.LessOrEqual(t, chainID, uint64(255), "Aptos chain id must fit in uint8") - chainIDUint8, err := aptosfeature.ChainIDUint8(chainID) + chainIDUint8, err := blockchains_aptos.ChainIDUint8(chainID) require.NoError(t, err, "failed to convert Aptos chain id") client, err := aptoslib.NewNodeClient(nodeURL, chainIDUint8) require.NoError(t, err, "failed to create Aptos client") @@ -535,6 +591,10 @@ func normalizeTxHashLikeHex(input string) string { return "0x" + s } +func normalizeHexValue(input string) string { + return strings.TrimPrefix(strings.ToLower(strings.TrimSpace(input)), "0x") +} + func deployAptosDataFeedsReceiverForWrite( t *testing.T, tenv *configuration.TestEnvironment, @@ -548,39 +608,29 @@ func deployAptosDataFeedsReceiverForWrite( require.True(t, ok, "expected aptos blockchain type") nodeURL := aptosBC.CtfOutput().Nodes[0].ExternalHTTPUrl require.NotEmpty(t, nodeURL, "Aptos node URL is required for receiver deployment") - nodeURL, err := aptosfeature.NormalizeNodeURL(nodeURL) + nodeURL, err := blockchains_aptos.NormalizeNodeURL(nodeURL) require.NoError(t, err, "failed to normalize Aptos node URL for receiver deployment") - containerName := aptosBC.CtfOutput().ContainerName chainID := aptosBC.ChainID() require.LessOrEqual(t, chainID, uint64(255), "Aptos chain id must fit in uint8") - chainIDUint8, err := aptosfeature.ChainIDUint8(chainID) + chainIDUint8, err := blockchains_aptos.ChainIDUint8(chainID) require.NoError(t, err, "failed to convert Aptos chain id") client, err := aptoslib.NewNodeClient(nodeURL, chainIDUint8) require.NoError(t, err, "failed to create Aptos client") deployer, err := aptosDeployerAccount() require.NoError(t, err, "failed to create Aptos deployer account") - - require.NoError( - t, - aptosfeature.FundAccountBestEffort(t.Context(), framework.L, client, nodeURL, containerName, deployer.AccountAddress(), aptosWorkerMinBalanceOctas, aptosWorkerFundingAmountOctas), - "failed to fund Aptos deployer account", - ) - require.NoError( - t, - aptosfeature.WaitForAccountVisible(t.Context(), client, deployer.AccountAddress(), 45*time.Second), - "Aptos deployer account must be visible before deploy", - ) + deployerAddress := deployer.AccountAddress() + require.NoError(t, aptosBC.Fund(t.Context(), deployerAddress.StringLong(), aptosWorkerFundingAmountOctas), "failed to fund Aptos deployer account") var primaryForwarderAddr aptoslib.AccountAddress err = primaryForwarderAddr.ParseStringRelaxed(primaryForwarderHex) require.NoError(t, err, "failed to parse primary forwarder address") - owner := deployer.AccountAddress() + owner := deployerAddress secondaryAddress, secondaryTx, _, err := aptosplatformsecondary.DeployToObject(deployer, client, owner) require.NoError(t, err, "failed to deploy Aptos secondary platform package") - require.NoError(t, aptosfeature.WaitForTransactionSuccess(client, secondaryTx.Hash, "platform_secondary deployment")) + require.NoError(t, blockchains_aptos.WaitForTransactionSuccess(client, secondaryTx.Hash, "platform_secondary deployment")) dataFeedsAddress, dataFeedsTx, dataFeeds, err := aptosdatafeeds.DeployToObject( deployer, @@ -591,7 +641,7 @@ func deployAptosDataFeedsReceiverForWrite( secondaryAddress, ) require.NoError(t, err, "failed to deploy Aptos data feeds receiver package") - require.NoError(t, aptosfeature.WaitForTransactionSuccess(client, dataFeedsTx.Hash, "data_feeds deployment")) + require.NoError(t, blockchains_aptos.WaitForTransactionSuccess(client, dataFeedsTx.Hash, "data_feeds deployment")) workflowOwner := workflowRegistryOwnerBytes(t, tenv) tx, err := dataFeeds.Registry().SetWorkflowConfig( @@ -600,7 +650,7 @@ func deployAptosDataFeedsReceiverForWrite( [][]byte{}, ) require.NoError(t, err, "failed to set data feeds workflow config") - require.NoError(t, aptosfeature.WaitForTransactionSuccess(client, tx.Hash, "data_feeds set_workflow_config")) + require.NoError(t, blockchains_aptos.WaitForTransactionSuccess(client, tx.Hash, "data_feeds set_workflow_config")) // Configure the feed that the write workflow will update. // Without this, registry::perform_update emits WriteSkippedFeedNotSet and benchmark remains unchanged. @@ -611,7 +661,7 @@ func deployAptosDataFeedsReceiverForWrite( []byte{0x99}, ) require.NoError(t, err, "failed to set data feeds feed config") - require.NoError(t, aptosfeature.WaitForTransactionSuccess(client, tx.Hash, "data_feeds set_feeds")) + require.NoError(t, blockchains_aptos.WaitForTransactionSuccess(client, tx.Hash, "data_feeds set_feeds")) return dataFeedsAddress.StringLong() } @@ -638,53 +688,19 @@ func ensureAptosWriteWorkersFunded(t *testing.T, aptosChain blockchains.Blockcha aptosBC, ok := aptosChain.(*blockchains_aptos.Blockchain) require.True(t, ok, "expected aptos blockchain type") - - nodeURL := aptosBC.CtfOutput().Nodes[0].ExternalHTTPUrl - require.NotEmpty(t, nodeURL, "Aptos node URL is required for worker funding") - nodeURL, err := aptosfeature.NormalizeNodeURL(nodeURL) - require.NoError(t, err, "failed to normalize Aptos node URL for worker funding") - - chainID := aptosBC.ChainID() - require.LessOrEqual(t, chainID, uint64(255), "Aptos chain id must fit in uint8") - chainIDUint8, err := aptosfeature.ChainIDUint8(chainID) - require.NoError(t, err, "failed to convert Aptos chain id") - client, err := aptoslib.NewNodeClient(nodeURL, chainIDUint8) - require.NoError(t, err, "failed to create Aptos client") - - containerName := aptosBC.CtfOutput().ContainerName workers, workerErr := writeDon.Workers() require.NoError(t, workerErr, "failed to list Aptos write DON workers for funding") require.NotEmpty(t, workers, "Aptos write DON workers list is empty") for _, worker := range workers { - addresses, fetchErr := crelib.AptosAccountsForNode(t.Context(), worker) - require.NoError(t, fetchErr, "failed to fetch Aptos key for worker %q", worker.Name) - require.NotEmpty(t, addresses, "missing Aptos key for worker %q", worker.Name) - for _, rawAddress := range addresses { - rawAddress = strings.TrimSpace(rawAddress) - if rawAddress == "" { - continue - } + require.NotNil(t, worker.Keys, "worker %q is missing metadata keys", worker.Name) + require.NotNil(t, worker.Keys.Aptos, "worker %q is missing metadata Aptos key", worker.Name) - var account aptoslib.AccountAddress - parseErr := account.ParseStringRelaxed(rawAddress) - require.NoError(t, parseErr, "failed to parse Aptos worker account for worker %q", worker.Name) - - require.NoError( - t, - aptosfeature.FundAccountBestEffort(t.Context(), framework.L, client, nodeURL, containerName, account, aptosWorkerMinBalanceOctas, aptosWorkerFundingAmountOctas), - "failed to fund Aptos worker account %s for worker %q", - account.StringLong(), - worker.Name, - ) - require.NoError( - t, - aptosfeature.WaitForAccountVisible(t.Context(), client, account, 45*time.Second), - "Aptos worker account %s must be visible/funded before write workflow for worker %q", - account.StringLong(), - worker.Name, - ) - } + var account aptoslib.AccountAddress + parseErr := account.ParseStringRelaxed(worker.Keys.Aptos.Account) + require.NoError(t, parseErr, "failed to parse Aptos worker account for worker %q", worker.Name) + + require.NoError(t, aptosBC.Fund(t.Context(), account.StringLong(), aptosWorkerFundingAmountOctas), "failed to fund Aptos worker account %s for worker %q", account.StringLong(), worker.Name) } } diff --git a/system-tests/tests/test-helpers/before_suite.go b/system-tests/tests/test-helpers/before_suite.go index dd397986816..045eda2e793 100644 --- a/system-tests/tests/test-helpers/before_suite.go +++ b/system-tests/tests/test-helpers/before_suite.go @@ -294,7 +294,7 @@ func GetTestConfig(t *testing.T, configPath string) *ttypes.TestConfig { return &ttypes.TestConfig{ RelativePathToRepoRoot: relativePathToRepoRoot, EnvironmentDirPath: environmentDirPath, - EnvironmentConfigPath: filepath.Join(environmentDirPath, configPath), + EnvironmentConfigPath: filepath.Join(environmentDirPath, configPath), // change to your desired config, if you want to use another topology EnvironmentStateFile: filepath.Join(environmentDirPath, envconfig.StateDirname, envconfig.LocalCREStateFilename), ChipIngressGRPCPort: chipingressset.DEFAULT_CHIP_INGRESS_GRPC_PORT, } @@ -303,6 +303,7 @@ func GetTestConfig(t *testing.T, configPath string) *ttypes.TestConfig { func getEnvironmentConfig(t *testing.T) *envconfig.Config { t.Helper() + // we call our own Load function because it executes a couple of crucial extra input transformations in := &envconfig.Config{} err := in.Load(os.Getenv("CTF_CONFIGS")) require.NoError(t, err, "couldn't load environment state") From 03c6b39287af4c6d3b0cd991fce65961ab861994 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Fri, 20 Mar 2026 16:18:09 +0000 Subject: [PATCH 16/34] lint and fix don_test --- system-tests/lib/cre/don_test.go | 11 +++++++++-- system-tests/lib/go.mod | 2 +- system-tests/tests/test-helpers/t_helpers.go | 6 +++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/system-tests/lib/cre/don_test.go b/system-tests/lib/cre/don_test.go index 77b86c29c31..7c70dab226d 100644 --- a/system-tests/lib/cre/don_test.go +++ b/system-tests/lib/cre/don_test.go @@ -2,6 +2,7 @@ package cre import ( "context" + "fmt" "net/http" "net/http/httptest" "sync/atomic" @@ -48,10 +49,16 @@ func TestAptosAccountForNode_FallsBackToNodeAPIAndCachesKey(t *testing.T) { t.Parallel() server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.Equal(t, "/v2/keys/aptos", r.URL.Path) + if r.URL.Path != "/v2/keys/aptos" { + t.Errorf("unexpected path: got %q want %q", r.URL.Path, "/v2/keys/aptos") + http.Error(w, fmt.Sprintf("unexpected path %q", r.URL.Path), http.StatusBadRequest) + return + } w.Header().Set("Content-Type", "application/json") _, err := w.Write([]byte(`{"data":[{"attributes":{"account":"0x1","publicKey":"0xabc123"}}]}`)) - require.NoError(t, err) + if err != nil { + t.Errorf("failed to write response: %v", err) + } })) t.Cleanup(server.Close) diff --git a/system-tests/lib/go.mod b/system-tests/lib/go.mod index c996afc9e69..d48d595ddf1 100644 --- a/system-tests/lib/go.mod +++ b/system-tests/lib/go.mod @@ -23,6 +23,7 @@ require ( github.com/ethereum/go-ethereum v1.17.1 github.com/fbsobreira/gotron-sdk v0.0.0-20250403083053-2943ce8c759b github.com/gagliardetto/solana-go v1.13.0 + github.com/go-resty/resty/v2 v2.17.2 github.com/goccy/go-yaml v1.19.2 github.com/google/uuid v1.6.0 github.com/jmoiron/sqlx v1.4.0 @@ -263,7 +264,6 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.30.1 // indirect - github.com/go-resty/resty/v2 v2.17.2 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect github.com/go-webauthn/webauthn v0.9.4 // indirect github.com/go-webauthn/x v0.1.5 // indirect diff --git a/system-tests/tests/test-helpers/t_helpers.go b/system-tests/tests/test-helpers/t_helpers.go index f7c3af806ec..23d2ab0c544 100644 --- a/system-tests/tests/test-helpers/t_helpers.go +++ b/system-tests/tests/test-helpers/t_helpers.go @@ -405,19 +405,19 @@ func workflowConfigFactory[T WorkflowConfig](t *testing.T, testLogger zerolog.Lo testLogger.Info().Msg("PoR v2 workflow config file created.") case *AptosReadWorkflowConfig: - workflowCfgFilePath, configErr := CreateWorkflowYamlConfigFile(workflowName, cfg) + workflowCfgFilePath, configErr := CreateWorkflowYamlConfigFile(workflowName, cfg, outputDir) workflowConfigFilePath = workflowCfgFilePath require.NoError(t, configErr, "failed to create aptos read workflow config file") testLogger.Info().Msg("Aptos read workflow config file created.") case *aptoswrite_config.Config: - workflowCfgFilePath, configErr := CreateWorkflowYamlConfigFile(workflowName, cfg) + workflowCfgFilePath, configErr := CreateWorkflowYamlConfigFile(workflowName, cfg, outputDir) workflowConfigFilePath = workflowCfgFilePath require.NoError(t, configErr, "failed to create aptos write workflow config file") testLogger.Info().Msg("Aptos write workflow config file created.") case *aptoswriteroundtrip_config.Config: - workflowCfgFilePath, configErr := CreateWorkflowYamlConfigFile(workflowName, cfg) + workflowCfgFilePath, configErr := CreateWorkflowYamlConfigFile(workflowName, cfg, outputDir) workflowConfigFilePath = workflowCfgFilePath require.NoError(t, configErr, "failed to create aptos write roundtrip workflow config file") testLogger.Info().Msg("Aptos write roundtrip workflow config file created.") From 0d6e3a8aabae631518b7b12c0fdcbc5dbf3cc626 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Fri, 20 Mar 2026 16:45:01 +0000 Subject: [PATCH 17/34] lint --- system-tests/tests/smoke/cre/v2_aptos_capability_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/system-tests/tests/smoke/cre/v2_aptos_capability_test.go b/system-tests/tests/smoke/cre/v2_aptos_capability_test.go index a5597382271..976e3eac769 100644 --- a/system-tests/tests/smoke/cre/v2_aptos_capability_test.go +++ b/system-tests/tests/smoke/cre/v2_aptos_capability_test.go @@ -43,7 +43,6 @@ import ( const aptosLocalMaxGasAmount uint64 = 200_000 const aptosWorkerFundingAmountOctas uint64 = 1_000_000_000_000 -const aptosWorkerMinBalanceOctas uint64 = 100_000_000 var aptosForwarderVersion = semver.MustParse("1.0.0") From 6afd1c6219b5ca4656b39a1a71da0238a358610b Mon Sep 17 00:00:00 2001 From: cawthorne Date: Fri, 20 Mar 2026 17:11:56 +0000 Subject: [PATCH 18/34] rename to BeforePoRTest --- system-tests/tests/smoke/cre/cre_suite_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system-tests/tests/smoke/cre/cre_suite_test.go b/system-tests/tests/smoke/cre/cre_suite_test.go index 1cd8225cd4f..6a92d66427e 100644 --- a/system-tests/tests/smoke/cre/cre_suite_test.go +++ b/system-tests/tests/smoke/cre/cre_suite_test.go @@ -66,7 +66,7 @@ func Test_CRE_V1_Billing_EVM_Write(t *testing.T) { "failed to start Billing stack", ) - priceProvider, porWfCfg := beforePoRTest(t, testEnv, "por-workflowV2-billing", PoRWFV2Location) + priceProvider, porWfCfg := BeforePoRTest(t, testEnv, "por-workflowV2-billing", PoRWFV2Location) porWfCfg.FeedIDs = []string{porWfCfg.FeedIDs[0]} ExecutePoRTest(t, testEnv, priceProvider, porWfCfg, true) } From ba461fd0043cb2aeaa5e68c7ac01654b87173704 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Wed, 25 Mar 2026 17:41:03 +0000 Subject: [PATCH 19/34] cre: repin aptos local deps and keep read CI --- core/scripts/go.mod | 6 +++--- core/scripts/go.sum | 12 ++++++------ go.mod | 6 +++--- go.sum | 12 ++++++------ plugins/plugins.private.yaml | 2 +- system-tests/lib/go.mod | 6 +++--- system-tests/lib/go.sum | 12 ++++++------ system-tests/tests/go.mod | 6 +++--- system-tests/tests/go.sum | 12 ++++++------ .../tests/smoke/cre/v2_aptos_capability_test.go | 8 ++++---- 10 files changed, 41 insertions(+), 41 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 24cdaa6f42f..0716d0117c3 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -46,13 +46,13 @@ require ( github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 - github.com/smartcontractkit/chainlink-common v0.10.1-0.20260319155722-325b0156b188 + github.com/smartcontractkit/chainlink-common v0.11.1-0.20260324124718-1e12ff95068b github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-data-streams v0.1.13 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260318010722-59d4165024f1 github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260119171452-39c98c3b33cd - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.5 github.com/smartcontractkit/chainlink-testing-framework/framework/components/dockercompose v0.1.20 @@ -485,7 +485,7 @@ require ( github.com/smartcontractkit/ccip-contract-examples/chains/evm v0.0.0-20260129135848-c86808ba5cb9 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.1.0 // indirect github.com/smartcontractkit/chain-selectors v1.0.97 // indirect - github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 // indirect + github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 // indirect github.com/smartcontractkit/chainlink-ccip/ccv/chains/evm v0.0.0-20260313162934-73fcb2020b93 // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 6c327b0b6a2..73a3c40b222 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1616,8 +1616,8 @@ github.com/smartcontractkit/ccip-owner-contracts v0.1.0 h1:GiBDtlx7539o7AKlDV+9L github.com/smartcontractkit/ccip-owner-contracts v0.1.0/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= github.com/smartcontractkit/chain-selectors v1.0.97 h1:ECOin+SkJv2MUrfqTUu28J0kub04Epds5NPMHERfGjo= github.com/smartcontractkit/chain-selectors v1.0.97/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 h1:hXteBGuRfdFA5Zj3f07la22ttq6NohB3g5d4vsHFJZ0= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200/go.mod h1:CLrLo4q6s25t9IGSMn4P1tRkrZFGjRiLOWskwPJEXrc= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 h1:goYYvVcQ3UV/Fw5R0V1jLJht/VXUxk5F8o+RwgSX9jo= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698/go.mod h1:khONNr+qqHzpZBjyTIXJEkcptm3pIOvke03ftAQibRw= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 h1:bpzTG/8qwnbnIQPcilnM8lPd/Or4Q22cnakzawds2NQ= @@ -1634,8 +1634,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260317124520-6b2931b8cd0a h1:6c6WDGfZB2ehsw9/nBuuKNCw89+rCav2k9so41pIu4o= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260317124520-6b2931b8cd0a/go.mod h1:4+ngpFXBJrxcKR0jd2CUZFYJVtL8pPJfBXHbGfSNJeA= -github.com/smartcontractkit/chainlink-common v0.10.1-0.20260319155722-325b0156b188 h1:6n15Fng45mSa2OEqRAiFk4e/6O5mZpo15eXzgF5g5xA= -github.com/smartcontractkit/chainlink-common v0.10.1-0.20260319155722-325b0156b188/go.mod h1:0ghbAr7tRO0tT5ZqBXhOyzgUO37tNNe33Yn0hskauVM= +github.com/smartcontractkit/chainlink-common v0.11.1-0.20260324124718-1e12ff95068b h1:81nacxJivGFaS22Hp2M1nT1bfy4/u/MEZd3eqDQIyfc= +github.com/smartcontractkit/chainlink-common v0.11.1-0.20260324124718-1e12ff95068b/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20251211140724-319861e514c4 h1:NOUsjsMzNecbjiPWUQGlRSRAutEvCFrqqyETDJeh5q4= @@ -1672,8 +1672,8 @@ github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0. github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396 h1:03tbcwjyIEjvHba1IWOj1sfThwebm2XNzyFHSuZtlWc= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 h1:fkS5FJpSozwxL2FA6OJDi7az2DrtMNiK1X5DWuHDyfA= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 h1:q+VDPcxWrj5k9QizSYfUOSMnDH3Sd5HvbPguZOgfXTY= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= diff --git a/go.mod b/go.mod index 48add0ad2f0..0eb0804bb29 100644 --- a/go.mod +++ b/go.mod @@ -79,13 +79,13 @@ require ( github.com/shirou/gopsutil/v3 v3.24.3 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chain-selectors v1.0.97 - github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 + github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260224214816-cb23ec38649f github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5 github.com/smartcontractkit/chainlink-ccv v0.0.0-20260317124520-6b2931b8cd0a - github.com/smartcontractkit/chainlink-common v0.10.1-0.20260319155722-325b0156b188 + github.com/smartcontractkit/chainlink-common v0.11.1-0.20260324124718-1e12ff95068b github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 github.com/smartcontractkit/chainlink-data-streams v0.1.13 @@ -97,7 +97,7 @@ require ( github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20260317132927-e8bc2c7b01f1 github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20251021173435-e86785845942 github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 github.com/smartcontractkit/chainlink-protos/ring/go v0.0.0-20260128151123-605e9540b706 diff --git a/go.sum b/go.sum index 02f01b94436..31e79b4bee3 100644 --- a/go.sum +++ b/go.sum @@ -1221,8 +1221,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartcontractkit/chain-selectors v1.0.97 h1:ECOin+SkJv2MUrfqTUu28J0kub04Epds5NPMHERfGjo= github.com/smartcontractkit/chain-selectors v1.0.97/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 h1:hXteBGuRfdFA5Zj3f07la22ttq6NohB3g5d4vsHFJZ0= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200/go.mod h1:CLrLo4q6s25t9IGSMn4P1tRkrZFGjRiLOWskwPJEXrc= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 h1:goYYvVcQ3UV/Fw5R0V1jLJht/VXUxk5F8o+RwgSX9jo= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698/go.mod h1:khONNr+qqHzpZBjyTIXJEkcptm3pIOvke03ftAQibRw= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 h1:bpzTG/8qwnbnIQPcilnM8lPd/Or4Q22cnakzawds2NQ= @@ -1235,8 +1235,8 @@ github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5/go.mod h1:xtZNi6pOKdC3sLvokDvXOhgHzT+cyBqH/gWwvxTxqrg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260317124520-6b2931b8cd0a h1:6c6WDGfZB2ehsw9/nBuuKNCw89+rCav2k9so41pIu4o= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260317124520-6b2931b8cd0a/go.mod h1:4+ngpFXBJrxcKR0jd2CUZFYJVtL8pPJfBXHbGfSNJeA= -github.com/smartcontractkit/chainlink-common v0.10.1-0.20260319155722-325b0156b188 h1:6n15Fng45mSa2OEqRAiFk4e/6O5mZpo15eXzgF5g5xA= -github.com/smartcontractkit/chainlink-common v0.10.1-0.20260319155722-325b0156b188/go.mod h1:0ghbAr7tRO0tT5ZqBXhOyzgUO37tNNe33Yn0hskauVM= +github.com/smartcontractkit/chainlink-common v0.11.1-0.20260324124718-1e12ff95068b h1:81nacxJivGFaS22Hp2M1nT1bfy4/u/MEZd3eqDQIyfc= +github.com/smartcontractkit/chainlink-common v0.11.1-0.20260324124718-1e12ff95068b/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= @@ -1271,8 +1271,8 @@ github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0. github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396 h1:03tbcwjyIEjvHba1IWOj1sfThwebm2XNzyFHSuZtlWc= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 h1:fkS5FJpSozwxL2FA6OJDi7az2DrtMNiK1X5DWuHDyfA= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY= github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260211172625-dff40e83b3c9 h1:hhevsu8k7tlDRrYZmgAh7V4avGQDMvus1bwIlial3Ps= diff --git a/plugins/plugins.private.yaml b/plugins/plugins.private.yaml index 2960d11a7bc..ab742b2f8eb 100644 --- a/plugins/plugins.private.yaml +++ b/plugins/plugins.private.yaml @@ -48,7 +48,7 @@ plugins: installPath: "." aptos: - moduleURI: "github.com/smartcontractkit/capabilities/chain_capabilities/aptos" - gitRef: "bab47549446cf8a47093b983419dbd3f06b40329" + gitRef: "be982f5604e86c91ba7fac14790e38648d5b9c1b" installPath: "." mock: - moduleURI: "github.com/smartcontractkit/capabilities/mock" diff --git a/system-tests/lib/go.mod b/system-tests/lib/go.mod index d48d595ddf1..a57e6630692 100644 --- a/system-tests/lib/go.mod +++ b/system-tests/lib/go.mod @@ -33,14 +33,14 @@ require ( github.com/scylladb/go-reflectx v1.0.1 github.com/sethvargo/go-retry v0.3.0 github.com/smartcontractkit/chain-selectors v1.0.97 - github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 + github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.10.1-0.20260319155722-325b0156b188 + github.com/smartcontractkit/chainlink-common v0.11.1-0.20260324124718-1e12ff95068b github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260318010722-59d4165024f1 github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260119171452-39c98c3b33cd - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260217043601-5cc966896c4f github.com/smartcontractkit/chainlink-solana v1.1.2-0.20260318003508-442c25062e9a diff --git a/system-tests/lib/go.sum b/system-tests/lib/go.sum index b5b6f8645cc..8ff829eacd0 100644 --- a/system-tests/lib/go.sum +++ b/system-tests/lib/go.sum @@ -1579,8 +1579,8 @@ github.com/smartcontractkit/ccip-owner-contracts v0.1.0 h1:GiBDtlx7539o7AKlDV+9L github.com/smartcontractkit/ccip-owner-contracts v0.1.0/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= github.com/smartcontractkit/chain-selectors v1.0.97 h1:ECOin+SkJv2MUrfqTUu28J0kub04Epds5NPMHERfGjo= github.com/smartcontractkit/chain-selectors v1.0.97/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 h1:hXteBGuRfdFA5Zj3f07la22ttq6NohB3g5d4vsHFJZ0= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200/go.mod h1:CLrLo4q6s25t9IGSMn4P1tRkrZFGjRiLOWskwPJEXrc= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 h1:goYYvVcQ3UV/Fw5R0V1jLJht/VXUxk5F8o+RwgSX9jo= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698/go.mod h1:khONNr+qqHzpZBjyTIXJEkcptm3pIOvke03ftAQibRw= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 h1:bpzTG/8qwnbnIQPcilnM8lPd/Or4Q22cnakzawds2NQ= @@ -1597,8 +1597,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260317124520-6b2931b8cd0a h1:6c6WDGfZB2ehsw9/nBuuKNCw89+rCav2k9so41pIu4o= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260317124520-6b2931b8cd0a/go.mod h1:4+ngpFXBJrxcKR0jd2CUZFYJVtL8pPJfBXHbGfSNJeA= -github.com/smartcontractkit/chainlink-common v0.10.1-0.20260319155722-325b0156b188 h1:6n15Fng45mSa2OEqRAiFk4e/6O5mZpo15eXzgF5g5xA= -github.com/smartcontractkit/chainlink-common v0.10.1-0.20260319155722-325b0156b188/go.mod h1:0ghbAr7tRO0tT5ZqBXhOyzgUO37tNNe33Yn0hskauVM= +github.com/smartcontractkit/chainlink-common v0.11.1-0.20260324124718-1e12ff95068b h1:81nacxJivGFaS22Hp2M1nT1bfy4/u/MEZd3eqDQIyfc= +github.com/smartcontractkit/chainlink-common v0.11.1-0.20260324124718-1e12ff95068b/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= @@ -1635,8 +1635,8 @@ github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0. github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396 h1:03tbcwjyIEjvHba1IWOj1sfThwebm2XNzyFHSuZtlWc= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260226130359-963f935e0396/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 h1:fkS5FJpSozwxL2FA6OJDi7az2DrtMNiK1X5DWuHDyfA= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 h1:q+VDPcxWrj5k9QizSYfUOSMnDH3Sd5HvbPguZOgfXTY= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= diff --git a/system-tests/tests/go.mod b/system-tests/tests/go.mod index 3aafecf055d..f3c120d7c22 100644 --- a/system-tests/tests/go.mod +++ b/system-tests/tests/go.mod @@ -60,12 +60,12 @@ require ( github.com/rs/zerolog v1.34.0 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chain-selectors v1.0.97 - github.com/smartcontractkit/chainlink-common v0.10.1-0.20260319155722-325b0156b188 + github.com/smartcontractkit/chainlink-common v0.11.1-0.20260324124718-1e12ff95068b github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-data-streams v0.1.13 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260119171452-39c98c3b33cd - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 github.com/smartcontractkit/chainlink-protos/ring/go v0.0.0-20260128151123-605e9540b706 github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260217043601-5cc966896c4f @@ -588,7 +588,7 @@ require ( github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/smartcontractkit/ccip-contract-examples/chains/evm v0.0.0-20260129135848-c86808ba5cb9 // indirect github.com/smartcontractkit/ccip-owner-contracts v0.1.0 // indirect - github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 + github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 github.com/smartcontractkit/chainlink-automation v0.8.1 // indirect github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 // indirect github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20251211140724-319861e514c4 diff --git a/system-tests/tests/go.sum b/system-tests/tests/go.sum index a50ab00d0a6..3f42eab950f 100644 --- a/system-tests/tests/go.sum +++ b/system-tests/tests/go.sum @@ -1763,8 +1763,8 @@ github.com/smartcontractkit/ccip-owner-contracts v0.1.0 h1:GiBDtlx7539o7AKlDV+9L github.com/smartcontractkit/ccip-owner-contracts v0.1.0/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= github.com/smartcontractkit/chain-selectors v1.0.97 h1:ECOin+SkJv2MUrfqTUu28J0kub04Epds5NPMHERfGjo= github.com/smartcontractkit/chain-selectors v1.0.97/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 h1:hXteBGuRfdFA5Zj3f07la22ttq6NohB3g5d4vsHFJZ0= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200/go.mod h1:CLrLo4q6s25t9IGSMn4P1tRkrZFGjRiLOWskwPJEXrc= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 h1:goYYvVcQ3UV/Fw5R0V1jLJht/VXUxk5F8o+RwgSX9jo= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698/go.mod h1:khONNr+qqHzpZBjyTIXJEkcptm3pIOvke03ftAQibRw= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 h1:bpzTG/8qwnbnIQPcilnM8lPd/Or4Q22cnakzawds2NQ= @@ -1781,8 +1781,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260317124520-6b2931b8cd0a h1:6c6WDGfZB2ehsw9/nBuuKNCw89+rCav2k9so41pIu4o= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260317124520-6b2931b8cd0a/go.mod h1:4+ngpFXBJrxcKR0jd2CUZFYJVtL8pPJfBXHbGfSNJeA= -github.com/smartcontractkit/chainlink-common v0.10.1-0.20260319155722-325b0156b188 h1:6n15Fng45mSa2OEqRAiFk4e/6O5mZpo15eXzgF5g5xA= -github.com/smartcontractkit/chainlink-common v0.10.1-0.20260319155722-325b0156b188/go.mod h1:0ghbAr7tRO0tT5ZqBXhOyzgUO37tNNe33Yn0hskauVM= +github.com/smartcontractkit/chainlink-common v0.11.1-0.20260324124718-1e12ff95068b h1:81nacxJivGFaS22Hp2M1nT1bfy4/u/MEZd3eqDQIyfc= +github.com/smartcontractkit/chainlink-common v0.11.1-0.20260324124718-1e12ff95068b/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20251211140724-319861e514c4 h1:NOUsjsMzNecbjiPWUQGlRSRAutEvCFrqqyETDJeh5q4= @@ -1819,8 +1819,8 @@ github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0. github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c h1:m+XflniQiuMPvcKtiWpnsqpOiRNcONKrhF5zwpR2QJM= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 h1:fkS5FJpSozwxL2FA6OJDi7az2DrtMNiK1X5DWuHDyfA= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 h1:q+VDPcxWrj5k9QizSYfUOSMnDH3Sd5HvbPguZOgfXTY= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= diff --git a/system-tests/tests/smoke/cre/v2_aptos_capability_test.go b/system-tests/tests/smoke/cre/v2_aptos_capability_test.go index 976e3eac769..2a5a614de13 100644 --- a/system-tests/tests/smoke/cre/v2_aptos_capability_test.go +++ b/system-tests/tests/smoke/cre/v2_aptos_capability_test.go @@ -46,8 +46,9 @@ const aptosWorkerFundingAmountOctas uint64 = 1_000_000_000_000 var aptosForwarderVersion = semver.MustParse("1.0.0") -// ExecuteAptosTest runs the Aptos CRE suite with the minimum CI scenarios that -// still cover the end-to-end happy path and the expected-failure path. +// ExecuteAptosTest runs the Aptos CRE suite with the read path only. The write +// scenarios stay available for local/manual execution until the write-report CI +// path is ready again. func ExecuteAptosTest(t *testing.T, tenv *configuration.TestEnvironment) { executeAptosScenarios(t, tenv, aptosDefaultScenarios()) } @@ -65,8 +66,7 @@ type aptosScenario struct { func aptosDefaultScenarios() []aptosScenario { return []aptosScenario{ - {name: "Aptos Write Read Roundtrip", run: ExecuteAptosWriteReadRoundtripTest}, - {name: "Aptos Write Expected Failure", run: ExecuteAptosWriteExpectedFailureTest}, + {name: "Aptos Read", run: ExecuteAptosReadTest}, } } From ae5c7d6549a5cb2d00cfa1c7ac5a285e7f067acb Mon Sep 17 00:00:00 2001 From: cawthorne Date: Wed, 25 Mar 2026 18:04:00 +0000 Subject: [PATCH 20/34] cre: share aptos internal node URL helper --- system-tests/lib/cre/don/config/config.go | 32 ++++++++----------- .../environment/blockchains/aptos/aptos.go | 7 ++++ 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/system-tests/lib/cre/don/config/config.go b/system-tests/lib/cre/don/config/config.go index 4c992ce2dee..53ade9ae1eb 100644 --- a/system-tests/lib/cre/don/config/config.go +++ b/system-tests/lib/cre/don/config/config.go @@ -5,7 +5,6 @@ import ( "fmt" "maps" "math/big" - "net/url" "slices" "strconv" "strings" @@ -36,6 +35,7 @@ import ( "github.com/smartcontractkit/chainlink/system-tests/lib/cre" crecontracts "github.com/smartcontractkit/chainlink/system-tests/lib/cre/contracts" creblockchains "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains" + aptoschain "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains/aptos" "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains/solana" "github.com/smartcontractkit/chainlink/system-tests/lib/infra" ) @@ -682,7 +682,10 @@ func gatherCommonInputs(input cre.GenerateConfigsInput) (*commonInputs, error) { capabilitiesRegistryAddress := crecontracts.MustGetAddressFromDataStore(input.Datastore, input.RegistryChainSelector, keystone_changeset.CapabilitiesRegistry.String(), input.ContractVersions[keystone_changeset.CapabilitiesRegistry.String()], "") workflowRegistryAddress := crecontracts.MustGetAddressFromDataStore(input.Datastore, input.RegistryChainSelector, keystone_changeset.WorkflowRegistry.String(), input.ContractVersions[keystone_changeset.WorkflowRegistry.String()], "") - aptosChains := findAptosChains(input) + aptosChains, aptosErr := findAptosChains(input) + if aptosErr != nil { + return nil, errors.Wrap(aptosErr, "failed to find Aptos chains in the environment configuration") + } return &commonInputs{ registryChainID: registryChainID, @@ -773,20 +776,7 @@ func findOneSolanaChain(input cre.GenerateConfigsInput) (*solanaChain, error) { const aptosZeroForwarderHex = "0x0000000000000000000000000000000000000000000000000000000000000000" -// aptosNodeURLWithV1 normalizes an Aptos node URL so the path is /v1 (Aptos REST API base). -func aptosNodeURLWithV1(nodeURL string) string { - u, err := url.Parse(nodeURL) - if err != nil { - return nodeURL - } - path := strings.TrimRight(u.Path, "/") - if path == "" || path != "/v1" { - u.Path = "/v1" - } - return u.String() -} - -func findAptosChains(input cre.GenerateConfigsInput) []*aptosChain { +func findAptosChains(input cre.GenerateConfigsInput) ([]*aptosChain, error) { capabilityChainIDs := input.DonMetadata.MustNodeSet().ChainCapabilityChainIDs() out := make([]*aptosChain, 0) for _, bcOut := range input.Blockchains { @@ -796,14 +786,20 @@ func findAptosChains(input cre.GenerateConfigsInput) []*aptosChain { if len(capabilityChainIDs) > 0 && !slices.Contains(capabilityChainIDs, bcOut.ChainID()) { continue } - nodeURL := aptosNodeURLWithV1(bcOut.CtfOutput().Nodes[0].InternalHTTPUrl) + + aptosBC := bcOut.(*aptoschain.Blockchain) + nodeURL, err := aptosBC.InternalNodeURL() + if err != nil { + return nil, errors.Wrapf(err, "failed to get Aptos internal node URL for chain %d", bcOut.ChainID()) + } + out = append(out, &aptosChain{ ChainID: strconv.FormatUint(bcOut.ChainID(), 10), NodeURL: nodeURL, ForwarderAddress: aptosZeroForwarderHex, }) } - return out + return out, nil } func buildTronEVMConfig(evmChain *evmChain) evmconfigtoml.EVMConfig { diff --git a/system-tests/lib/cre/environment/blockchains/aptos/aptos.go b/system-tests/lib/cre/environment/blockchains/aptos/aptos.go index aa8acbb645e..461a86ea4b4 100644 --- a/system-tests/lib/cre/environment/blockchains/aptos/aptos.go +++ b/system-tests/lib/cre/environment/blockchains/aptos/aptos.go @@ -61,6 +61,13 @@ func (a *Blockchain) NodeURL() (string, error) { return NormalizeNodeURL(a.ctfOutput.Nodes[0].ExternalHTTPUrl) } +func (a *Blockchain) InternalNodeURL() (string, error) { + if a.ctfOutput == nil || len(a.ctfOutput.Nodes) == 0 { + return "", fmt.Errorf("no nodes found for Aptos chain %s-%d", a.ChainFamily(), a.chainID) + } + return NormalizeNodeURL(a.ctfOutput.Nodes[0].InternalHTTPUrl) +} + func (a *Blockchain) NodeClient() (*aptoslib.NodeClient, error) { nodeURL, err := a.NodeURL() if err != nil { From e435004a52958c736de9651bfdc47203f42ba6c8 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Wed, 25 Mar 2026 18:24:01 +0000 Subject: [PATCH 21/34] plugins: pin aptos capability branch head --- plugins/plugins.private.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/plugins.private.yaml b/plugins/plugins.private.yaml index 046411c5677..34a3180b371 100644 --- a/plugins/plugins.private.yaml +++ b/plugins/plugins.private.yaml @@ -48,7 +48,7 @@ plugins: installPath: "." aptos: - moduleURI: "github.com/smartcontractkit/capabilities/chain_capabilities/aptos" - gitRef: "5cada8dc7b542ace4f8da42d1fea8f8aac74c8e2" + gitRef: "c55222dcfa1f4304efe0b2ff532ed31429bc748e" installPath: "." mock: - moduleURI: "github.com/smartcontractkit/capabilities/mock" From 9663bae6c99d959a4e510d9fe4890a0e103fba6d Mon Sep 17 00:00:00 2001 From: cawthorne Date: Wed, 25 Mar 2026 18:31:16 +0000 Subject: [PATCH 22/34] cre: repin aptos transitive modules and public plugin --- deployment/go.mod | 2 +- deployment/go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- plugins/plugins.public.yaml | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/deployment/go.mod b/deployment/go.mod index 62165212e6c..1e6520840f1 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -38,7 +38,7 @@ require ( github.com/smartcontractkit/ccip-contract-examples/chains/evm v0.0.0-20260129135848-c86808ba5cb9 github.com/smartcontractkit/ccip-owner-contracts v0.1.0 github.com/smartcontractkit/chain-selectors v1.0.97 - github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 + github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-ccip/chains/evm/deployment v0.0.0-20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260224214816-cb23ec38649f diff --git a/deployment/go.sum b/deployment/go.sum index 87f706591c9..3c4ea6b3cd3 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1369,8 +1369,8 @@ github.com/smartcontractkit/ccip-owner-contracts v0.1.0 h1:GiBDtlx7539o7AKlDV+9L github.com/smartcontractkit/ccip-owner-contracts v0.1.0/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= github.com/smartcontractkit/chain-selectors v1.0.97 h1:ECOin+SkJv2MUrfqTUu28J0kub04Epds5NPMHERfGjo= github.com/smartcontractkit/chain-selectors v1.0.97/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 h1:hXteBGuRfdFA5Zj3f07la22ttq6NohB3g5d4vsHFJZ0= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200/go.mod h1:CLrLo4q6s25t9IGSMn4P1tRkrZFGjRiLOWskwPJEXrc= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 h1:goYYvVcQ3UV/Fw5R0V1jLJht/VXUxk5F8o+RwgSX9jo= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698/go.mod h1:khONNr+qqHzpZBjyTIXJEkcptm3pIOvke03ftAQibRw= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 h1:bpzTG/8qwnbnIQPcilnM8lPd/Or4Q22cnakzawds2NQ= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index b06923d0586..5c5d6fcaf92 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -42,7 +42,7 @@ require ( github.com/shopspring/decimal v1.4.0 github.com/slack-go/slack v0.15.0 github.com/smartcontractkit/chain-selectors v1.0.97 - github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 + github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 8201c16deff..45d231fe0ad 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1608,8 +1608,8 @@ github.com/smartcontractkit/ccip-owner-contracts v0.1.0 h1:GiBDtlx7539o7AKlDV+9L github.com/smartcontractkit/ccip-owner-contracts v0.1.0/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= github.com/smartcontractkit/chain-selectors v1.0.97 h1:ECOin+SkJv2MUrfqTUu28J0kub04Epds5NPMHERfGjo= github.com/smartcontractkit/chain-selectors v1.0.97/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 h1:hXteBGuRfdFA5Zj3f07la22ttq6NohB3g5d4vsHFJZ0= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200/go.mod h1:CLrLo4q6s25t9IGSMn4P1tRkrZFGjRiLOWskwPJEXrc= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 h1:goYYvVcQ3UV/Fw5R0V1jLJht/VXUxk5F8o+RwgSX9jo= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698/go.mod h1:khONNr+qqHzpZBjyTIXJEkcptm3pIOvke03ftAQibRw= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 h1:bpzTG/8qwnbnIQPcilnM8lPd/Or4Q22cnakzawds2NQ= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 58e172d9b07..e57589c5b4a 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -23,7 +23,7 @@ require ( github.com/gagliardetto/solana-go v1.13.0 github.com/rs/zerolog v1.34.0 github.com/smartcontractkit/chain-selectors v1.0.97 - github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 + github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index bf2007188ce..8f5c83c1d9c 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1578,8 +1578,8 @@ github.com/smartcontractkit/ccip-owner-contracts v0.1.0 h1:GiBDtlx7539o7AKlDV+9L github.com/smartcontractkit/ccip-owner-contracts v0.1.0/go.mod h1:NnT6w4Kj42OFFXhSx99LvJZWPpMjmo4+CpDEWfw61xY= github.com/smartcontractkit/chain-selectors v1.0.97 h1:ECOin+SkJv2MUrfqTUu28J0kub04Epds5NPMHERfGjo= github.com/smartcontractkit/chain-selectors v1.0.97/go.mod h1:qy7whtgG5g+7z0jt0nRyii9bLND9m15NZTzuQPkMZ5w= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 h1:hXteBGuRfdFA5Zj3f07la22ttq6NohB3g5d4vsHFJZ0= -github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200/go.mod h1:CLrLo4q6s25t9IGSMn4P1tRkrZFGjRiLOWskwPJEXrc= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 h1:goYYvVcQ3UV/Fw5R0V1jLJht/VXUxk5F8o+RwgSX9jo= +github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698/go.mod h1:khONNr+qqHzpZBjyTIXJEkcptm3pIOvke03ftAQibRw= github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU= github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08= github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 h1:bpzTG/8qwnbnIQPcilnM8lPd/Or4Q22cnakzawds2NQ= diff --git a/plugins/plugins.public.yaml b/plugins/plugins.public.yaml index e0b53817230..8fa87391ef3 100644 --- a/plugins/plugins.public.yaml +++ b/plugins/plugins.public.yaml @@ -10,7 +10,7 @@ defaults: plugins: aptos: - moduleURI: "github.com/smartcontractkit/chainlink-aptos" - gitRef: "v0.0.0-20260318173523-755cafb24200" + gitRef: "v0.0.0-20260324144720-484863604698" installPath: "./cmd/chainlink-aptos" sui: From f041ef29f4eae6eabb76cb6bca38d637e81a024f Mon Sep 17 00:00:00 2001 From: cawthorne Date: Wed, 25 Mar 2026 19:00:01 +0000 Subject: [PATCH 23/34] cre: repin aptos workflow modules upstream --- system-tests/tests/smoke/cre/aptos/aptosread/go.mod | 6 +++--- system-tests/tests/smoke/cre/aptos/aptosread/go.sum | 12 ++++++------ system-tests/tests/smoke/cre/aptos/aptoswrite/go.mod | 6 +++--- system-tests/tests/smoke/cre/aptos/aptoswrite/go.sum | 12 ++++++------ .../tests/smoke/cre/aptos/aptoswriteroundtrip/go.mod | 6 +++--- .../tests/smoke/cre/aptos/aptoswriteroundtrip/go.sum | 12 ++++++------ 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/system-tests/tests/smoke/cre/aptos/aptosread/go.mod b/system-tests/tests/smoke/cre/aptos/aptosread/go.mod index 0dca8e844ce..92eaeaa1e11 100644 --- a/system-tests/tests/smoke/cre/aptos/aptosread/go.mod +++ b/system-tests/tests/smoke/cre/aptos/aptosread/go.mod @@ -3,8 +3,8 @@ module github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/ go 1.25.5 require ( - github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 - github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed + github.com/smartcontractkit/cre-sdk-go v1.4.1-0.20260312154349-ecb4cb615f37 + github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260312154349-ecb4cb615f37 github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -14,7 +14,7 @@ require ( github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/shopspring/decimal v1.4.0 // indirect - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c // indirect + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4 // indirect github.com/stretchr/testify v1.11.1 // indirect google.golang.org/protobuf v1.36.11 // indirect ) diff --git a/system-tests/tests/smoke/cre/aptos/aptosread/go.sum b/system-tests/tests/smoke/cre/aptos/aptosread/go.sum index 314c081af43..32c4532781c 100644 --- a/system-tests/tests/smoke/cre/aptos/aptosread/go.sum +++ b/system-tests/tests/smoke/cre/aptos/aptosread/go.sum @@ -8,12 +8,12 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c h1:m+XflniQiuMPvcKtiWpnsqpOiRNcONKrhF5zwpR2QJM= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= -github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 h1:sY79Ue8wkzPbpo4tFvvGSQiTMiqBvgyL0FBJV2UIhWI= -github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373/go.mod h1:MP93PP7lxaFyW+RRNYcEdXHm/gJM/HPqRPUPOAfBH4w= -github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed h1:sShKvyFh1MNBXW5cxau/U2IB4dTdYGah/n5d9G0gOnA= -github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed/go.mod h1:gonMhNKHWWnkNYSfxad+6sVUgZP2LVM4+qm8VqrWqZQ= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4 h1:kqdSsgt2OzJnAk0io8GsA2lJE5hKlLM2EY4uy+R6H9Y= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/cre-sdk-go v1.4.1-0.20260312154349-ecb4cb615f37 h1:+awsWWPj1CWtvcDwU8QAkUvljo/YYpnKGDrZc2afYls= +github.com/smartcontractkit/cre-sdk-go v1.4.1-0.20260312154349-ecb4cb615f37/go.mod h1:yYrQFz1UH7hhRbPO0q4fgo1tfsJNd4yXnI3oCZE0RzM= +github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260312154349-ecb4cb615f37 h1:UNem52lhklNEp4VdPBYHN+p1wgG0vDYEKSvonQgV+3o= +github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260312154349-ecb4cb615f37/go.mod h1:Ht8wSAAJRJgaZig5kwE5ogRJFngEmfQqBO0e+0y0Zng= github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0 h1:g7UrVaNKVEmIhVkJTk4f8raCM8Kp/RTFnAT64wqNmTY= github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0/go.mod h1:PWyrIw16It4TSyq6mDXqmSR0jF2evZRKuBxu7pK1yDw= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= diff --git a/system-tests/tests/smoke/cre/aptos/aptoswrite/go.mod b/system-tests/tests/smoke/cre/aptos/aptoswrite/go.mod index d8337bae77c..588331939b0 100644 --- a/system-tests/tests/smoke/cre/aptos/aptoswrite/go.mod +++ b/system-tests/tests/smoke/cre/aptos/aptoswrite/go.mod @@ -3,9 +3,9 @@ module github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/ go 1.25.5 require ( - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c - github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 - github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4 + github.com/smartcontractkit/cre-sdk-go v1.4.1-0.20260312154349-ecb4cb615f37 + github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260312154349-ecb4cb615f37 github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/system-tests/tests/smoke/cre/aptos/aptoswrite/go.sum b/system-tests/tests/smoke/cre/aptos/aptoswrite/go.sum index 314c081af43..32c4532781c 100644 --- a/system-tests/tests/smoke/cre/aptos/aptoswrite/go.sum +++ b/system-tests/tests/smoke/cre/aptos/aptoswrite/go.sum @@ -8,12 +8,12 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c h1:m+XflniQiuMPvcKtiWpnsqpOiRNcONKrhF5zwpR2QJM= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= -github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 h1:sY79Ue8wkzPbpo4tFvvGSQiTMiqBvgyL0FBJV2UIhWI= -github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373/go.mod h1:MP93PP7lxaFyW+RRNYcEdXHm/gJM/HPqRPUPOAfBH4w= -github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed h1:sShKvyFh1MNBXW5cxau/U2IB4dTdYGah/n5d9G0gOnA= -github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed/go.mod h1:gonMhNKHWWnkNYSfxad+6sVUgZP2LVM4+qm8VqrWqZQ= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4 h1:kqdSsgt2OzJnAk0io8GsA2lJE5hKlLM2EY4uy+R6H9Y= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/cre-sdk-go v1.4.1-0.20260312154349-ecb4cb615f37 h1:+awsWWPj1CWtvcDwU8QAkUvljo/YYpnKGDrZc2afYls= +github.com/smartcontractkit/cre-sdk-go v1.4.1-0.20260312154349-ecb4cb615f37/go.mod h1:yYrQFz1UH7hhRbPO0q4fgo1tfsJNd4yXnI3oCZE0RzM= +github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260312154349-ecb4cb615f37 h1:UNem52lhklNEp4VdPBYHN+p1wgG0vDYEKSvonQgV+3o= +github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260312154349-ecb4cb615f37/go.mod h1:Ht8wSAAJRJgaZig5kwE5ogRJFngEmfQqBO0e+0y0Zng= github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0 h1:g7UrVaNKVEmIhVkJTk4f8raCM8Kp/RTFnAT64wqNmTY= github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0/go.mod h1:PWyrIw16It4TSyq6mDXqmSR0jF2evZRKuBxu7pK1yDw= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= diff --git a/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.mod b/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.mod index b76176fc279..3acde03e5a6 100644 --- a/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.mod +++ b/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.mod @@ -3,9 +3,9 @@ module github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/aptos/ go 1.25.5 require ( - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c - github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 - github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4 + github.com/smartcontractkit/cre-sdk-go v1.4.1-0.20260312154349-ecb4cb615f37 + github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260312154349-ecb4cb615f37 github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.sum b/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.sum index 314c081af43..32c4532781c 100644 --- a/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.sum +++ b/system-tests/tests/smoke/cre/aptos/aptoswriteroundtrip/go.sum @@ -8,12 +8,12 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c h1:m+XflniQiuMPvcKtiWpnsqpOiRNcONKrhF5zwpR2QJM= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260318054214-bad7873faa1c/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= -github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 h1:sY79Ue8wkzPbpo4tFvvGSQiTMiqBvgyL0FBJV2UIhWI= -github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373/go.mod h1:MP93PP7lxaFyW+RRNYcEdXHm/gJM/HPqRPUPOAfBH4w= -github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed h1:sShKvyFh1MNBXW5cxau/U2IB4dTdYGah/n5d9G0gOnA= -github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260317133250-2edd562283ed/go.mod h1:gonMhNKHWWnkNYSfxad+6sVUgZP2LVM4+qm8VqrWqZQ= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4 h1:kqdSsgt2OzJnAk0io8GsA2lJE5hKlLM2EY4uy+R6H9Y= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/cre-sdk-go v1.4.1-0.20260312154349-ecb4cb615f37 h1:+awsWWPj1CWtvcDwU8QAkUvljo/YYpnKGDrZc2afYls= +github.com/smartcontractkit/cre-sdk-go v1.4.1-0.20260312154349-ecb4cb615f37/go.mod h1:yYrQFz1UH7hhRbPO0q4fgo1tfsJNd4yXnI3oCZE0RzM= +github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260312154349-ecb4cb615f37 h1:UNem52lhklNEp4VdPBYHN+p1wgG0vDYEKSvonQgV+3o= +github.com/smartcontractkit/cre-sdk-go/capabilities/blockchain/aptos v0.0.0-20260312154349-ecb4cb615f37/go.mod h1:Ht8wSAAJRJgaZig5kwE5ogRJFngEmfQqBO0e+0y0Zng= github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0 h1:g7UrVaNKVEmIhVkJTk4f8raCM8Kp/RTFnAT64wqNmTY= github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v0.10.0/go.mod h1:PWyrIw16It4TSyq6mDXqmSR0jF2evZRKuBxu7pK1yDw= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= From c1f43d78e123aa9b66b6eb0ef56c3b0b4d0b5c75 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Wed, 25 Mar 2026 20:06:13 +0000 Subject: [PATCH 24/34] plugins: repin aptos capability to merged main --- plugins/plugins.private.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/plugins.private.yaml b/plugins/plugins.private.yaml index 34a3180b371..69a67c427e6 100644 --- a/plugins/plugins.private.yaml +++ b/plugins/plugins.private.yaml @@ -48,7 +48,7 @@ plugins: installPath: "." aptos: - moduleURI: "github.com/smartcontractkit/capabilities/chain_capabilities/aptos" - gitRef: "c55222dcfa1f4304efe0b2ff532ed31429bc748e" + gitRef: "98d846140eb6620ae10d73e2489df4377cbddba1" installPath: "." mock: - moduleURI: "github.com/smartcontractkit/capabilities/mock" From ec38097882c1311f3cdb7de3ee1694bb3182a125 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 26 Mar 2026 12:28:32 +0000 Subject: [PATCH 25/34] deps: pin chainlink-common aptos compat fix --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- deployment/go.mod | 2 +- deployment/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- system-tests/lib/go.mod | 2 +- system-tests/lib/go.sum | 4 ++-- system-tests/tests/go.mod | 4 ++-- system-tests/tests/go.sum | 12 ++++++------ 14 files changed, 26 insertions(+), 26 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 0b930e9007f..b96ba5b0d4b 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -46,7 +46,7 @@ require ( github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 - github.com/smartcontractkit/chainlink-common v0.11.1 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-data-streams v0.1.13 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 8872cd60f45..1ec80887832 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1634,8 +1634,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.1 h1:JVTnqoQjdLDmQQXNgssmzEQnJK0gQ/0427LqS4UDuqE= -github.com/smartcontractkit/chainlink-common v0.11.1/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c h1:u29Hem3LUYpWtamoXy4Xib4xUe1ao1AcL4lvcgZYnkE= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20251211140724-319861e514c4 h1:NOUsjsMzNecbjiPWUQGlRSRAutEvCFrqqyETDJeh5q4= diff --git a/deployment/go.mod b/deployment/go.mod index 1e6520840f1..88e94925131 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -44,7 +44,7 @@ require ( github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260224214816-cb23ec38649f github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317175207-e9ff89561326 - github.com/smartcontractkit/chainlink-common v0.11.1 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce diff --git a/deployment/go.sum b/deployment/go.sum index 3c4ea6b3cd3..ca7a8ed6530 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1387,8 +1387,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317175207-e9ff github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317175207-e9ff89561326/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.1 h1:JVTnqoQjdLDmQQXNgssmzEQnJK0gQ/0427LqS4UDuqE= -github.com/smartcontractkit/chainlink-common v0.11.1/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c h1:u29Hem3LUYpWtamoXy4Xib4xUe1ao1AcL4lvcgZYnkE= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/go.mod b/go.mod index f1e6edc2376..a67ab81bc9a 100644 --- a/go.mod +++ b/go.mod @@ -85,7 +85,7 @@ require ( github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260224214816-cb23ec38649f github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5 github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 - github.com/smartcontractkit/chainlink-common v0.11.1 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 github.com/smartcontractkit/chainlink-data-streams v0.1.13 diff --git a/go.sum b/go.sum index 75680021f9b..453bfc4f1b9 100644 --- a/go.sum +++ b/go.sum @@ -1235,8 +1235,8 @@ github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5/go.mod h1:xtZNi6pOKdC3sLvokDvXOhgHzT+cyBqH/gWwvxTxqrg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.1 h1:JVTnqoQjdLDmQQXNgssmzEQnJK0gQ/0427LqS4UDuqE= -github.com/smartcontractkit/chainlink-common v0.11.1/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c h1:u29Hem3LUYpWtamoXy4Xib4xUe1ao1AcL4lvcgZYnkE= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 5c5d6fcaf92..282564e95de 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -47,7 +47,7 @@ require ( github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.11.1 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 45d231fe0ad..6915b690c2a 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1626,8 +1626,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.1 h1:JVTnqoQjdLDmQQXNgssmzEQnJK0gQ/0427LqS4UDuqE= -github.com/smartcontractkit/chainlink-common v0.11.1/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c h1:u29Hem3LUYpWtamoXy4Xib4xUe1ao1AcL4lvcgZYnkE= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index e57589c5b4a..799dc4df880 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -27,7 +27,7 @@ require ( github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.11.1 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.3 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 8f5c83c1d9c..7e71dc6c4ac 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1596,8 +1596,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.1 h1:JVTnqoQjdLDmQQXNgssmzEQnJK0gQ/0427LqS4UDuqE= -github.com/smartcontractkit/chainlink-common v0.11.1/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c h1:u29Hem3LUYpWtamoXy4Xib4xUe1ao1AcL4lvcgZYnkE= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/system-tests/lib/go.mod b/system-tests/lib/go.mod index 785a6244fbd..d163d11e53b 100644 --- a/system-tests/lib/go.mod +++ b/system-tests/lib/go.mod @@ -35,7 +35,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.97 github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.11.1 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce diff --git a/system-tests/lib/go.sum b/system-tests/lib/go.sum index 5184e676d3b..8d896721b3c 100644 --- a/system-tests/lib/go.sum +++ b/system-tests/lib/go.sum @@ -1601,8 +1601,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.1 h1:JVTnqoQjdLDmQQXNgssmzEQnJK0gQ/0427LqS4UDuqE= -github.com/smartcontractkit/chainlink-common v0.11.1/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c h1:u29Hem3LUYpWtamoXy4Xib4xUe1ao1AcL4lvcgZYnkE= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/system-tests/tests/go.mod b/system-tests/tests/go.mod index 32e1227e802..6b52902a178 100644 --- a/system-tests/tests/go.mod +++ b/system-tests/tests/go.mod @@ -62,13 +62,13 @@ require ( github.com/rs/zerolog v1.34.0 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chain-selectors v1.0.97 - github.com/smartcontractkit/chainlink-common v0.11.1 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-data-streams v0.1.13 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm/contracts/cre/gobindings v0.0.0-20260107191744-4b93f62cffe3 github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260119171452-39c98c3b33cd - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4 github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 github.com/smartcontractkit/chainlink-protos/ring/go v0.0.0-20260128151123-605e9540b706 github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260217043601-5cc966896c4f diff --git a/system-tests/tests/go.sum b/system-tests/tests/go.sum index 67c3905aae1..02d8e9b16e7 100644 --- a/system-tests/tests/go.sum +++ b/system-tests/tests/go.sum @@ -1785,8 +1785,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.1 h1:JVTnqoQjdLDmQQXNgssmzEQnJK0gQ/0427LqS4UDuqE= -github.com/smartcontractkit/chainlink-common v0.11.1/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c h1:u29Hem3LUYpWtamoXy4Xib4xUe1ao1AcL4lvcgZYnkE= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20251211140724-319861e514c4 h1:NOUsjsMzNecbjiPWUQGlRSRAutEvCFrqqyETDJeh5q4= @@ -1823,8 +1823,8 @@ github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0. github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 h1:fkS5FJpSozwxL2FA6OJDi7az2DrtMNiK1X5DWuHDyfA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4 h1:kqdSsgt2OzJnAk0io8GsA2lJE5hKlLM2EY4uy+R6H9Y= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 h1:q+VDPcxWrj5k9QizSYfUOSMnDH3Sd5HvbPguZOgfXTY= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= @@ -1881,8 +1881,8 @@ github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.202602181 github.com/smartcontractkit/chainlink-tron/relayer/gotron-sdk v0.0.5-0.20260218133534-cbd44da2856b/go.mod h1:ea1LESxlSSOgc2zZBqf1RTkXTMthHaspdqUHd7W4lF0= github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/evmread v0.0.0-20250917232237-c4ecf802c6f8 h1:ZhpUCMDFATsyS1B+6YaAxWYfh/WsVx9WWtYSOkl5V0g= github.com/smartcontractkit/chainlink/system-tests/tests/smoke/cre/evmread v0.0.0-20250917232237-c4ecf802c6f8/go.mod h1:96T5PZe9IRPcuMTnS2I2VGAtyDdkL5U9aWUykLtAYb8= -github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373 h1:sY79Ue8wkzPbpo4tFvvGSQiTMiqBvgyL0FBJV2UIhWI= -github.com/smartcontractkit/cre-sdk-go v1.6.1-0.20260318054402-f2512ecc8373/go.mod h1:MP93PP7lxaFyW+RRNYcEdXHm/gJM/HPqRPUPOAfBH4w= +github.com/smartcontractkit/cre-sdk-go v1.5.0 h1:kepW3QDKARrOOHjXwWAZ9j5KLk6bxLzvi6OMrLsFwVo= +github.com/smartcontractkit/cre-sdk-go v1.5.0/go.mod h1:yYrQFz1UH7hhRbPO0q4fgo1tfsJNd4yXnI3oCZE0RzM= github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad h1:lgHxTHuzJIF3Vj6LSMOnjhqKgRqYW+0MV2SExtCYL1Q= github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad/go.mod h1:T4zH9R8R8lVWKfU7tUvYz2o2jMv1OpGCdpY2j2QZXzU= github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 h1:12ijqMM9tvYVEm+nR826WsrNi6zCKpwBhuApq127wHs= From 2e4c5528b327d8ec9cdf19e928cbb12d9764c8f0 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 26 Mar 2026 13:27:43 +0000 Subject: [PATCH 26/34] cre: wire aptos OCR config in local CRE --- system-tests/lib/cre/features/aptos/aptos.go | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/system-tests/lib/cre/features/aptos/aptos.go b/system-tests/lib/cre/features/aptos/aptos.go index 6f8322b69f7..fab553533f9 100644 --- a/system-tests/lib/cre/features/aptos/aptos.go +++ b/system-tests/lib/cre/features/aptos/aptos.go @@ -31,6 +31,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment/cre/jobs" crejobops "github.com/smartcontractkit/chainlink/deployment/cre/jobs/operations" jobtypes "github.com/smartcontractkit/chainlink/deployment/cre/jobs/types" + "github.com/smartcontractkit/chainlink/deployment/cre/ocr3" "github.com/smartcontractkit/chainlink/deployment/cre/pkg/offchain" aptoschangeset "github.com/smartcontractkit/chainlink/deployment/data-feeds/changeset/aptos" keystone_changeset "github.com/smartcontractkit/chainlink/deployment/keystone/changeset" @@ -125,6 +126,8 @@ func (a *Aptos) PreEnvStartup( } caps := make([]keystone_changeset.DONCapabilityWithConfig, 0, len(enabledChainIDs)) + capabilityToOCR3Config := make(map[string]*ocr3.OracleConfig, len(enabledChainIDs)) + capabilityLabels := make([]string, 0, len(enabledChainIDs)) for _, chainID := range enabledChainIDs { aptosChain, err := findAptosChainByChainID(creEnv.Blockchains, chainID) if err != nil { @@ -146,12 +149,20 @@ func (a *Aptos) PreEnvStartup( Version: capabilityVersion, CapabilityType: 1, }, - Config: capConfig, + Config: capConfig, + UseCapRegOCRConfig: true, }) + capabilityLabels = append(capabilityLabels, labelledName) + capabilityToOCR3Config[labelledName] = crecontracts.DefaultChainCapabilityOCR3Config() } return &cre.PreEnvStartupOutput{ DONCapabilityWithConfig: caps, + CapabilityToOCR3Config: capabilityToOCR3Config, + CapabilityToExtraSignerFamilies: cre.CapabilityToExtraSignerFamilies( + cre.OCRExtraSignerFamilies(creEnv.Blockchains), + capabilityLabels..., + ), }, nil } From 58ac80d3b5b8a0aae2c9763e159f42538127acb8 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 26 Mar 2026 15:03:19 +0000 Subject: [PATCH 27/34] deps: update chainlink-common aptos compat fix --- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 ++-- deployment/go.mod | 2 +- deployment/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- system-tests/lib/go.mod | 2 +- system-tests/lib/go.sum | 4 ++-- system-tests/tests/go.mod | 2 +- system-tests/tests/go.sum | 4 ++-- 14 files changed, 21 insertions(+), 21 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index b96ba5b0d4b..6bea98808ab 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -46,7 +46,7 @@ require ( github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-data-streams v0.1.13 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 1ec80887832..8e938a8fc3a 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1634,8 +1634,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c h1:u29Hem3LUYpWtamoXy4Xib4xUe1ao1AcL4lvcgZYnkE= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 h1:C8VTUde44PBpB8IL+UZ05nuRUA4lTV4R91Uc8NweKNI= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20251211140724-319861e514c4 h1:NOUsjsMzNecbjiPWUQGlRSRAutEvCFrqqyETDJeh5q4= diff --git a/deployment/go.mod b/deployment/go.mod index 88e94925131..d93c9b6e90c 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -44,7 +44,7 @@ require ( github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260224214816-cb23ec38649f github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317175207-e9ff89561326 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce diff --git a/deployment/go.sum b/deployment/go.sum index ca7a8ed6530..d26db1b29b3 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1387,8 +1387,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317175207-e9ff github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317175207-e9ff89561326/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c h1:u29Hem3LUYpWtamoXy4Xib4xUe1ao1AcL4lvcgZYnkE= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 h1:C8VTUde44PBpB8IL+UZ05nuRUA4lTV4R91Uc8NweKNI= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/go.mod b/go.mod index a67ab81bc9a..ce69dcb90ad 100644 --- a/go.mod +++ b/go.mod @@ -85,7 +85,7 @@ require ( github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260224214816-cb23ec38649f github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5 github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 github.com/smartcontractkit/chainlink-data-streams v0.1.13 diff --git a/go.sum b/go.sum index 453bfc4f1b9..252a79b629c 100644 --- a/go.sum +++ b/go.sum @@ -1235,8 +1235,8 @@ github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5/go.mod h1:xtZNi6pOKdC3sLvokDvXOhgHzT+cyBqH/gWwvxTxqrg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c h1:u29Hem3LUYpWtamoXy4Xib4xUe1ao1AcL4lvcgZYnkE= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 h1:C8VTUde44PBpB8IL+UZ05nuRUA4lTV4R91Uc8NweKNI= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 282564e95de..f9cd368ac7b 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -47,7 +47,7 @@ require ( github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 6915b690c2a..add9be2e3da 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1626,8 +1626,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c h1:u29Hem3LUYpWtamoXy4Xib4xUe1ao1AcL4lvcgZYnkE= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 h1:C8VTUde44PBpB8IL+UZ05nuRUA4lTV4R91Uc8NweKNI= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 799dc4df880..e8e205933ee 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -27,7 +27,7 @@ require ( github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.3 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 7e71dc6c4ac..35c3d718d26 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1596,8 +1596,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c h1:u29Hem3LUYpWtamoXy4Xib4xUe1ao1AcL4lvcgZYnkE= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 h1:C8VTUde44PBpB8IL+UZ05nuRUA4lTV4R91Uc8NweKNI= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/system-tests/lib/go.mod b/system-tests/lib/go.mod index d163d11e53b..86ce4d2467d 100644 --- a/system-tests/lib/go.mod +++ b/system-tests/lib/go.mod @@ -35,7 +35,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.97 github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce diff --git a/system-tests/lib/go.sum b/system-tests/lib/go.sum index 8d896721b3c..25450b0f88c 100644 --- a/system-tests/lib/go.sum +++ b/system-tests/lib/go.sum @@ -1601,8 +1601,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c h1:u29Hem3LUYpWtamoXy4Xib4xUe1ao1AcL4lvcgZYnkE= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 h1:C8VTUde44PBpB8IL+UZ05nuRUA4lTV4R91Uc8NweKNI= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/system-tests/tests/go.mod b/system-tests/tests/go.mod index 6b52902a178..01597c78970 100644 --- a/system-tests/tests/go.mod +++ b/system-tests/tests/go.mod @@ -62,7 +62,7 @@ require ( github.com/rs/zerolog v1.34.0 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chain-selectors v1.0.97 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-data-streams v0.1.13 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 diff --git a/system-tests/tests/go.sum b/system-tests/tests/go.sum index 02d8e9b16e7..9d55f0eeb45 100644 --- a/system-tests/tests/go.sum +++ b/system-tests/tests/go.sum @@ -1785,8 +1785,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c h1:u29Hem3LUYpWtamoXy4Xib4xUe1ao1AcL4lvcgZYnkE= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326110305-5de11bc1b49c/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 h1:C8VTUde44PBpB8IL+UZ05nuRUA4lTV4R91Uc8NweKNI= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20251211140724-319861e514c4 h1:NOUsjsMzNecbjiPWUQGlRSRAutEvCFrqqyETDJeh5q4= From 44225e31ba4d454e0002ae9dda66f414aca0d91b Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 26 Mar 2026 18:14:12 +0000 Subject: [PATCH 28/34] cre: use capreg aptos config with cl-common fix --- core/scripts/go.mod | 4 ++-- core/scripts/go.sum | 8 ++++---- deployment/go.mod | 4 ++-- deployment/go.sum | 8 ++++---- go.mod | 4 ++-- go.sum | 8 ++++---- integration-tests/go.mod | 4 ++-- integration-tests/go.sum | 8 ++++---- integration-tests/load/go.mod | 4 ++-- integration-tests/load/go.sum | 8 ++++---- system-tests/lib/go.mod | 4 ++-- system-tests/lib/go.sum | 8 ++++---- system-tests/tests/go.mod | 4 ++-- system-tests/tests/go.sum | 8 ++++---- 14 files changed, 42 insertions(+), 42 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 6bea98808ab..b201c324b00 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -46,13 +46,13 @@ require ( github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-data-streams v0.1.13 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260119171452-39c98c3b33cd - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.5 github.com/smartcontractkit/chainlink-testing-framework/framework/components/dockercompose v0.1.20 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 8e938a8fc3a..58909fc615c 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1634,8 +1634,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 h1:C8VTUde44PBpB8IL+UZ05nuRUA4lTV4R91Uc8NweKNI= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f h1:Nrvh1Oy4kNlDND9tGhQ7Ndi7uXxLNU4OOoCwOYpOUWA= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20251211140724-319861e514c4 h1:NOUsjsMzNecbjiPWUQGlRSRAutEvCFrqqyETDJeh5q4= @@ -1672,8 +1672,8 @@ github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0. github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 h1:fkS5FJpSozwxL2FA6OJDi7az2DrtMNiK1X5DWuHDyfA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f h1:8p3vE987AHM3Of1JvnNJXNE/AtWtfNvJhk3TeeAG3Qw= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 h1:q+VDPcxWrj5k9QizSYfUOSMnDH3Sd5HvbPguZOgfXTY= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= diff --git a/deployment/go.mod b/deployment/go.mod index d93c9b6e90c..6fdefa7f038 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -44,14 +44,14 @@ require ( github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260224214816-cb23ec38649f github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317175207-e9ff89561326 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce github.com/smartcontractkit/chainlink-evm/contracts/cre/gobindings v0.0.0-20260107191744-4b93f62cffe3 github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260119171452-39c98c3b33cd github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20251021173435-e86785845942 - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 github.com/smartcontractkit/chainlink-solana v1.1.2-0.20260320011913-f2205f8506c7 diff --git a/deployment/go.sum b/deployment/go.sum index d26db1b29b3..785e0a5ce3b 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1387,8 +1387,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317175207-e9ff github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317175207-e9ff89561326/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 h1:C8VTUde44PBpB8IL+UZ05nuRUA4lTV4R91Uc8NweKNI= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f h1:Nrvh1Oy4kNlDND9tGhQ7Ndi7uXxLNU4OOoCwOYpOUWA= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= @@ -1425,8 +1425,8 @@ github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0. github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 h1:fkS5FJpSozwxL2FA6OJDi7az2DrtMNiK1X5DWuHDyfA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f h1:8p3vE987AHM3Of1JvnNJXNE/AtWtfNvJhk3TeeAG3Qw= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 h1:q+VDPcxWrj5k9QizSYfUOSMnDH3Sd5HvbPguZOgfXTY= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= diff --git a/go.mod b/go.mod index ce69dcb90ad..b10bd1cb7b6 100644 --- a/go.mod +++ b/go.mod @@ -85,7 +85,7 @@ require ( github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260224214816-cb23ec38649f github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5 github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 github.com/smartcontractkit/chainlink-data-streams v0.1.13 @@ -97,7 +97,7 @@ require ( github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20260317132927-e8bc2c7b01f1 github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20251021173435-e86785845942 github.com/smartcontractkit/chainlink-protos/billing/go v0.0.0-20251024234028-0988426d98f4 - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260319180422-b5808c964785 github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 diff --git a/go.sum b/go.sum index 252a79b629c..bfdbd3ac785 100644 --- a/go.sum +++ b/go.sum @@ -1235,8 +1235,8 @@ github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5/go.mod h1:xtZNi6pOKdC3sLvokDvXOhgHzT+cyBqH/gWwvxTxqrg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 h1:C8VTUde44PBpB8IL+UZ05nuRUA4lTV4R91Uc8NweKNI= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f h1:Nrvh1Oy4kNlDND9tGhQ7Ndi7uXxLNU4OOoCwOYpOUWA= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= @@ -1271,8 +1271,8 @@ github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0. github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 h1:fkS5FJpSozwxL2FA6OJDi7az2DrtMNiK1X5DWuHDyfA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f h1:8p3vE987AHM3Of1JvnNJXNE/AtWtfNvJhk3TeeAG3Qw= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b/go.mod h1:qSTSwX3cBP3FKQwQacdjArqv0g6QnukjV4XuzO6UyoY= github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260319180422-b5808c964785 h1:oli+2uLU6jcrJGCuYFqk3475hiwL17SWlITWLv+tx/w= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index f9cd368ac7b..36d95958559 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -47,7 +47,7 @@ require ( github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce @@ -513,7 +513,7 @@ require ( github.com/smartcontractkit/chainlink-protos/chainlink-ccv/heartbeat v0.0.0-20260115142640-f6b99095c12e // indirect github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d // indirect github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d // indirect - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 // indirect + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f // indirect github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260319180422-b5808c964785 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.10.0 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index add9be2e3da..4e83549d325 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1626,8 +1626,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 h1:C8VTUde44PBpB8IL+UZ05nuRUA4lTV4R91Uc8NweKNI= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f h1:Nrvh1Oy4kNlDND9tGhQ7Ndi7uXxLNU4OOoCwOYpOUWA= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= @@ -1664,8 +1664,8 @@ github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0. github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 h1:fkS5FJpSozwxL2FA6OJDi7az2DrtMNiK1X5DWuHDyfA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f h1:8p3vE987AHM3Of1JvnNJXNE/AtWtfNvJhk3TeeAG3Qw= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 h1:q+VDPcxWrj5k9QizSYfUOSMnDH3Sd5HvbPguZOgfXTY= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index e8e205933ee..d7b77909199 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -27,7 +27,7 @@ require ( github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.3 @@ -490,7 +490,7 @@ require ( github.com/smartcontractkit/chainlink-protos/chainlink-ccv/heartbeat v0.0.0-20260115142640-f6b99095c12e // indirect github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d // indirect github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d // indirect - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 // indirect + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f // indirect github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 // indirect github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b // indirect github.com/smartcontractkit/chainlink-protos/node-platform v0.0.0-20260319180422-b5808c964785 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 35c3d718d26..8f8747ce3df 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1596,8 +1596,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 h1:C8VTUde44PBpB8IL+UZ05nuRUA4lTV4R91Uc8NweKNI= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f h1:Nrvh1Oy4kNlDND9tGhQ7Ndi7uXxLNU4OOoCwOYpOUWA= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= @@ -1634,8 +1634,8 @@ github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0. github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 h1:fkS5FJpSozwxL2FA6OJDi7az2DrtMNiK1X5DWuHDyfA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f h1:8p3vE987AHM3Of1JvnNJXNE/AtWtfNvJhk3TeeAG3Qw= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 h1:q+VDPcxWrj5k9QizSYfUOSMnDH3Sd5HvbPguZOgfXTY= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= diff --git a/system-tests/lib/go.mod b/system-tests/lib/go.mod index 86ce4d2467d..b4dd4aa25a5 100644 --- a/system-tests/lib/go.mod +++ b/system-tests/lib/go.mod @@ -35,12 +35,12 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.97 github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260119171452-39c98c3b33cd - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260217043601-5cc966896c4f github.com/smartcontractkit/chainlink-solana v1.1.2-0.20260320011913-f2205f8506c7 diff --git a/system-tests/lib/go.sum b/system-tests/lib/go.sum index 25450b0f88c..13442edb826 100644 --- a/system-tests/lib/go.sum +++ b/system-tests/lib/go.sum @@ -1601,8 +1601,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 h1:C8VTUde44PBpB8IL+UZ05nuRUA4lTV4R91Uc8NweKNI= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f h1:Nrvh1Oy4kNlDND9tGhQ7Ndi7uXxLNU4OOoCwOYpOUWA= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= @@ -1639,8 +1639,8 @@ github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0. github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4 h1:fkS5FJpSozwxL2FA6OJDi7az2DrtMNiK1X5DWuHDyfA= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260320153346-314ec8dbe5a4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f h1:8p3vE987AHM3Of1JvnNJXNE/AtWtfNvJhk3TeeAG3Qw= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 h1:q+VDPcxWrj5k9QizSYfUOSMnDH3Sd5HvbPguZOgfXTY= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= diff --git a/system-tests/tests/go.mod b/system-tests/tests/go.mod index 01597c78970..7fb3b2b9dbd 100644 --- a/system-tests/tests/go.mod +++ b/system-tests/tests/go.mod @@ -62,13 +62,13 @@ require ( github.com/rs/zerolog v1.34.0 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chain-selectors v1.0.97 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-data-streams v0.1.13 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm/contracts/cre/gobindings v0.0.0-20260107191744-4b93f62cffe3 github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260119171452-39c98c3b33cd - github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4 + github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 github.com/smartcontractkit/chainlink-protos/ring/go v0.0.0-20260128151123-605e9540b706 github.com/smartcontractkit/chainlink-protos/workflows/go v0.0.0-20260217043601-5cc966896c4f diff --git a/system-tests/tests/go.sum b/system-tests/tests/go.sum index 9d55f0eeb45..3fe9252bb3d 100644 --- a/system-tests/tests/go.sum +++ b/system-tests/tests/go.sum @@ -1785,8 +1785,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211 h1:C8VTUde44PBpB8IL+UZ05nuRUA4lTV4R91Uc8NweKNI= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326140735-63ba77cad211/go.mod h1:9W8E7tfchAsrSNHdMM1mzLmle+bL1P8Ou0I4LG1qNxw= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f h1:Nrvh1Oy4kNlDND9tGhQ7Ndi7uXxLNU4OOoCwOYpOUWA= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20251211140724-319861e514c4 h1:NOUsjsMzNecbjiPWUQGlRSRAutEvCFrqqyETDJeh5q4= @@ -1823,8 +1823,8 @@ github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0. github.com/smartcontractkit/chainlink-protos/chainlink-ccv/message-discovery v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:ATjAPIVJibHRcIfiG47rEQkUIOoYa6KDvWj3zwCAw6g= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d h1:AJy55QJ/pBhXkZjc7N+ATnWfxrcjq9BI9DmdtdjwDUQ= github.com/smartcontractkit/chainlink-protos/chainlink-ccv/verifier v0.0.0-20251211142334-5c3421fe2c8d/go.mod h1:5JdppgngCOUS76p61zCinSCgOhPeYQ+OcDUuome5THQ= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4 h1:kqdSsgt2OzJnAk0io8GsA2lJE5hKlLM2EY4uy+R6H9Y= -github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260325181729-0cac87f98cd4/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f h1:8p3vE987AHM3Of1JvnNJXNE/AtWtfNvJhk3TeeAG3Qw= +github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f/go.mod h1:Jqt53s27Tr0jDl8mdBXg1xhu6F8Fci8JOuq43tgHOM8= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0 h1:q+VDPcxWrj5k9QizSYfUOSMnDH3Sd5HvbPguZOgfXTY= github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/linking-service/go v0.0.0-20251002192024-d2ad9222409b h1:QuI6SmQFK/zyUlVWEf0GMkiUYBPY4lssn26nKSd/bOM= From 670af6dcc3f9be3a86ca5e2048152f12cffc2d2e Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 26 Mar 2026 18:16:38 +0000 Subject: [PATCH 29/34] cre: disable capreg OCR config for local aptos --- system-tests/lib/cre/features/aptos/aptos.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system-tests/lib/cre/features/aptos/aptos.go b/system-tests/lib/cre/features/aptos/aptos.go index fab553533f9..e3416b21179 100644 --- a/system-tests/lib/cre/features/aptos/aptos.go +++ b/system-tests/lib/cre/features/aptos/aptos.go @@ -150,7 +150,7 @@ func (a *Aptos) PreEnvStartup( CapabilityType: 1, }, Config: capConfig, - UseCapRegOCRConfig: true, + UseCapRegOCRConfig: false, }) capabilityLabels = append(capabilityLabels, labelledName) capabilityToOCR3Config[labelledName] = crecontracts.DefaultChainCapabilityOCR3Config() From d06a6809a46acf1ffbb077ff05f01afbd4f1951c Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 26 Mar 2026 18:28:06 +0000 Subject: [PATCH 30/34] deps: drop chainlink-common aptos compat pin --- core/scripts/go.mod | 10 ++++------ core/scripts/go.sum | 4 ++-- deployment/go.mod | 2 +- deployment/go.sum | 4 ++-- go.mod | 2 +- go.sum | 4 ++-- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 ++-- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 ++-- system-tests/lib/go.mod | 2 +- system-tests/lib/go.sum | 4 ++-- system-tests/tests/go.mod | 2 +- system-tests/tests/go.sum | 4 ++-- 14 files changed, 24 insertions(+), 26 deletions(-) diff --git a/core/scripts/go.mod b/core/scripts/go.mod index b201c324b00..c3dd08f3e29 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -15,10 +15,7 @@ replace github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examp // Using a separate `require` here to avoid surrounding line changes // creating potential merge conflicts. -require ( - github.com/smartcontractkit/chainlink/deployment v0.0.0-20251021194914-c0e3fec1a97c - github.com/smartcontractkit/chainlink/v2 v2.32.0 -) +require github.com/smartcontractkit/chainlink/v2 v2.32.0 require ( github.com/Masterminds/semver/v3 v3.4.0 @@ -46,7 +43,7 @@ require ( github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421 github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-data-streams v0.1.13 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 @@ -60,7 +57,8 @@ require ( github.com/smartcontractkit/chainlink-testing-framework/seth v1.51.5 github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/cron-based v0.0.0-20251020210257-0a6ec41648b4 github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v1/proof-of-reserve/web-trigger-based v0.0.0-20251020210257-0a6ec41648b4 - github.com/smartcontractkit/chainlink/system-tests/lib v0.0.0-20251020210257-0a6ec41648b4 + github.com/smartcontractkit/chainlink/deployment v0.0.0-20251021194914-c0e3fec1a97c + github.com/smartcontractkit/chainlink/system-tests/lib v0.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20260304194147-a03701e2c02e github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 58909fc615c..ce3c06560f2 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1634,8 +1634,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f h1:Nrvh1Oy4kNlDND9tGhQ7Ndi7uXxLNU4OOoCwOYpOUWA= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421 h1:nh92CD2TZTtziEWu2reMDgEx1Zu0TGTkQcjQ3IE5bYM= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20251211140724-319861e514c4 h1:NOUsjsMzNecbjiPWUQGlRSRAutEvCFrqqyETDJeh5q4= diff --git a/deployment/go.mod b/deployment/go.mod index 6fdefa7f038..6c22821843d 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -44,7 +44,7 @@ require ( github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260224214816-cb23ec38649f github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317175207-e9ff89561326 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421 github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce diff --git a/deployment/go.sum b/deployment/go.sum index 785e0a5ce3b..a7eb4dbac5a 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1387,8 +1387,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317175207-e9ff github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317175207-e9ff89561326/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f h1:Nrvh1Oy4kNlDND9tGhQ7Ndi7uXxLNU4OOoCwOYpOUWA= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421 h1:nh92CD2TZTtziEWu2reMDgEx1Zu0TGTkQcjQ3IE5bYM= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/go.mod b/go.mod index b10bd1cb7b6..7cd8e44e579 100644 --- a/go.mod +++ b/go.mod @@ -85,7 +85,7 @@ require ( github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260224214816-cb23ec38649f github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5 github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421 github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 github.com/smartcontractkit/chainlink-data-streams v0.1.13 diff --git a/go.sum b/go.sum index bfdbd3ac785..af6f7b53ad5 100644 --- a/go.sum +++ b/go.sum @@ -1235,8 +1235,8 @@ github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20250912190424-fd2e35d7deb5/go.mod h1:xtZNi6pOKdC3sLvokDvXOhgHzT+cyBqH/gWwvxTxqrg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f h1:Nrvh1Oy4kNlDND9tGhQ7Ndi7uXxLNU4OOoCwOYpOUWA= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421 h1:nh92CD2TZTtziEWu2reMDgEx1Zu0TGTkQcjQ3IE5bYM= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 36d95958559..71aabca52a4 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -47,7 +47,7 @@ require ( github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421 github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 4e83549d325..78e768254f2 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1626,8 +1626,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f h1:Nrvh1Oy4kNlDND9tGhQ7Ndi7uXxLNU4OOoCwOYpOUWA= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421 h1:nh92CD2TZTtziEWu2reMDgEx1Zu0TGTkQcjQ3IE5bYM= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index d7b77909199..94094412ad8 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -27,7 +27,7 @@ require ( github.com/smartcontractkit/chainlink-ccip v0.1.1-solana.0.20260317185256-d5f7db87ae70 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.3 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 8f8747ce3df..6521242f3c6 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1596,8 +1596,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f h1:Nrvh1Oy4kNlDND9tGhQ7Ndi7uXxLNU4OOoCwOYpOUWA= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421 h1:nh92CD2TZTtziEWu2reMDgEx1Zu0TGTkQcjQ3IE5bYM= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/system-tests/lib/go.mod b/system-tests/lib/go.mod index b4dd4aa25a5..2801ddb1e5d 100644 --- a/system-tests/lib/go.mod +++ b/system-tests/lib/go.mod @@ -35,7 +35,7 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.97 github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421 github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 github.com/smartcontractkit/chainlink-evm v0.3.4-0.20260320152158-2191d797b5ce diff --git a/system-tests/lib/go.sum b/system-tests/lib/go.sum index 13442edb826..60772566c44 100644 --- a/system-tests/lib/go.sum +++ b/system-tests/lib/go.sum @@ -1601,8 +1601,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f h1:Nrvh1Oy4kNlDND9tGhQ7Ndi7uXxLNU4OOoCwOYpOUWA= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421 h1:nh92CD2TZTtziEWu2reMDgEx1Zu0TGTkQcjQ3IE5bYM= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.10 h1:FJAFgXS9oqASnkS03RE1HQwYQQxrO4l46O5JSzxqLgg= diff --git a/system-tests/tests/go.mod b/system-tests/tests/go.mod index 7fb3b2b9dbd..6126b410457 100644 --- a/system-tests/tests/go.mod +++ b/system-tests/tests/go.mod @@ -62,7 +62,7 @@ require ( github.com/rs/zerolog v1.34.0 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chain-selectors v1.0.97 - github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f + github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421 github.com/smartcontractkit/chainlink-common/keystore v1.0.2 github.com/smartcontractkit/chainlink-data-streams v0.1.13 github.com/smartcontractkit/chainlink-deployments-framework v0.86.3 diff --git a/system-tests/tests/go.sum b/system-tests/tests/go.sum index 3fe9252bb3d..19fa5f39142 100644 --- a/system-tests/tests/go.sum +++ b/system-tests/tests/go.sum @@ -1785,8 +1785,8 @@ github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7 github.com/smartcontractkit/chainlink-ccip/deployment v0.0.0-20260317185256-d5f7db87ae70/go.mod h1:P0/tjeeIIxfsBupk5MneRjq5uI9mj+ZQpMpYnFla6WM= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2 h1:5HdH/A6yn8INZAltYDLb7UkUi5IKemhJzJkDW4Bgxyg= github.com/smartcontractkit/chainlink-ccv v0.0.0-20260324000441-d4cfddc9f7d2/go.mod h1:wDHq2E0KwUWG0lQ9f5frW1a7CKVW17MJLPuvKmtSRDg= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f h1:Nrvh1Oy4kNlDND9tGhQ7Ndi7uXxLNU4OOoCwOYpOUWA= -github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326164412-6378f013c66f/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421 h1:nh92CD2TZTtziEWu2reMDgEx1Zu0TGTkQcjQ3IE5bYM= +github.com/smartcontractkit/chainlink-common v0.11.2-0.20260326163134-c8e0d77df421/go.mod h1:6tlxlsiWypGdpaZI+Kz5gFm53gCAcU/pTU3PR9CiFB8= github.com/smartcontractkit/chainlink-common/keystore v1.0.2 h1:AWisx4JT3QV8tcgh6J5NCrex+wAgTYpWyHsyNPSXzsQ= github.com/smartcontractkit/chainlink-common/keystore v1.0.2/go.mod h1:rSkIHdomyak3YnUtXLenl6poIq8q0V3UZPiiyYqPdGA= github.com/smartcontractkit/chainlink-common/pkg/chipingress v0.0.11-0.20251211140724-319861e514c4 h1:NOUsjsMzNecbjiPWUQGlRSRAutEvCFrqqyETDJeh5q4= From de61415eac84db67ee3f0b276b717c1987603646 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Thu, 26 Mar 2026 21:45:21 +0000 Subject: [PATCH 31/34] plugins: repin aptos capability after common fix merge --- plugins/plugins.private.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/plugins.private.yaml b/plugins/plugins.private.yaml index 69a67c427e6..721da490e32 100644 --- a/plugins/plugins.private.yaml +++ b/plugins/plugins.private.yaml @@ -48,7 +48,7 @@ plugins: installPath: "." aptos: - moduleURI: "github.com/smartcontractkit/capabilities/chain_capabilities/aptos" - gitRef: "98d846140eb6620ae10d73e2489df4377cbddba1" + gitRef: "ebca0cad82543712816668e5c418e1df49ec0c88" installPath: "." mock: - moduleURI: "github.com/smartcontractkit/capabilities/mock" From b2bd6155fb7c60d840fa41597ba09cccc9ff1d8a Mon Sep 17 00:00:00 2001 From: cawthorne Date: Sat, 28 Mar 2026 12:04:04 +0000 Subject: [PATCH 32/34] cre: add aptos job template --- deployment/cre/jobs/aptos.go | 42 +++++++++ deployment/cre/jobs/propose_job_spec.go | 20 ++-- deployment/cre/jobs/propose_job_spec_test.go | 94 ++++++++++++++++--- .../cre/jobs/types/job_spec_template.go | 5 + .../cre/jobs/types/job_spec_template_test.go | 14 +++ 5 files changed, 156 insertions(+), 19 deletions(-) create mode 100644 deployment/cre/jobs/aptos.go diff --git a/deployment/cre/jobs/aptos.go b/deployment/cre/jobs/aptos.go new file mode 100644 index 00000000000..a9a06a4d01d --- /dev/null +++ b/deployment/cre/jobs/aptos.go @@ -0,0 +1,42 @@ +package jobs + +import ( + "errors" + "strings" + + "github.com/smartcontractkit/chainlink/deployment/cre/jobs/pkg" + job_types "github.com/smartcontractkit/chainlink/deployment/cre/jobs/types" + "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" +) + +func verifyAptosJobSpecInputs(inputs job_types.JobSpecInput) error { + scj := &pkg.StandardCapabilityJob{} + if err := inputs.UnmarshalTo(scj); err != nil { + return errors.New("failed to unmarshal job spec input to StandardCapabilityJob: " + err.Error()) + } + + if strings.TrimSpace(scj.Command) == "" { + return errors.New("command is required and must be a string") + } + + if strings.TrimSpace(scj.Config) == "" { + return errors.New("config is required and must be a string") + } + + if scj.ChainSelectorEVM == 0 { + return errors.New("chainSelectorEVM is required") + } + + if scj.ChainSelectorAptos == 0 { + return errors.New("chainSelectorAptos is required") + } + + if len(scj.BootstrapPeers) == 0 { + return errors.New("bootstrapPeers is required") + } + if _, err := ocrcommon.ParseBootstrapPeers(scj.BootstrapPeers); err != nil { + return errors.New("bootstrapPeers is invalid: " + err.Error()) + } + + return nil +} diff --git a/deployment/cre/jobs/propose_job_spec.go b/deployment/cre/jobs/propose_job_spec.go index c714f75ec18..3a80678fdae 100644 --- a/deployment/cre/jobs/propose_job_spec.go +++ b/deployment/cre/jobs/propose_job_spec.go @@ -62,9 +62,13 @@ func (u ProposeJobSpec) VerifyPreconditions(_ cldf.Environment, config ProposeJo if err := verifyEVMJobSpecInputs(config.Inputs); err != nil { return fmt.Errorf("invalid inputs for EVM job spec: %w", err) } + case job_types.Aptos: + if err := verifyAptosJobSpecInputs(config.Inputs); err != nil { + return fmt.Errorf("invalid inputs for Aptos job spec: %w", err) + } case job_types.Solana: if err := verifySolanaJobSpecInputs(config.Inputs); err != nil { - return fmt.Errorf("invalid inputs for EVM job spec: %w", err) + return fmt.Errorf("invalid inputs for Solana job spec: %w", err) } case job_types.Cron, job_types.BootstrapOCR3, job_types.OCR3, job_types.Gateway, job_types.HTTPTrigger, job_types.HTTPAction, job_types.ConfidentialHTTP, job_types.BootstrapVault, job_types.Consensus, job_types.WebAPITrigger, job_types.WebAPITarget, job_types.CustomCompute, job_types.LogEventTrigger, job_types.ReadContract: case job_types.CRESettings: @@ -90,12 +94,12 @@ func (u ProposeJobSpec) Apply(e cldf.Environment, input ProposeJobSpecInput) (cl var report operations.Report[any, any] switch input.Template { // This will hold all standard capabilities jobs as we add support for them. - case job_types.EVM, job_types.Cron, job_types.HTTPTrigger, job_types.HTTPAction, job_types.ConfidentialHTTP, job_types.Consensus, job_types.WebAPITrigger, job_types.WebAPITarget, job_types.CustomCompute, job_types.LogEventTrigger, job_types.ReadContract, job_types.Solana: + case job_types.EVM, job_types.Aptos, job_types.Cron, job_types.HTTPTrigger, job_types.HTTPAction, job_types.ConfidentialHTTP, job_types.Consensus, job_types.WebAPITrigger, job_types.WebAPITarget, job_types.CustomCompute, job_types.LogEventTrigger, job_types.ReadContract, job_types.Solana: job, err := input.Inputs.ToStandardCapabilityJob(input.JobName) if err != nil { return cldf.ChangesetOutput{}, fmt.Errorf("failed to convert inputs to standard capability job: %w", err) } - job.GenerateOracleFactory = requiresOracleFactory(input.Template, job) + job.GenerateOracleFactory = requiresOracleFactory(input.Template) r, rErr := operations.ExecuteSequence( e.OperationsBundle, @@ -329,12 +333,14 @@ func (u ProposeJobSpec) Apply(e cldf.Environment, input ProposeJobSpecInput) (cl }, nil } -func requiresOracleFactory(template job_types.JobSpecTemplate, job pkg.StandardCapabilityJob) bool { +func requiresOracleFactory(template job_types.JobSpecTemplate) bool { if template == job_types.Consensus { return true } - // Aptos ReadContract jobs need oracle-factory generation so we can add the - // Aptos OCR key bundle to the multi-chain signing strategy. - return template == job_types.ReadContract && job.ChainSelectorAptos != 0 + if template == job_types.Aptos { + return true + } + + return false } diff --git a/deployment/cre/jobs/propose_job_spec_test.go b/deployment/cre/jobs/propose_job_spec_test.go index ba5b2cff0bd..6086e29273e 100644 --- a/deployment/cre/jobs/propose_job_spec_test.go +++ b/deployment/cre/jobs/propose_job_spec_test.go @@ -440,6 +440,74 @@ func TestProposeJobSpec_VerifyPreconditions_EVM(t *testing.T) { } } +func TestProposeJobSpec_VerifyPreconditions_Aptos(t *testing.T) { + j := jobs.ProposeJobSpec{} + var env cldf.Environment + + base := jobs.ProposeJobSpecInput{ + Environment: "test", + Domain: "cre", + DONName: "test-don", + JobName: "aptos-test", + DONFilters: []offchain.TargetDONFilter{ + {Key: offchain.FilterKeyDONName, Value: "d"}, + {Key: "environment", Value: "e"}, + {Key: "product", Value: offchain.ProductLabel}, + }, + Template: job_types.Aptos, + } + + validAptosInputs := func() job_types.JobSpecInput { + return job_types.JobSpecInput{ + "command": "/usr/local/bin/aptos", + "config": `{"chainId":"4","network":"aptos","creForwarderAddress":"0x1111111111111111111111111111111111111111111111111111111111111111"}`, + "chainSelectorEVM": "3379446385462418246", + "chainSelectorAptos": "4457093679053095497", + "bootstrapPeers": []string{ + "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001", + }, + "useCapRegOCRConfig": true, + "capRegVersion": "2.0.0", + } + } + + t.Run("valid aptos spec passes", func(t *testing.T) { + in := base + in.Inputs = validAptosInputs() + require.NoError(t, j.VerifyPreconditions(env, in)) + }) + + type negCase struct { + name string + mutate func(job_types.JobSpecInput) + wantEnd string + } + + const prefix = "invalid inputs for Aptos job spec: " + + cases := []negCase{ + {"missing command", func(m job_types.JobSpecInput) { delete(m, "command") }, "command is required and must be a string"}, + {"missing config", func(m job_types.JobSpecInput) { delete(m, "config") }, "config is required and must be a string"}, + {"missing chainSelectorEVM", func(m job_types.JobSpecInput) { delete(m, "chainSelectorEVM") }, "chainSelectorEVM is required"}, + {"missing chainSelectorAptos", func(m job_types.JobSpecInput) { delete(m, "chainSelectorAptos") }, "chainSelectorAptos is required"}, + {"missing bootstrapPeers", func(m job_types.JobSpecInput) { delete(m, "bootstrapPeers") }, "bootstrapPeers is required"}, + {"invalid bootstrapPeers", func(m job_types.JobSpecInput) { m["bootstrapPeers"] = []string{"not-a-peer"} }, "bootstrapPeers is invalid"}, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + in := base + in.Inputs = validAptosInputs() + tc.mutate(in.Inputs) + + err := j.VerifyPreconditions(env, in) + require.Error(t, err) + assert.Contains(t, err.Error(), prefix) + assert.Contains(t, err.Error(), tc.wantEnd) + }) + } +} + func TestProposeJobSpec_Apply(t *testing.T) { testEnv := test.SetupEnvV2(t, false) env := testEnv.Env @@ -766,19 +834,20 @@ PerSenderBurst = 100 assert.Contains(t, req.Spec, `command = "/usr/bin/read-contract"`) assert.Contains(t, req.Spec, `config = """{"chainId":1337,"network":"evm"}"""`) assert.Contains(t, req.Spec, `externalJobID = "a-readcontract-job-id"`) + assert.NotContains(t, req.Spec, `[oracle_factory]`) } }) - t.Run("successful aptos readcontract job distribution includes oracle factory", func(t *testing.T) { + t.Run("successful aptos job distribution includes oracle factory", func(t *testing.T) { chainSelector := testEnv.RegistrySelector ds := datastore.NewMemoryDataStore() err := ds.Addresses().Add(datastore.AddressRef{ ChainSelector: chainSelector, - Type: datastore.ContractType(ocr3.OCR3Capability), - Version: semver.MustParse("1.0.0"), + Type: datastore.ContractType("CapabilitiesRegistry"), + Version: semver.MustParse("2.0.0"), Address: "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", - Qualifier: "ocr3-contract-qualifier", + Qualifier: "", }) require.NoError(t, err) @@ -787,19 +856,18 @@ PerSenderBurst = 100 input := jobs.ProposeJobSpecInput{ Environment: "test", Domain: "cre", - JobName: "aptos-readcontract-cap-job", + JobName: "aptos-cap-job", DONName: test.DONName, - Template: job_types.ReadContract, + Template: job_types.Aptos, DONFilters: []offchain.TargetDONFilter{ {Key: offchain.FilterKeyDONName, Value: test.DONName}, {Key: "environment", Value: "test"}, {Key: "product", Value: offchain.ProductLabel}, }, Inputs: job_types.JobSpecInput{ - "command": "/usr/bin/aptos", - "config": `{"chainId":"4","network":"aptos","creForwarderAddress":"0x1111111111111111111111111111111111111111111111111111111111111111"}`, - "contractQualifier": "ocr3-contract-qualifier", - "chainSelectorEVM": strconv.FormatUint(chainSelector, 10), + "command": "/usr/bin/aptos", + "config": `{"chainId":"4","network":"aptos","creForwarderAddress":"0x1111111111111111111111111111111111111111111111111111111111111111"}`, + "chainSelectorEVM": strconv.FormatUint(chainSelector, 10), "chainSelectorAptos": strconv.FormatUint( testEnv.AptosSelector, 10, @@ -807,6 +875,8 @@ PerSenderBurst = 100 "bootstrapPeers": []string{ "12D3KooWHfYFQ8hGttAYbMCevQVESEQhzJAqFZokMVtom8bNxwGq@127.0.0.1:5001", }, + "useCapRegOCRConfig": true, + "capRegVersion": "2.0.0", }, } @@ -818,12 +888,12 @@ PerSenderBurst = 100 require.NoError(t, err) filteredReqs := slices.DeleteFunc(reqs, func(s *job.ProposeJobRequest) bool { - return !strings.Contains(s.Spec, `name = "aptos-readcontract-cap-job"`) + return !strings.Contains(s.Spec, `name = "aptos-cap-job"`) }) assert.Len(t, filteredReqs, 4) for _, req := range filteredReqs { - assert.Contains(t, req.Spec, `name = "aptos-readcontract-cap-job"`) + assert.Contains(t, req.Spec, `name = "aptos-cap-job"`) assert.Contains(t, req.Spec, `command = "/usr/bin/aptos"`) assert.Contains(t, req.Spec, `[oracle_factory]`) assert.Contains(t, req.Spec, `enabled = true`) diff --git a/deployment/cre/jobs/types/job_spec_template.go b/deployment/cre/jobs/types/job_spec_template.go index d9a7d25e2ec..6d5e6ede7be 100644 --- a/deployment/cre/jobs/types/job_spec_template.go +++ b/deployment/cre/jobs/types/job_spec_template.go @@ -19,6 +19,7 @@ const ( HTTPAction ConfidentialHTTP EVM + Aptos Solana Gateway BootstrapVault @@ -48,6 +49,8 @@ func (jt JobSpecTemplate) String() string { return "confidential-http" case EVM: return "evm" + case Aptos: + return "aptos" case Solana: return "solana" case Gateway: @@ -92,6 +95,8 @@ func parseJobSpecTemplate(s string) (JobSpecTemplate, error) { return ConfidentialHTTP, nil case "evm": return EVM, nil + case "aptos": + return Aptos, nil case "solana": return Solana, nil case "gateway": diff --git a/deployment/cre/jobs/types/job_spec_template_test.go b/deployment/cre/jobs/types/job_spec_template_test.go index 3d9c8219e4e..0bcc2f1d181 100644 --- a/deployment/cre/jobs/types/job_spec_template_test.go +++ b/deployment/cre/jobs/types/job_spec_template_test.go @@ -19,6 +19,13 @@ func TestJobSpecTemplate_UnmarshalJSON(t *testing.T) { require.Equal(t, job_types.Cron, in.Template) }) + t.Run("aptos string", func(t *testing.T) { + var in jobs.ProposeJobSpecInput + js := `{"environment":"e","domain":"d","don_name":"don","don_filters":[],"job_name":"j","template":"aptos","inputs":{}}` + require.NoError(t, json.Unmarshal([]byte(js), &in)) + require.Equal(t, job_types.Aptos, in.Template) + }) + t.Run("invalid string", func(t *testing.T) { var in jobs.ProposeJobSpecInput js := `{"environment":"e","domain":"d","don_name":"don","don_filters":[],"job_name":"j","template":"nope","inputs":{}}` @@ -42,6 +49,13 @@ func TestJobSpecTemplate_UnmarshalYAML(t *testing.T) { require.Equal(t, job_types.Cron, in.Template) }) + t.Run("aptos string", func(t *testing.T) { + var in jobs.ProposeJobSpecInput + yml := "environment: e\ndomain: d\ndon_name: don\ndon_filters: []\njob_name: j\ntemplate: aptos\ninputs: {}\n" + require.NoError(t, yaml.Unmarshal([]byte(yml), &in)) + require.Equal(t, job_types.Aptos, in.Template) + }) + t.Run("invalid string", func(t *testing.T) { var in jobs.ProposeJobSpecInput yml := "environment: e\ndomain: d\ndon_name: don\ndon_filters: []\njob_name: j\ntemplate: nope\ninputs: {}\n" From 10449fd2778d53f24d5b00ef3c9a9a71c17ca5a0 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Sat, 28 Mar 2026 12:04:31 +0000 Subject: [PATCH 33/34] cre: wire local aptos OCR config --- deployment/cre/ocr3/config.go | 3 +- .../cre/ocr3/v2/changeset/configure_ocr3.go | 23 +++-- .../operations/contracts/configure_ocr3.go | 2 + plugins/plugins.private.yaml | 2 +- system-tests/lib/cre/features/aptos/aptos.go | 95 +++++++++++++------ .../lib/cre/features/aptos/aptos_test.go | 20 ++++ 6 files changed, 107 insertions(+), 38 deletions(-) diff --git a/deployment/cre/ocr3/config.go b/deployment/cre/ocr3/config.go index 1182e3a5ea0..e96c73b00cd 100644 --- a/deployment/cre/ocr3/config.go +++ b/deployment/cre/ocr3/config.go @@ -299,6 +299,7 @@ type ConfigureOCR3Config struct { DryRun bool ReportingPluginConfigOverride []byte + ExtraSignerFamilies []string UseMCMS bool Strategy strategies.TransactionStrategy @@ -327,7 +328,7 @@ func ConfigureOCR3ContractFromJD(env *cldf.Environment, cfg ConfigureOCR3Config) return nil, err } - config, err := GenerateOCR3ConfigFromNodes(*cfg.OCR3Config, nodes, cfg.ChainSel, env.OCRSecrets, cfg.ReportingPluginConfigOverride, nil) + config, err := GenerateOCR3ConfigFromNodes(*cfg.OCR3Config, nodes, cfg.ChainSel, env.OCRSecrets, cfg.ReportingPluginConfigOverride, cfg.ExtraSignerFamilies) if err != nil { return nil, err } diff --git a/deployment/cre/ocr3/v2/changeset/configure_ocr3.go b/deployment/cre/ocr3/v2/changeset/configure_ocr3.go index 7ecebe544c0..6971dfeb7bb 100644 --- a/deployment/cre/ocr3/v2/changeset/configure_ocr3.go +++ b/deployment/cre/ocr3/v2/changeset/configure_ocr3.go @@ -25,9 +25,10 @@ type ConfigureOCR3Input struct { ContractChainSelector uint64 `json:"contractChainSelector" yaml:"contractChainSelector"` ContractQualifier string `json:"contractQualifier" yaml:"contractQualifier"` - DON contracts.DonNodeSet `json:"don" yaml:"don"` - OracleConfig *ocr3.OracleConfig `json:"oracleConfig" yaml:"oracleConfig"` - DryRun bool `json:"dryRun" yaml:"dryRun"` + DON contracts.DonNodeSet `json:"don" yaml:"don"` + OracleConfig *ocr3.OracleConfig `json:"oracleConfig" yaml:"oracleConfig"` + DryRun bool `json:"dryRun" yaml:"dryRun"` + ExtraSignerFamilies []string `json:"extraSignerFamilies,omitempty" yaml:"extraSignerFamilies,omitempty"` MCMSConfig *crecontracts.MCMSConfig `json:"mcmsConfig" yaml:"mcmsConfig"` } @@ -50,6 +51,9 @@ func (l ConfigureOCR3) VerifyPreconditions(_ cldf.Environment, input ConfigureOC if input.OracleConfig == nil { return errors.New("oracle config is required") } + if err := ocr3.ValidateExtraSignerFamilies(input.ExtraSignerFamilies); err != nil { + return fmt.Errorf("invalid extra signer families: %w", err) + } return nil } @@ -93,12 +97,13 @@ func (l ConfigureOCR3) Apply(e cldf.Environment, input ConfigureOCR3Input) (cldf Env: &e, Strategy: strategy, }, contracts.ConfigureOCR3Input{ - ContractAddress: &contractAddr, - ChainSelector: input.ContractChainSelector, - DON: input.DON, - Config: input.OracleConfig, - DryRun: input.DryRun, - MCMSConfig: input.MCMSConfig, + ContractAddress: &contractAddr, + ChainSelector: input.ContractChainSelector, + DON: input.DON, + Config: input.OracleConfig, + DryRun: input.DryRun, + ExtraSignerFamilies: input.ExtraSignerFamilies, + MCMSConfig: input.MCMSConfig, }) if err != nil { return cldf.ChangesetOutput{}, fmt.Errorf("failed to configure OCR3 contract: %w", err) diff --git a/deployment/cre/ocr3/v2/changeset/operations/contracts/configure_ocr3.go b/deployment/cre/ocr3/v2/changeset/operations/contracts/configure_ocr3.go index ad59fc4f6d0..fd1b115bc18 100644 --- a/deployment/cre/ocr3/v2/changeset/operations/contracts/configure_ocr3.go +++ b/deployment/cre/ocr3/v2/changeset/operations/contracts/configure_ocr3.go @@ -35,6 +35,7 @@ type ConfigureOCR3Input struct { DryRun bool ReportingPluginConfigOverride []byte + ExtraSignerFamilies []string MCMSConfig *contracts.MCMSConfig } @@ -72,6 +73,7 @@ var ConfigureOCR3 = operations.NewOperation[ConfigureOCR3Input, ConfigureOCR3OpO OCR3Config: input.Config, Contract: contract.Contract, DryRun: input.DryRun, + ExtraSignerFamilies: input.ExtraSignerFamilies, UseMCMS: input.UseMCMS(), Strategy: deps.Strategy, ReportingPluginConfigOverride: input.ReportingPluginConfigOverride, diff --git a/plugins/plugins.private.yaml b/plugins/plugins.private.yaml index 721da490e32..0e635df31f8 100644 --- a/plugins/plugins.private.yaml +++ b/plugins/plugins.private.yaml @@ -48,7 +48,7 @@ plugins: installPath: "." aptos: - moduleURI: "github.com/smartcontractkit/capabilities/chain_capabilities/aptos" - gitRef: "ebca0cad82543712816668e5c418e1df49ec0c88" + gitRef: "a410cc7b314110c6793e80aa6cb3dcff1c44b881" installPath: "." mock: - moduleURI: "github.com/smartcontractkit/capabilities/mock" diff --git a/system-tests/lib/cre/features/aptos/aptos.go b/system-tests/lib/cre/features/aptos/aptos.go index e3416b21179..ab402c82c83 100644 --- a/system-tests/lib/cre/features/aptos/aptos.go +++ b/system-tests/lib/cre/features/aptos/aptos.go @@ -1,14 +1,13 @@ package aptos import ( - "bytes" "context" "encoding/hex" + "encoding/json" stderrors "errors" "fmt" "strconv" "strings" - "text/template" "time" "dario.cat/mergo" @@ -32,12 +31,13 @@ import ( crejobops "github.com/smartcontractkit/chainlink/deployment/cre/jobs/operations" jobtypes "github.com/smartcontractkit/chainlink/deployment/cre/jobs/types" "github.com/smartcontractkit/chainlink/deployment/cre/ocr3" + creocr3changeset "github.com/smartcontractkit/chainlink/deployment/cre/ocr3/v2/changeset" + creocr3contracts "github.com/smartcontractkit/chainlink/deployment/cre/ocr3/v2/changeset/operations/contracts" "github.com/smartcontractkit/chainlink/deployment/cre/pkg/offchain" aptoschangeset "github.com/smartcontractkit/chainlink/deployment/data-feeds/changeset/aptos" keystone_changeset "github.com/smartcontractkit/chainlink/deployment/keystone/changeset" "github.com/smartcontractkit/chainlink/system-tests/lib/cre" crecontracts "github.com/smartcontractkit/chainlink/system-tests/lib/cre/contracts" - credon "github.com/smartcontractkit/chainlink/system-tests/lib/cre/don" crejobs "github.com/smartcontractkit/chainlink/system-tests/lib/cre/don/jobs" "github.com/smartcontractkit/chainlink/system-tests/lib/cre/don/jobs/standardcapability" creblockchains "github.com/smartcontractkit/chainlink/system-tests/lib/cre/environment/blockchains" @@ -59,8 +59,8 @@ const ( deltaStageKey = "DeltaStage" transmissionScheduleKey = "TransmissionSchedule" forwarderQualifier = "" + ocr3ContractQualifier = "aptos_capability_ocr3" zeroForwarderHex = "0x0000000000000000000000000000000000000000000000000000000000000000" - aptosConfigTemplate = `{"chainId":"{{.ChainID}}","network":"aptos","creForwarderAddress":"{{.CREForwarderAddress}}"}` defaultWriteDeltaStage = 500*time.Millisecond + 1*time.Second defaultRequestTimeout = 30 * time.Second ) @@ -206,11 +206,9 @@ func (a *Aptos) PostEnvStartup( fmt.Sprintf("%s@%s:%d", strings.TrimPrefix(bootstrapNode.Keys.PeerID(), "p2p_"), bootstrapNode.Host, cre.OCRPeeringPort), } - capRegSemver, ok := creEnv.ContractVersions[keystone_changeset.CapabilitiesRegistry.String()] - if !ok { - return pkgerrors.New("CapabilitiesRegistry version not found in contract versions") + if _, _, err := crecontracts.DeployOCR3Contract(testLogger, ocr3ContractQualifier, creEnv.RegistryChainSelector, creEnv.CldfEnvironment, creEnv.ContractVersions); err != nil { + return fmt.Errorf("failed to deploy Aptos OCR3 contract: %w", err) } - capRegVersion := capRegSemver.String() for _, chainID := range enabledChainIDs { aptosChain, err := findAptosChainByChainID(creEnv.Blockchains, chainID) @@ -227,25 +225,22 @@ func (a *Aptos) PostEnvStartup( return pkgerrors.Wrap(cErr, "failed to get command for Aptos capability") } - tmpl, tmplErr := template.New("aptos-config").Parse(aptosConfigTemplate) - if tmplErr != nil { - return pkgerrors.Wrap(tmplErr, "failed to parse Aptos config template") - } - forwarderAddress := mustForwarderAddress(creEnv.CldfEnvironment.DataStore, aptosChain.ChainSelector()) - templateData := map[string]string{ - "ChainID": strconv.FormatUint(chainID, 10), - "CREForwarderAddress": forwarderAddress, + workerMetadata, metadataErr := don.Metadata().Workers() + if metadataErr != nil { + return fmt.Errorf("failed to collect Aptos worker metadata for DON %q: %w", don.Name, metadataErr) } - - var configBuffer bytes.Buffer - if execErr := tmpl.Execute(&configBuffer, templateData); execErr != nil { - return pkgerrors.Wrap(execErr, "failed to execute Aptos config template") + p2pToTransmitterMap, mapErr := p2pToTransmitterMapForWorkers(workerMetadata) + if mapErr != nil { + return fmt.Errorf("failed to collect Aptos worker transmitters for DON %q: %w", don.Name, mapErr) } - - configStr := configBuffer.String() - if validationErr := credon.ValidateTemplateSubstitution(configStr, flag); validationErr != nil { - return fmt.Errorf("aptos template validation failed: %w\nRendered: %s", validationErr, configStr) + methodSettings, settingsErr := resolveMethodConfigSettings(capabilityConfig.Values) + if settingsErr != nil { + return fmt.Errorf("failed to resolve Aptos method config settings for chain %d: %w", chainID, settingsErr) + } + configStr, configErr := buildWorkerConfigJSON(chainID, forwarderAddress, methodSettings, p2pToTransmitterMap, true) + if configErr != nil { + return fmt.Errorf("failed to build Aptos worker config: %w", configErr) } workerInput := jobs.ProposeJobSpecInput{ @@ -257,15 +252,15 @@ func (a *Aptos) PostEnvStartup( DONFilters: []offchain.TargetDONFilter{ {Key: offchain.FilterKeyDONName, Value: don.Name}, }, - Template: jobtypes.ReadContract, + Template: jobtypes.Aptos, Inputs: jobtypes.JobSpecInput{ "command": command, "config": configStr, "chainSelectorEVM": creEnv.RegistryChainSelector, "chainSelectorAptos": aptosChain.ChainSelector(), "bootstrapPeers": bootstrapPeers, - "useCapRegOCRConfig": true, - "capRegVersion": capRegVersion, + "useCapRegOCRConfig": false, + "contractQualifier": ocr3ContractQualifier, }, } @@ -295,6 +290,33 @@ func (a *Aptos) PostEnvStartup( if err := crejobs.Approve(ctx, creEnv.CldfEnvironment.Offchain, dons, specs); err != nil { return fmt.Errorf("failed to approve Aptos jobs: %w", err) } + + workers, err := don.Workers() + if err != nil { + return fmt.Errorf("failed to collect Aptos worker nodes for OCR3 config: %w", err) + } + workerNodeIDs := make([]string, 0, len(workers)) + for _, worker := range workers { + if worker.JobDistributorDetails == nil { + return fmt.Errorf("worker %q is missing job distributor details", worker.Name) + } + workerNodeIDs = append(workerNodeIDs, worker.JobDistributorDetails.NodeID) + } + + _, err = creocr3changeset.ConfigureOCR3{}.Apply(*creEnv.CldfEnvironment, creocr3changeset.ConfigureOCR3Input{ + ContractChainSelector: creEnv.RegistryChainSelector, + ContractQualifier: ocr3ContractQualifier, + DON: creocr3contracts.DonNodeSet{ + Name: don.Name, + NodeIDs: workerNodeIDs, + }, + OracleConfig: don.ResolveORC3Config(crecontracts.DefaultChainCapabilityOCR3Config()), + DryRun: false, + ExtraSignerFamilies: cre.OCRExtraSignerFamilies(creEnv.Blockchains), + }) + if err != nil { + return fmt.Errorf("failed to configure Aptos OCR3 contract: %w", err) + } return nil } @@ -339,6 +361,25 @@ func BuildCapabilityConfig(values map[string]any, p2pToTransmitterMap map[string return capConfig, nil } +func buildWorkerConfigJSON(chainID uint64, forwarderAddress string, settings methodConfigSettings, p2pToTransmitterMap map[string]string, isLocal bool) (string, error) { + cfg := map[string]any{ + "chainId": strconv.FormatUint(chainID, 10), + "network": "aptos", + "creForwarderAddress": forwarderAddress, + "isLocal": isLocal, + "deltaStage": settings.DeltaStage, + } + if len(p2pToTransmitterMap) > 0 { + cfg[specConfigP2PMapKey] = p2pToTransmitterMap + } + + raw, err := json.Marshal(cfg) + if err != nil { + return "", fmt.Errorf("failed to marshal Aptos worker config: %w", err) + } + return string(raw), nil +} + func methodConfigs(settings methodConfigSettings) map[string]*capabilitiespb.CapabilityMethodConfig { return map[string]*capabilitiespb.CapabilityMethodConfig{ "View": { diff --git a/system-tests/lib/cre/features/aptos/aptos_test.go b/system-tests/lib/cre/features/aptos/aptos_test.go index 95bbf282ba0..0b00cb9eb08 100644 --- a/system-tests/lib/cre/features/aptos/aptos_test.go +++ b/system-tests/lib/cre/features/aptos/aptos_test.go @@ -2,6 +2,7 @@ package aptos import ( "encoding/hex" + "encoding/json" "math/big" "testing" "time" @@ -124,6 +125,25 @@ func TestBuildCapabilityConfig_WithoutP2PMap_StillSetsRuntimeSpecConfig(t *testi require.Contains(t, specConfig.Underlying, specConfigDeltaStageKey) } +func TestBuildWorkerConfigJSON_IncludesLocalRuntimeValues(t *testing.T) { + configStr, err := buildWorkerConfigJSON( + 4, + "0x000000000000000000000000000000000000000000000000000000000000000a", + methodConfigSettings{DeltaStage: 2500 * time.Millisecond}, + map[string]string{"peer-a": "0x1"}, + true, + ) + require.NoError(t, err) + + var got map[string]any + require.NoError(t, json.Unmarshal([]byte(configStr), &got)) + require.Equal(t, "4", got["chainId"]) + require.Equal(t, "aptos", got["network"]) + require.Equal(t, true, got["isLocal"]) + require.EqualValues(t, (2500 * time.Millisecond).Nanoseconds(), got["deltaStage"]) + require.Equal(t, map[string]any{"peer-a": "0x1"}, got[specConfigP2PMapKey]) +} + func TestNormalizeTransmitter(t *testing.T) { tests := []struct { name string From 83295b811988e96a6c3049f66167c47ea01d79d7 Mon Sep 17 00:00:00 2001 From: cawthorne Date: Sat, 28 Mar 2026 12:39:29 +0000 Subject: [PATCH 34/34] cre: fix aptos lint issues --- system-tests/lib/cre/features/aptos/aptos.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/system-tests/lib/cre/features/aptos/aptos.go b/system-tests/lib/cre/features/aptos/aptos.go index ab402c82c83..fad29a05799 100644 --- a/system-tests/lib/cre/features/aptos/aptos.go +++ b/system-tests/lib/cre/features/aptos/aptos.go @@ -206,14 +206,14 @@ func (a *Aptos) PostEnvStartup( fmt.Sprintf("%s@%s:%d", strings.TrimPrefix(bootstrapNode.Keys.PeerID(), "p2p_"), bootstrapNode.Host, cre.OCRPeeringPort), } - if _, _, err := crecontracts.DeployOCR3Contract(testLogger, ocr3ContractQualifier, creEnv.RegistryChainSelector, creEnv.CldfEnvironment, creEnv.ContractVersions); err != nil { - return fmt.Errorf("failed to deploy Aptos OCR3 contract: %w", err) + if _, _, deployErr := crecontracts.DeployOCR3Contract(testLogger, ocr3ContractQualifier, creEnv.RegistryChainSelector, creEnv.CldfEnvironment, creEnv.ContractVersions); deployErr != nil { + return fmt.Errorf("failed to deploy Aptos OCR3 contract: %w", deployErr) } for _, chainID := range enabledChainIDs { - aptosChain, err := findAptosChainByChainID(creEnv.Blockchains, chainID) - if err != nil { - return err + aptosChain, chainErr := findAptosChainByChainID(creEnv.Blockchains, chainID) + if chainErr != nil { + return chainErr } capabilityConfig, resolveErr := cre.ResolveCapabilityConfig(nodeSet, flag, cre.ChainCapabilityScope(chainID)) @@ -268,9 +268,9 @@ func (a *Aptos) PostEnvStartup( if verifyErr := proposer.VerifyPreconditions(*creEnv.CldfEnvironment, workerInput); verifyErr != nil { return fmt.Errorf("precondition verification failed for Aptos worker job: %w", verifyErr) } - workerReport, err := proposer.Apply(*creEnv.CldfEnvironment, workerInput) - if err != nil { - return fmt.Errorf("failed to propose Aptos worker job spec: %w", err) + workerReport, applyErr := proposer.Apply(*creEnv.CldfEnvironment, workerInput) + if applyErr != nil { + return fmt.Errorf("failed to propose Aptos worker job spec: %w", applyErr) } for _, report := range workerReport.Reports { @@ -287,8 +287,8 @@ func (a *Aptos) PostEnvStartup( if len(specs) == 0 { return nil } - if err := crejobs.Approve(ctx, creEnv.CldfEnvironment.Offchain, dons, specs); err != nil { - return fmt.Errorf("failed to approve Aptos jobs: %w", err) + if approveErr := crejobs.Approve(ctx, creEnv.CldfEnvironment.Offchain, dons, specs); approveErr != nil { + return fmt.Errorf("failed to approve Aptos jobs: %w", approveErr) } workers, err := don.Workers()