Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
e3cb897
system-tests: finish aptos local CRE write parity
cawthorne Mar 18, 2026
0256fbb
cre: surface aptos account bootstrap errors
cawthorne Mar 18, 2026
ac0276e
plugins: narrow private capability refs
cawthorne Mar 19, 2026
36600ae
jobs: clarify aptos oracle-factory comment
cawthorne Mar 19, 2026
95af065
cre: move aptos transmitters into pre-start metadata
cawthorne Mar 19, 2026
2fa9d3b
cre: pass aptos config directly in local setup
cawthorne Mar 19, 2026
6382cf9
aptos: drop container funding fallback
cawthorne Mar 19, 2026
0c93262
cre: rename ocr extra signer helper
cawthorne Mar 19, 2026
0f9de7c
cre: tolerate empty imported aptos secrets
cawthorne Mar 19, 2026
8a5739a
cre: fix rebased aptos local wiring
cawthorne Mar 19, 2026
08e9f65
ci: fix tidy drift and consensus plugin pin
cawthorne Mar 19, 2026
bfb4880
aptos: provide cli fallback for forwarder deploy
cawthorne Mar 19, 2026
6321a3e
aptos: reuse cli fallback in smoke deploys
cawthorne Mar 19, 2026
9a6e76f
ci: install aptos cli for cre aptos suite
cawthorne Mar 19, 2026
c76d835
cre: tighten aptos local setup and key wiring
cawthorne Mar 20, 2026
03c6b39
lint and fix don_test
cawthorne Mar 20, 2026
0d6e3a8
lint
cawthorne Mar 20, 2026
6afd1c6
rename to BeforePoRTest
cawthorne Mar 20, 2026
ba461fd
cre: repin aptos local deps and keep read CI
cawthorne Mar 25, 2026
d319287
Merge remote-tracking branch 'origin/develop' into codex/aptos-local-…
cawthorne Mar 25, 2026
ae5c7d6
cre: share aptos internal node URL helper
cawthorne Mar 25, 2026
e435004
plugins: pin aptos capability branch head
cawthorne Mar 25, 2026
9663bae
cre: repin aptos transitive modules and public plugin
cawthorne Mar 25, 2026
f041ef2
cre: repin aptos workflow modules upstream
cawthorne Mar 25, 2026
c1f43d7
plugins: repin aptos capability to merged main
cawthorne Mar 25, 2026
ec38097
deps: pin chainlink-common aptos compat fix
cawthorne Mar 26, 2026
2e4c552
cre: wire aptos OCR config in local CRE
cawthorne Mar 26, 2026
58ac80d
deps: update chainlink-common aptos compat fix
cawthorne Mar 26, 2026
44225e3
cre: use capreg aptos config with cl-common fix
cawthorne Mar 26, 2026
670af6d
cre: disable capreg OCR config for local aptos
cawthorne Mar 26, 2026
d06a680
deps: drop chainlink-common aptos compat pin
cawthorne Mar 26, 2026
a3f3203
Merge origin/develop into codex/aptos-local-cre-minimal-write-refresh
cawthorne Mar 26, 2026
de61415
plugins: repin aptos capability after common fix merge
cawthorne Mar 26, 2026
b2bd615
cre: add aptos job template
cawthorne Mar 28, 2026
10449fd
cre: wire local aptos OCR config
cawthorne Mar 28, 2026
18e12d8
Merge remote-tracking branch 'origin/develop' into HEAD
cawthorne Mar 28, 2026
83295b8
cre: fix aptos lint issues
cawthorne Mar 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/cre-system-tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"}
],
Expand Down Expand Up @@ -213,6 +216,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
Expand Down
20 changes: 20 additions & 0 deletions core/capabilities/fakes/register.go
Original file line number Diff line number Diff line change
@@ -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
}
33 changes: 33 additions & 0 deletions core/capabilities/fakes/register_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
35 changes: 30 additions & 5 deletions core/capabilities/fakes/streams_trigger.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ package fakes

import (
"context"
"crypto/ecdsa"
"encoding/hex"
"errors"
"fmt"
"math/big"
"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"
Expand All @@ -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"
)

Expand All @@ -32,7 +33,7 @@ type fakeStreamsTrigger struct {
eng *services.Engine
lggr logger.Logger

signers []ocr2key.KeyBundle
signers []fakeStreamsTriggerSigner
codec datastreams.ReportCodec
meta datastreams.Metadata

Expand All @@ -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)

Expand Down Expand Up @@ -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()
}

Expand Down Expand Up @@ -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{}
Expand Down
17 changes: 17 additions & 0 deletions core/cmd/shell_local.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -505,6 +506,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())
Expand Down Expand Up @@ -552,6 +557,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)
Expand Down
37 changes: 37 additions & 0 deletions core/config/toml/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand All @@ -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 {
Expand Down Expand Up @@ -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
}
Expand Down
10 changes: 10 additions & 0 deletions core/scripts/cre/environment/configs/capability_defaults.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# 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 <this file>, 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"

#[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_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]
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

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 = ""
10 changes: 9 additions & 1 deletion core/scripts/cre/environment/environment/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,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)
Expand Down
Loading
Loading