Skip to content

Commit 7fcfab4

Browse files
authored
Add Aptos local CRE read/write support with write CI coverage (#21766)
* cre: finish aptos local CRE read and write setup parity * test: use known aptos chain id in health fixture * chore: trim aptos branch pin carryover * go: drop stale aptos checksum entries * cre: bump aptos ledger version before read smoke * deps: restore aptos relayer ledger version pin * test: drop aptos health fixture tweak * test: keep aptos health fixture on localnet chain id * tests: align aptos local and ci coverage * lint: fix aptos refactor formatting and shadowing * chore: trim aptos pr collateral changes * docs: restore generated aptos dependency graph * test: drop unrelated ccip nonce tweak * aptos: pin consensus to main and keep CI read-only * docs: clarify aptos metadata fallback * tests: tighten aptos workflow names and helpers * chore: address aptos review comments * refactor: use framework aptos account helper * chore: tidy framework aptos helper sums * test: simplify aptos scenario constants * fix: scope OCR signer families per capability * style: fix aptos import grouping * test: migrate aptos write to capreg ocr config * fix: address aptos lint issues * refactor: remove unused aptos forwarder placeholder * test: run aptos ci on roundtrip and expected failure * docs: clarify aptos capability config defaults * docs: consolidate aptos changeset notes * refactor: align aptos capability naming * feat: make imported aptos keys chain-aware * docs: clarify imported aptos key adapter * test: regenerate aptos config mocks * refactor: drop read contract aptos residue * test: speed up aptos cre suite * fix: address aptos lint issues
1 parent 22645d2 commit 7fcfab4

87 files changed

Lines changed: 5229 additions & 155 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"chainlink": patch
3+
---
4+
5+
#internal
6+
7+
Add Aptos local CRE read/write support, including Capabilities Registry OCR config for Aptos write and CI coverage for the Aptos write roundtrip and expected-failure scenarios.

.github/workflows/cre-system-tests.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ jobs:
7575
7676
# Add list of tests with certain topologies
7777
PER_TEST_TOPOLOGIES_JSON=${PER_TEST_TOPOLOGIES_JSON:-'{
78+
"Test_CRE_V2_Aptos_Suite": [
79+
{"topology":"workflow-gateway-aptos","configs":"configs/workflow-gateway-don-aptos.toml"}
80+
],
7881
"Test_CRE_V2_Solana_Suite": [
7982
{"topology":"workflow","configs":"configs/workflow-don-solana.toml"}
8083
],
@@ -213,6 +216,35 @@ jobs:
213216
chmod +x bin/ctf
214217
echo "::endgroup::"
215218
219+
- name: Install Aptos CLI
220+
if: ${{ matrix.tests.test_name == 'Test_CRE_V2_Aptos_Suite' }}
221+
shell: bash
222+
env:
223+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
224+
APTOS_CLI_TAG: "aptos-cli-v7.8.0"
225+
run: |
226+
echo "::startgroup::Install Aptos CLI"
227+
bin_dir="$HOME/.local/bin"
228+
mkdir -p "$bin_dir"
229+
230+
gh release download "${APTOS_CLI_TAG}" \
231+
--pattern "aptos-cli-*-Ubuntu-24.04-x86_64.zip" \
232+
--clobber \
233+
--repo aptos-labs/aptos-core \
234+
-O aptos-cli.zip
235+
236+
unzip -o aptos-cli.zip -d aptos-cli-extract >/dev/null
237+
aptos_path="$(find aptos-cli-extract -type f -name aptos | head -n1)"
238+
if [[ -z "$aptos_path" ]]; then
239+
echo "failed to locate aptos binary in release archive"
240+
exit 1
241+
fi
242+
243+
install -m 0755 "$aptos_path" "$bin_dir/aptos"
244+
echo "$bin_dir" >> "$GITHUB_PATH"
245+
"$bin_dir/aptos" --version
246+
echo "::endgroup::"
247+
216248
- name: Start local CRE${{ matrix.tests.cre_version }}
217249
shell: bash
218250
id: start-local-cre

core/cmd/shell_local.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,19 @@ func (s *Shell) runNode(c *cli.Context) error {
552552
}
553553
}
554554
if s.Config.AptosEnabled() {
555+
for _, k := range s.Config.ImportedAptosKeys().List() {
556+
lggr.Debug("Importing aptos key")
557+
_, err2 := app.GetKeyStore().Aptos().Import(rootCtx, []byte(k.JSON()), k.Password())
558+
if err2 != nil {
559+
if errors.Is(err2, keystore.ErrKeyExists) {
560+
lggr.Debugf("Aptos key %s already exists for chain %v", k.JSON(), k.ChainDetails())
561+
continue
562+
}
563+
return s.errorOut(fmt.Errorf("error importing aptos key: %w", err2))
564+
}
565+
lggr.Debugf("Imported aptos key %s for chain %v", k.JSON(), k.ChainDetails())
566+
}
567+
555568
err2 := app.GetKeyStore().Aptos().EnsureKey(rootCtx)
556569
if err2 != nil {
557570
return fmt.Errorf("failed to ensure aptos key: %w", err2)

core/config/toml/types.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ type Secrets struct {
146146
Threshold ThresholdKeyShareSecrets `toml:",omitempty"`
147147
EVM EthKeys `toml:",omitempty"` // choose EVM as the TOML field name to align with relayer config convention
148148
Solana SolKeys `toml:",omitempty"` // choose Solana as the TOML field name to align with relayer config convention
149+
Aptos AptosKeys `toml:",omitempty"` // choose Aptos as the TOML field name to align with relayer config convention
149150

150151
P2PKey P2PKey `toml:",omitempty"`
151152
DKGRecipientKey DKGRecipientKey `toml:",omitempty"`
@@ -164,6 +165,16 @@ type SolKey struct {
164165
Password *models.Secret
165166
}
166167

168+
type AptosKeys struct {
169+
Keys []*AptosKey
170+
}
171+
172+
type AptosKey struct {
173+
JSON *models.Secret
174+
ID *uint64
175+
Password *models.Secret
176+
}
177+
167178
func (s *SolKeys) SetFrom(f *SolKeys) error {
168179
err := s.validateMerge(f)
169180
if err != nil {
@@ -245,6 +256,85 @@ func (e *SolKey) ValidateConfig() (err error) {
245256
return err
246257
}
247258

259+
func (a *AptosKeys) SetFrom(f *AptosKeys) error {
260+
err := a.validateMerge(f)
261+
if err != nil {
262+
return err
263+
}
264+
if f == nil || len(f.Keys) == 0 {
265+
return nil
266+
}
267+
a.Keys = make([]*AptosKey, len(f.Keys))
268+
copy(a.Keys, f.Keys)
269+
return nil
270+
}
271+
272+
func (a *AptosKeys) validateMerge(f *AptosKeys) (err error) {
273+
have := make(map[uint64]struct{})
274+
if a != nil && f != nil {
275+
for _, aptosKey := range a.Keys {
276+
have[*aptosKey.ID] = struct{}{}
277+
}
278+
for _, aptosKey := range f.Keys {
279+
if _, ok := have[*aptosKey.ID]; ok {
280+
err = errors.Join(err, configutils.ErrOverride{Name: fmt.Sprintf("AptosKeys: %d", *aptosKey.ID)})
281+
}
282+
}
283+
}
284+
return err
285+
}
286+
287+
func (a *AptosKeys) ValidateConfig() (err error) {
288+
for i, aptosKey := range a.Keys {
289+
if err2 := aptosKey.ValidateConfig(); err2 != nil {
290+
err = errors.Join(err, configutils.ErrInvalid{Name: fmt.Sprintf("AptosKeys[%d]", i), Value: aptosKey, Msg: "invalid AptosKey"})
291+
}
292+
}
293+
return err
294+
}
295+
296+
func (p *AptosKey) SetFrom(f *AptosKey) (err error) {
297+
err = p.validateMerge(f)
298+
if err != nil {
299+
return err
300+
}
301+
if v := f.JSON; v != nil {
302+
p.JSON = v
303+
}
304+
if v := f.ID; v != nil {
305+
p.ID = v
306+
}
307+
if v := f.Password; v != nil {
308+
p.Password = v
309+
}
310+
return nil
311+
}
312+
313+
func (p *AptosKey) validateMerge(f *AptosKey) (err error) {
314+
if p.JSON != nil && f.JSON != nil {
315+
err = errors.Join(err, configutils.ErrOverride{Name: "JSON"})
316+
}
317+
if p.ID != nil && f.ID != nil {
318+
err = errors.Join(err, configutils.ErrOverride{Name: "ID"})
319+
}
320+
if p.Password != nil && f.Password != nil {
321+
err = errors.Join(err, configutils.ErrOverride{Name: "Password"})
322+
}
323+
return err
324+
}
325+
326+
func (p *AptosKey) ValidateConfig() (err error) {
327+
if (p.JSON != nil) != (p.Password != nil) || (p.Password != nil) != (p.ID != nil) {
328+
err = errors.Join(err, configutils.ErrInvalid{Name: "AptosKey", Value: p.JSON, Msg: "all fields must be nil or non-nil"})
329+
}
330+
if p.ID != nil {
331+
if _, ok := chain_selectors.AptosChainIdToChainSelector()[*p.ID]; !ok {
332+
err = errors.Join(err, configutils.ErrInvalid{Name: "ID", Value: p.ID, Msg: "invalid chain id"})
333+
}
334+
}
335+
return err
336+
}
337+
248338
type EthKeys struct {
249339
Keys []*EthKey
250340
}

core/scripts/cre/environment/configs/capability_defaults.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,17 @@
130130
# FromAddress = "0x0000000000000000000000000000000000000000"
131131
# ForwarderAddress = "0x0000000000000000000000000000000000000000"
132132

133+
# Aptos chain capability plugin (View + WriteReport). Runtime values are injected per chain.
134+
[capability_configs.aptos]
135+
binary_name = "aptos"
136+
137+
[capability_configs.aptos.values]
138+
# These values build the Aptos capability config registered in CapReg.
139+
# ChainID and forwarder address are injected separately at job proposal time.
140+
# They are not emitted as top-level worker job-spec fields.
141+
RequestTimeout = "30s"
142+
DeltaStage = "1500ms"
143+
133144
[capability_configs.solana.values]
134145
TxAcceptanceState = 3
135146
TxRetentonTimeout = "120s"
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Same as workflow-gateway-don.toml but with Aptos chain and a single Aptos capability.
2+
# Anvil 1337: registry and gateway. Aptos: local devnet (chain_id 4). Run: env config path <this file>, then env start.
3+
4+
[[blockchains]]
5+
type = "anvil"
6+
chain_id = "1337"
7+
container_name = "anvil-1337"
8+
docker_cmd_params = ["-b", "0.5", "--mixed-mining"]
9+
10+
[[blockchains]]
11+
type = "aptos"
12+
chain_id = "4"
13+
14+
[jd]
15+
csa_encryption_key = "d1093c0060d50a3c89c189b2e485da5a3ce57f3dcb38ab7e2c0d5f0bb2314a44"
16+
# change to your version
17+
image = "job-distributor:0.22.1"
18+
19+
#[s3provider]
20+
# # use all defaults
21+
# port = 9000
22+
# console_port = 9001
23+
24+
[infra]
25+
# either "docker" or "kubernetes"
26+
type = "docker"
27+
28+
[[nodesets]]
29+
nodes = 4
30+
name = "workflow"
31+
don_types = ["workflow"]
32+
override_mode = "all"
33+
http_port_range_start = 10100
34+
35+
# Keep the registry chain (1337) in node TOML even though this DON's chain-scoped
36+
# capability is Aptos-only; the workflow stack still needs the EVM registry chain.
37+
supported_evm_chains = [1337]
38+
# Workflow runtime limits still need both the EVM registry chain and the Aptos chain selector.
39+
env_vars = { CL_CRE_SETTINGS_DEFAULT = '{"PerWorkflow":{"CapabilityCallTimeout":"5m0s","ChainAllowed":{"Default":"false","Values":{"1337":"true","4457093679053095497":"true"}}}}' }
40+
capabilities = ["cron", "consensus", "aptos-4"]
41+
registry_based_launch_allowlist = ["cron-trigger@1.0.0"]
42+
43+
[nodesets.db]
44+
image = "postgres:12.0"
45+
port = 13000
46+
47+
[[nodesets.node_specs]]
48+
roles = ["plugin"]
49+
[nodesets.node_specs.node]
50+
docker_ctx = "../../../.."
51+
docker_file = "core/chainlink.Dockerfile"
52+
docker_build_args = { "CL_IS_PROD_BUILD" = "false" }
53+
# image = "chainlink-tmp:latest"
54+
user_config_overrides = ""
55+
56+
[[nodesets]]
57+
nodes = 1
58+
name = "bootstrap-gateway"
59+
don_types = ["bootstrap", "gateway"]
60+
override_mode = "each"
61+
http_port_range_start = 10300
62+
63+
supported_evm_chains = [1337]
64+
65+
[nodesets.db]
66+
image = "postgres:12.0"
67+
port = 13200
68+
69+
[[nodesets.node_specs]]
70+
roles = ["bootstrap", "gateway"]
71+
[nodesets.node_specs.node]
72+
docker_ctx = "../../../.."
73+
docker_file = "core/chainlink.Dockerfile"
74+
docker_build_args = { "CL_IS_PROD_BUILD" = "false" }
75+
# 5002 is the web API capabilities port for incoming requests
76+
# 15002 is the vault port for incoming requests
77+
custom_ports = ["5002:5002", "15002:15002"]
78+
# image = "chainlink-tmp:latest"
79+
user_config_overrides = ""

core/scripts/cre/environment/environment/environment.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,16 @@ func startCmd() *cobra.Command {
330330
}
331331

332332
features := feature_set.New()
333+
extraAllowedPorts := append([]int(nil), extraAllowedGatewayPorts...)
334+
if in.Fake != nil {
335+
extraAllowedPorts = append(extraAllowedPorts, in.Fake.Port)
336+
}
337+
if in.FakeHTTP != nil {
338+
extraAllowedPorts = append(extraAllowedPorts, in.FakeHTTP.Port)
339+
}
340+
333341
gatewayWhitelistConfig := gateway.WhitelistConfig{
334-
ExtraAllowedPorts: append(extraAllowedGatewayPorts, in.Fake.Port, in.FakeHTTP.Port),
342+
ExtraAllowedPorts: extraAllowedPorts,
335343
ExtraAllowedIPsCIDR: []string{"0.0.0.0/0"},
336344
}
337345
output, startErr := StartCLIEnvironment(cmdContext, relativePathToRepoRoot, in, nil, features, nil, envDependencies, gatewayWhitelistConfig)

core/scripts/cre/environment/mock/trigger_types.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import (
55
"time"
66

77
"github.com/google/uuid"
8-
cron2 "github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron"
98
"google.golang.org/protobuf/types/known/anypb"
109

10+
crontypedapi "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/triggers/cron"
11+
1112
pb2 "github.com/smartcontractkit/chainlink/system-tests/lib/cre/mock/pb"
1213
)
1314

@@ -24,7 +25,7 @@ func getTriggerRequest(triggerType TriggerType) (*pb2.SendTriggerEventRequest, e
2425
switch triggerType {
2526
case TriggerTypeCron:
2627
// First create the payload
27-
payload := &cron2.LegacyPayload{ //nolint:staticcheck // legacy
28+
payload := &crontypedapi.LegacyPayload{ //nolint:staticcheck // legacy
2829
ScheduledExecutionTime: time.Now().Format(time.RFC3339Nano),
2930
}
3031

core/scripts/go.mod

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,12 @@ require (
5353
github.com/smartcontractkit/chainlink-evm/gethwrappers v0.0.0-20260119171452-39c98c3b33cd
5454
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260326111235-8c09d1a4491f
5555
github.com/smartcontractkit/chainlink-protos/job-distributor v0.18.0
56-
github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.8
56+
github.com/smartcontractkit/chainlink-testing-framework/framework v0.15.9-0.20260330164022-15e89dd1431f
5757
github.com/smartcontractkit/chainlink-testing-framework/framework/components/dockercompose v0.1.20
5858
github.com/smartcontractkit/chainlink-testing-framework/lib v1.54.5
5959
github.com/smartcontractkit/chainlink-testing-framework/seth v1.51.5
6060
github.com/smartcontractkit/chainlink/core/scripts/cre/environment/examples/workflows/v2/proof-of-reserve/cron-based v0.0.0-00010101000000-000000000000
61-
github.com/smartcontractkit/chainlink/system-tests/lib v0.0.0-20251020210257-0a6ec41648b4
62-
github.com/smartcontractkit/cre-sdk-go/capabilities/scheduler/cron v1.3.0
61+
github.com/smartcontractkit/chainlink/system-tests/lib v0.0.0-00010101000000-000000000000
6362
github.com/smartcontractkit/libocr v0.0.0-20260304194147-a03701e2c02e
6463
github.com/spf13/cobra v1.10.2
6564
github.com/spf13/pflag v1.0.10
@@ -483,7 +482,7 @@ require (
483482
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
484483
github.com/smartcontractkit/ccip-contract-examples/chains/evm v0.0.0-20260129135848-c86808ba5cb9 // indirect
485484
github.com/smartcontractkit/ccip-owner-contracts v0.1.0 // indirect
486-
github.com/smartcontractkit/chainlink-aptos v0.0.0-20260318173523-755cafb24200 // indirect
485+
github.com/smartcontractkit/chainlink-aptos v0.0.0-20260324144720-484863604698 // indirect
487486
github.com/smartcontractkit/chainlink-ccip/ccv/chains/evm v0.0.0-20260323224438-d819cb3228e1 // indirect
488487
github.com/smartcontractkit/chainlink-ccip/chains/evm/deployment v0.0.0-20260317185256-d5f7db87ae70 // indirect
489488
github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20260310183131-8d0f0e383288 // indirect
@@ -519,7 +518,6 @@ require (
519518
github.com/smartcontractkit/chainlink-ton v0.0.0-20260331005855-7b5a4b3384f8 // indirect
520519
github.com/smartcontractkit/chainlink-ton/deployment v0.0.0-20260326230916-bcfdbe85f221 // indirect
521520
github.com/smartcontractkit/chainlink-tron/relayer v0.0.11-0.20260218133534-cbd44da2856b // indirect
522-
github.com/smartcontractkit/cre-sdk-go v1.5.0 // indirect
523521
github.com/smartcontractkit/freeport v0.1.3-0.20250828155247-add56fa28aad // indirect
524522
github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect
525523
github.com/smartcontractkit/mcms v0.38.2 // indirect

core/scripts/go.sum

Lines changed: 4 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)