Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/red-cats-attend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": minor
---

#internal Refactor system tests
2 changes: 1 addition & 1 deletion core/scripts/cre/environment/environment/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ func startCmd() *cobra.Command {
// environment without full setup. Then persist absolute paths to the
// generated artifacts (env artifact JSON and the cached CTF config) in
// `artifact_paths.json`. System tests use these to reload environment
// state across runs (see `system-tests/tests/smoke/cre/capabilities_test.go`),
// state across runs (see `system-tests/tests/smoke/cre/cre_suite_test.go`),
// where the cached config and env artifact are consumed to reconstruct
// the in-memory CLDF environment without re-provisioning.
//
Expand Down
6 changes: 3 additions & 3 deletions core/scripts/cre/environment/environment/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ func compileWorkflow(workflowFilePathFlag, workflowNameFlag string) (string, err
}

func deployWorkflow(ctx context.Context, wasmWorkflowFilePathFlag, workflowNameFlag, workflowOwnerAddressFlag, workflowRegistryAddressFlag, capabilitiesRegistryAddressFlag, containerNamePatternFlag, containerTargetDirFlag, configFilePathFlag, secretsFilePathFlag, rpcURLFlag string, donIDFlag uint32, deleteWorkflowFile bool) error {
copyErr := creworkflow.CopyArtifactToDockerContainers(wasmWorkflowFilePathFlag, containerNamePatternFlag, containerTargetDirFlag)
copyErr := creworkflow.CopyArtifactsToDockerContainers(wasmWorkflowFilePathFlag, containerNamePatternFlag, containerTargetDirFlag)
if copyErr != nil {
return errors.Wrap(copyErr, "❌ failed to copy workflow to Docker container")
}
Expand Down Expand Up @@ -409,7 +409,7 @@ func deployWorkflow(ctx context.Context, wasmWorkflowFilePathFlag, workflowNameF
return errors.Wrap(configPathAbsErr, "failed to get absolute path of the config file")
}

configCopyErr := creworkflow.CopyArtifactToDockerContainers(configFilePathFlag, containerNamePatternFlag, containerTargetDirFlag)
configCopyErr := creworkflow.CopyArtifactsToDockerContainers(configFilePathFlag, containerNamePatternFlag, containerTargetDirFlag)
if configCopyErr != nil {
return errors.Wrap(configCopyErr, "❌ failed to copy config file to Docker container")
}
Expand All @@ -436,7 +436,7 @@ func deployWorkflow(ctx context.Context, wasmWorkflowFilePathFlag, workflowNameF
fmt.Printf("\n✅ Encrypted workflow secrets file prepared\n\n")

fmt.Printf("\n⚙️ Copying encrypted secrets file to Docker container\n")
secretsCopyErr := creworkflow.CopyArtifactToDockerContainers(secretPathAbs, containerNamePatternFlag, containerTargetDirFlag)
secretsCopyErr := creworkflow.CopyArtifactsToDockerContainers(secretPathAbs, containerNamePatternFlag, containerTargetDirFlag)
if secretsCopyErr != nil {
return errors.Wrap(secretsCopyErr, "❌ failed to copy encrypted secrets file to Docker container")
}
Expand Down
21 changes: 21 additions & 0 deletions system-tests/lib/cre/capabilities/vault/vault.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,27 @@ func New(chainID uint64) (*capabilities.Capability, error) {
)
}

func EncryptSecret(secret string) (string, error) {
masterPublicKey := tdh2easy.PublicKey{}
masterPublicKeyBytes, err := hex.DecodeString(MasterPublicKeyStr)
if err != nil {
return "", errors.Wrap(err, "failed to decode master public key")
}
err = masterPublicKey.Unmarshal(masterPublicKeyBytes)
if err != nil {
return "", errors.Wrap(err, "failed to unmarshal master public key")
}
cipher, err := tdh2easy.Encrypt(&masterPublicKey, []byte(secret))
if err != nil {
return "", errors.Wrap(err, "failed to encrypt secret")
}
cipherBytes, err := cipher.Marshal()
if err != nil {
return "", errors.Wrap(err, "failed to marshal encrypted secrets to bytes")
}
return hex.EncodeToString(cipherBytes), nil
}

func jobSpec(chainID uint64) cre.JobSpecFn {
return func(input *cre.JobSpecInput) (cre.DonsToJobSpecs, error) {
if input.DonTopology == nil {
Expand Down
81 changes: 81 additions & 0 deletions system-tests/lib/cre/contracts/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,29 @@ func MustFindAddressesForChain(addressBook cldf.AddressBook, chainSelector uint6
return addr
}

// MergeAllDataStores merges all DataStores (after contracts deployments)
func MergeAllDataStores(fullCldEnvOutput *cre.FullCLDEnvironmentOutput, changesetOutputs ...cldf.ChangesetOutput) {
fmt.Print("Merging DataStores (after contracts deployments)...")
minChangesetsCap := 2
if len(changesetOutputs) < minChangesetsCap {
panic(fmt.Errorf("DataStores merging failed: at least %d changesets required", minChangesetsCap))
}

// Start with the first changeset's data store
baseDataStore := changesetOutputs[0].DataStore

// Merge all subsequent changesets into the base data store
for i := 1; i < len(changesetOutputs); i++ {
otherDataStore := changesetOutputs[i].DataStore
mergeErr := baseDataStore.Merge(otherDataStore.Seal())
if mergeErr != nil {
panic(errors.Wrap(mergeErr, "DataStores merging failed"))
}
}

fullCldEnvOutput.Environment.DataStore = baseDataStore.Seal()
}

func ConfigureWorkflowRegistry(testLogger zerolog.Logger, input *cre.WorkflowRegistryInput) (*cre.WorkflowRegistryOutput, error) {
if input == nil {
return nil, errors.New("input is nil")
Expand Down Expand Up @@ -519,3 +542,61 @@ func ConfigureDataFeedsCache(testLogger zerolog.Logger, input *cre.ConfigureData

return out, nil
}

func DeployDataFeedsCacheContract(testLogger zerolog.Logger, chainSelector uint64, fullCldEnvOutput *cre.FullCLDEnvironmentOutput) (common.Address, cldf.ChangesetOutput, error) {
testLogger.Info().Msg("Deploying Data Feeds Cache contract...")
deployDfConfig := df_changeset_types.DeployConfig{
ChainsToDeploy: []uint64{chainSelector},
Labels: []string{"data-feeds"}, // label required by the changeset
}

dfOutput, dfErr := commonchangeset.RunChangeset(df_changeset.DeployCacheChangeset, *fullCldEnvOutput.Environment, deployDfConfig)
if dfErr != nil {
return common.Address{}, cldf.ChangesetOutput{}, errors.Wrapf(dfErr, "failed to deploy Data Feeds Cache contract on chain %d", chainSelector)
}

mergeErr := fullCldEnvOutput.Environment.ExistingAddresses.Merge(dfOutput.AddressBook) //nolint:staticcheck // won't migrate now
if mergeErr != nil {
return common.Address{}, cldf.ChangesetOutput{}, errors.Wrap(mergeErr, "failed to merge address book of Data Feeds Cache contract")
}
testLogger.Info().Msgf("Data Feeds Cache contract deployed to %d", chainSelector)

dataFeedsCacheAddress, dataFeedsCacheErr := FindAddressesForChain(
fullCldEnvOutput.Environment.ExistingAddresses, //nolint:staticcheck // won't migrate now
chainSelector,
df_changeset.DataFeedsCache.String(),
)
if dataFeedsCacheErr != nil {
return common.Address{}, cldf.ChangesetOutput{}, errors.Wrapf(dataFeedsCacheErr, "failed to find Data Feeds Cache contract address on chain %d", chainSelector)
}
testLogger.Info().Msgf("Data Feeds Cache contract found on chain %d at address %s", chainSelector, dataFeedsCacheAddress)

return dataFeedsCacheAddress, dfOutput, nil
}

func DeployReadBalancesContract(testLogger zerolog.Logger, chainSelector uint64, fullCldEnvOutput *cre.FullCLDEnvironmentOutput) (common.Address, cldf.ChangesetOutput, error) {
testLogger.Info().Msg("Deploying Read Balances contract...")
deployReadBalanceRequest := &keystone_changeset.DeployRequestV2{ChainSel: chainSelector}
rbOutput, rbErr := keystone_changeset.DeployBalanceReaderV2(*fullCldEnvOutput.Environment, deployReadBalanceRequest)
if rbErr != nil {
return common.Address{}, cldf.ChangesetOutput{}, errors.Wrap(rbErr, "failed to deploy Read Balances contract")
}

mergeErr2 := fullCldEnvOutput.Environment.ExistingAddresses.Merge(rbOutput.AddressBook) //nolint:staticcheck // won't migrate now
if mergeErr2 != nil {
return common.Address{}, cldf.ChangesetOutput{}, errors.Wrap(mergeErr2, "failed to merge address book of Read Balances contract")
}
testLogger.Info().Msgf("Read Balances contract deployed to %d", chainSelector)

readBalancesAddress, readContractErr := FindAddressesForChain(
fullCldEnvOutput.Environment.ExistingAddresses, //nolint:staticcheck // won't migrate now
chainSelector,
keystone_changeset.BalanceReader.String(),
)
if readContractErr != nil {
return common.Address{}, cldf.ChangesetOutput{}, errors.Wrap(readContractErr, "failed to find Read Balances contract address")
}
testLogger.Info().Msgf("Read Balances contract found on chain %d at address %s", chainSelector, readBalancesAddress)

return readBalancesAddress, rbOutput, nil
}
18 changes: 17 additions & 1 deletion system-tests/lib/cre/workflow/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,23 @@ func findAllDockerContainerNames(pattern string) ([]string, error) {
return containerNames, nil
}

func CopyArtifactToDockerContainers(filePath string, containerNamePattern string, targetDir string) error {
func CopyArtifactsToDockerContainers(containerTargetDir string, containerNamePattern string, filesToCopy ...string) error {
for _, file := range filesToCopy {
if _, err := os.Stat(file); err != nil {
fmt.Fprintf(os.Stderr, "Warning: File '%s' does not exist. Skipping file copying to docker containers\n", file)
continue
}

workflowCopyErr := copyArtifactToDockerContainers(file, containerNamePattern, containerTargetDir)
if workflowCopyErr != nil {
return errors.Wrapf(workflowCopyErr, "failed to copy a file (%s) to docker containers", file)
}
}
return nil
}

func copyArtifactToDockerContainers(filePath string, containerNamePattern string, targetDir string) error {
fmt.Printf("Copying file '%s' to Docker containers.\n", filePath)
containerNames, containerNamesErr := findAllDockerContainerNames(containerNamePattern)
if containerNamesErr != nil {
return errors.Wrap(containerNamesErr, "failed to find Docker containers")
Expand Down
19 changes: 17 additions & 2 deletions system-tests/lib/cre/workflow/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/hex"
"fmt"
"math/big"
"os"
"path/filepath"
"strings"

Expand Down Expand Up @@ -38,7 +39,7 @@ func RegisterWithContract(ctx context.Context, sc *seth.Client, workflowRegistry
var configData []byte
var configErr error
configURLToUse := ""
if configURL != nil {
if configURL != nil && *configURL != "" {
configData, configErr = libnet.Download(ctx, *configURL)
if configErr != nil {
return "", errors.Wrap(configErr, "failed to download workflow config")
Expand All @@ -52,7 +53,7 @@ func RegisterWithContract(ctx context.Context, sc *seth.Client, workflowRegistry
}

secretsURLToUse := ""
if secretsURL != nil {
if secretsURL != nil && *secretsURL != "" {
if artifactsDirInContainer != nil {
secretsURLToUse = fmt.Sprintf("file://%s/%s", *artifactsDirInContainer, filepath.Base(*secretsURL))
} else {
Expand Down Expand Up @@ -157,6 +158,20 @@ func DeleteWithContract(ctx context.Context, sc *seth.Client, workflowRegistryAd
return nil
}

func RemoveWorkflowArtifactsFromLocalEnv(workflowArtifactsLocations ...string) error {
for _, artifactLocation := range workflowArtifactsLocations {
if artifactLocation == "" {
continue
}

err := os.Remove(artifactLocation)
if err != nil {
return errors.Wrap(err, fmt.Sprintf("failed to remove workflow artifact located at %s: %s", artifactLocation, err.Error()))
}
}
return nil
}

func generateWorkflowIDFromStrings(owner string, name string, workflow []byte, config []byte, secretsURL string) (string, error) {
ownerWithoutPrefix := owner
if strings.HasPrefix(owner, "0x") {
Expand Down
20 changes: 20 additions & 0 deletions system-tests/lib/crypto/evm.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package crypto

import (
"crypto/ecdsa"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"

"github.com/pkg/errors"

"github.com/smartcontractkit/chainlink-testing-framework/framework/clclient"
)
Expand All @@ -27,3 +32,18 @@ func GenerateEVMKeys(password string, n int) (*EVMKeys, error) {
}
return result, nil
}

/*
Generates new private and public key pair

Returns a new public address and a private key
*/
func GenerateNewKeyPair() (common.Address, *ecdsa.PrivateKey, error) {
privateKey, pkErr := crypto.GenerateKey()
if pkErr != nil {
return common.Address{}, nil, errors.Wrap(pkErr, "failed to generate a new private key (EOA)")
}

publicKeyAddr := crypto.PubkeyToAddress(privateKey.PublicKey)
return publicKeyAddr, privateKey, nil
}
2 changes: 1 addition & 1 deletion system-tests/tests/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ require (
github.com/smartcontractkit/chainlink/deployment v0.0.0-20250826151008-ae5ec0ee6f2c
github.com/smartcontractkit/chainlink/system-tests/lib v0.0.0-20250826151008-ae5ec0ee6f2c
github.com/smartcontractkit/libocr v0.0.0-20250707144819-babe0ec4e358
github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20250624150019-e49f7e125e6b
github.com/spf13/cobra v1.9.1
github.com/stretchr/testify v1.10.0
golang.org/x/sync v0.16.0
Expand Down Expand Up @@ -537,6 +536,7 @@ require (
github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect
github.com/smartcontractkit/mcms v0.21.1 // indirect
github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de // indirect
github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20250624150019-e49f7e125e6b // indirect
github.com/smartcontractkit/wsrpc v0.8.5-0.20250502134807-c57d3d995945 // indirect
github.com/sony/gobreaker/v2 v2.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
Expand Down
17 changes: 9 additions & 8 deletions system-tests/tests/smoke/cre/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ Only if you want to run the tests on non-default topology you need to set follow

- `CTF_CONFIGS` -- either `configs/workflow-gateway-don.toml` or `configs/workflow-gateway-capabilities-don.toml`
- `CRE_TOPOLOGY` -- either `workflow-gateway` or `workflow-gateway-capabilities`
- `CTF_LOG_LEVEL=debug` -- to display test debug-level logs

---

Expand Down Expand Up @@ -173,7 +174,7 @@ Example `launch.json` entry:
"request": "launch",
"mode": "test",
"program": "${workspaceFolder}/system-tests/tests/smoke/cre",
"args": ["-test.run", "Test_CRE_Workflow_Don"]
"args": ["-test.run", "Test_CRE_Suite"]
}
```

Expand Down Expand Up @@ -578,15 +579,15 @@ After compilation, workflow files must be distributed to the appropriate contain
containerTargetDir := "/home/chainlink/workflows"

// Copy compiled workflow binary
workflowCopyErr := creworkflow.CopyArtifactToDockerContainers(
workflowCopyErr := creworkflow.CopyArtifactsToDockerContainers(
compressedWorkflowWasmPath,
"workflow-node",
containerTargetDir,
)
require.NoError(t, workflowCopyErr, "failed to copy workflow to docker containers")

// Copy configuration file
configCopyErr := creworkflow.CopyArtifactToDockerContainers(
configCopyErr := creworkflow.CopyArtifactsToDockerContainers(
workflowConfigFilePath,
"workflow-node",
containerTargetDir,
Expand Down Expand Up @@ -681,11 +682,11 @@ func setupWorkflow(t *testing.T, workflowSourcePath, workflowName string, config

// 3. Copy files to containers
containerTargetDir := "/home/chainlink/workflows"
err := creworkflow.CopyArtifactToDockerContainers(compressedWorkflowWasmPath, "workflow-node", containerTargetDir)
err := creworkflow.CopyArtifactsToDockerContainers(compressedWorkflowWasmPath, "workflow-node", containerTargetDir)
require.NoError(t, err, "failed to copy workflow binary")

if configFilePath != "" {
err = creworkflow.CopyArtifactToDockerContainers(configFilePath, "workflow-node", containerTargetDir)
err = creworkflow.CopyArtifactsToDockerContainers(configFilePath, "workflow-node", containerTargetDir)
require.NoError(t, err, "failed to copy config file")
}

Expand Down Expand Up @@ -777,7 +778,7 @@ encryptedSecretsPath, err := creworkflow.PrepareSecrets(
require.NoError(t, err, "failed to prepare secrets")

// 3. Copy encrypted secrets to containers
err = creworkflow.CopyArtifactToDockerContainers(
err = creworkflow.CopyArtifactsToDockerContainers(
encryptedSecretsPath,
"workflow-node",
"/home/chainlink/workflows",
Expand Down Expand Up @@ -869,10 +870,10 @@ func setupWorkflowWithSecrets(t *testing.T, workflowSourcePath, workflowName, se

// Copy files to containers
containerTargetDir := "/home/chainlink/workflows"
err = creworkflow.CopyArtifactToDockerContainers(compressedWorkflowWasmPath, "workflow-node", containerTargetDir)
err = creworkflow.CopyArtifactsToDockerContainers(compressedWorkflowWasmPath, "workflow-node", containerTargetDir)
require.NoError(t, err, "failed to copy workflow")

err = creworkflow.CopyArtifactToDockerContainers(encryptedSecretsPath, "workflow-node", containerTargetDir)
err = creworkflow.CopyArtifactsToDockerContainers(encryptedSecretsPath, "workflow-node", containerTargetDir)
require.NoError(t, err, "failed to copy secrets")

// Register workflow with secrets
Expand Down
Loading
Loading