Skip to content

Commit

Permalink
Use the memory environment on deploy tests too
Browse files Browse the repository at this point in the history
  • Loading branch information
archseer committed Jan 8, 2025
1 parent 334079b commit 7a5f109
Show file tree
Hide file tree
Showing 10 changed files with 44 additions and 122 deletions.
2 changes: 1 addition & 1 deletion deployment/ccip/changeset/cs_deploy_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ func deployChainContractsSolana(
if chainState.CcipRouter.IsZero() {
// deploy and initialize router

programID, err := deployment.DeploySolProgramCLI(chain, "ccip_router")
programID, err := chain.DeployProgram("ccip_router")
if err != nil {
return fmt.Errorf("failed to deploy program: %v", err)
}
Expand Down
112 changes: 13 additions & 99 deletions deployment/common/changeset/deploy_link_token_sol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,22 @@ package changeset_test

import (
"context"
"strconv"
"testing"
"time"

"bytes"
"fmt"
"os/exec"

// "github.com/stretchr/testify/require"
// "go.uber.org/zap/zapcore"
// "github.com/smartcontractkit/chainlink/deployment/common/changeset"
// "github.com/smartcontractkit/chainlink/deployment/environment/memory"
// "github.com/smartcontractkit/chainlink/v2/core/logger"
bin "github.com/gagliardetto/binary"
"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/rpc"
"github.com/smartcontractkit/chainlink-ccip/chains/solana/contracts/tests/config"
"github.com/smartcontractkit/chainlink-ccip/chains/solana/contracts/tests/testutils"
"github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/ccip_router"
"github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/external_program_cpi_stub"
"github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
"github.com/smartcontractkit/chainlink/deployment"
"github.com/smartcontractkit/chainlink/deployment/environment/memory"
"github.com/stretchr/testify/require"
"github.com/test-go/testify/assert"
)

var (
Expand Down Expand Up @@ -83,14 +74,8 @@ func setDevNet(keypairPath string) error {

// TestDeployProgram is a test for deploying the Solana program.
func TestDeployProgram(t *testing.T) {
// TODO: spin up proper env remove setDevNet/spinUpDevNet

// Path to your .so file and keypair file
// programFile := "/Users/yashvardhan/chainlink-internal-integrations/solana/contracts/target/deploy/external_program_cpi_stub.so"
keypairPath := "/Users/yashvardhan/.config/solana/id.json" //wallet
// TODO:
// programKeyPair := "/Users/yashvardhan/chainlink-internal-integrations/solana/contracts/target/deploy/external_program_cpi_stub-keypair.json"
// keypairPath := "/Users/yashvardhan/chainlink-internal-integrations/solana/contracts/target/deploy/external_program_cpi_stub-keypair.json"
chains := memory.NewMemoryChainsSol(t)
chain := chains[deployment.SolanaChainSelector]

ExternalCpiStubProgram := solana.MustPublicKeyFromBase58("EQPCTRibpsPcQNb464QVBkS1PkFfuK8kYdpd5Y17HaGh")
solanaGoClient := rpc.New("http://127.0.0.1:8899")
Expand All @@ -108,7 +93,7 @@ func TestDeployProgram(t *testing.T) {
} else {
fmt.Println("Program does not exist or is not executable.")
// Deploy the program
programID, err := deployment.DeploySolProgramCLI(chain, "external_program_cpi_stub")
programID, err := chain.DeployProgram("external_program_cpi_stub")
if err != nil {
t.Fatalf("Failed to deploy program: %v", err)
}
Expand All @@ -123,10 +108,6 @@ func TestDeployProgram(t *testing.T) {
// program should exist by now (either already deployed, or deployed and waited for confirmation)
external_program_cpi_stub.SetProgramID(ExternalCpiStubProgram)

// wallet keys
privateKey, _ := solana.PrivateKeyFromSolanaKeygenFile(keypairPath)
publicKey := privateKey.PublicKey()

// this is a PDA that gets initialised when you call init on the programID
StubAccountPDA, _, _ := solana.FindProgramAddress([][]byte{[]byte("u8_value")}, ExternalCpiStubProgram)
t.Logf("StubAccountPDA %s", StubAccountPDA)
Expand All @@ -145,76 +126,16 @@ func TestDeployProgram(t *testing.T) {
fmt.Println("Account does not exist or has no data.")
ix, err = external_program_cpi_stub.NewInitializeInstruction(
StubAccountPDA,
publicKey,
chain.DeployerKey.PublicKey(),
solana.SystemProgramID, // 1111111
).ValidateAndBuild()
}

_, err = common.SendAndConfirm(context.Background(), solanaGoClient, []solana.Instruction{ix}, privateKey, config.DefaultCommitment)
_, err = common.SendAndConfirm(context.Background(), solanaGoClient, []solana.Instruction{ix}, *chain.DeployerKey, config.DefaultCommitment)

require.NoError(t, err)
}

func spinUpDevNet(t *testing.T) (string, string) {
t.Helper()
port := "8899"
portInt, _ := strconv.Atoi(port)

faucetPort := "8877"
url := "http://127.0.0.1:" + port
wsURL := "ws://127.0.0.1:" + strconv.Itoa(portInt+1)

args := []string{
"--reset",
"--rpc-port", port,
"--faucet-port", faucetPort,
"--ledger", t.TempDir(),
}

cmd := exec.Command("solana-test-validator", args...)

var stdErr bytes.Buffer
cmd.Stderr = &stdErr
var stdOut bytes.Buffer
cmd.Stdout = &stdOut
require.NoError(t, cmd.Start())
t.Cleanup(func() {
assert.NoError(t, cmd.Process.Kill())
if err2 := cmd.Wait(); assert.Error(t, err2) {
if !assert.Contains(t, err2.Error(), "signal: killed", cmd.ProcessState.String()) {
t.Logf("solana-test-validator\n stdout: %s\n stderr: %s", stdOut.String(), stdErr.String())
}
}
})

// Wait for api server to boot
var ready bool
for i := 0; i < 30; i++ {
time.Sleep(time.Second)
client := rpc.New(url)
out, err := client.GetHealth(tests.Context(t))
if err != nil || out != rpc.HealthOk {
t.Logf("API server not ready yet (attempt %d)\n", i+1)
continue
}
ready = true
break
}
if !ready {
t.Logf("Cmd output: %s\nCmd error: %s\n", stdOut.String(), stdErr.String())
}
require.True(t, ready)
t.Logf("Solana Devnet spun up successfully")

return url, wsURL
}

func getRpcClient(t *testing.T) *rpc.Client {
url, _ := spinUpDevNet(t)
// url, _ := memory.solChain(t)
return rpc.New(url)
}

// Added TestDeployLinkTokenSol -> so this is not required anymore
// func TestTokenDeploy(t *testing.T) {
// solanaGoClient := getRpcClient(t)
Expand All @@ -229,32 +150,25 @@ func getRpcClient(t *testing.T) *rpc.Client {
// }

func TestCcipRouterDeploy(t *testing.T) {
// Path to your .so file and keypair file
// programFile := "/Users/ttata/dev/chainlink-ccip/chains/solana/contracts/target/deploy/ccip_router.so"
keypairPath := "/Users/yashvardhan/.config/solana/id.json" //wallet
// programKeyPair := "/Users/ttata/dev/chainlink-ccip/chains/solana/contracts/target/deploy/ccip_router-keypair.json"
chains := memory.NewMemoryChainsSol(t)
chain := chains[deployment.SolanaChainSelector]

adminPrivateKey, _ := solana.PrivateKeyFromSolanaKeygenFile(keypairPath)
adminPublicKey := adminPrivateKey.PublicKey()
solanaGoClient := getRpcClient(t)
err := setDevNet(keypairPath)
require.NoError(t, err)
ctx := context.Background()
testutils.FundAccounts(ctx, []solana.PrivateKey{adminPrivateKey}, solanaGoClient, t)
// testutils.FundAccounts(ctx, []solana.PrivateKey{adminPrivateKey}, solanaGoClient, t)

// get program data account before deploying, hitting NotFound error
// data, err := solanaGoClient.GetAccountInfoWithOpts(ctx, CcipRouterProgram, &rpc.GetAccountInfoOpts{
// Commitment: DefaultCommitment,
// })
// require.ErrorAs(t, err, &rpc.ErrNotFound)
// Deploy the program
programID, err := deployment.DeploySolProgramCLI(chain, "ccip_router")
programID, err := chain.DeployProgram("ccip_router")
CcipRouterProgram := solana.MustPublicKeyFromBase58(programID)
if err != nil {
t.Fatalf("Failed to deploy program: %v", err)
}
// get program data account
data, err := solanaGoClient.GetAccountInfoWithOpts(ctx, CcipRouterProgram, &rpc.GetAccountInfoOpts{
data, err := chain.Client.GetAccountInfoWithOpts(ctx, CcipRouterProgram, &rpc.GetAccountInfoOpts{
Commitment: DefaultCommitment,
})
require.NoError(t, err)
Expand All @@ -275,7 +189,7 @@ func TestCcipRouterDeploy(t *testing.T) {
EnableExecutionAfter, // period to wait before allowing manual execution
RouterConfigPDA,
RouterStatePDA,
adminPublicKey,
chain.DeployerKey.PublicKey(),
solana.SystemProgramID,
CcipRouterProgram,
programData.Address,
Expand All @@ -285,7 +199,7 @@ func TestCcipRouterDeploy(t *testing.T) {
require.NoError(t, err)

// skip preflight, txs with init PDAs will fail preflight
_, err = common.SendAndConfirm(ctx, solanaGoClient, []solana.Instruction{instruction}, adminPrivateKey, DefaultCommitment)
_, err = common.SendAndConfirm(ctx, chain.Client, []solana.Instruction{instruction}, *chain.DeployerKey, DefaultCommitment)
require.NoError(t, err)
t.Logf("Program deployed successfully with ID: %s", programID)
}
2 changes: 2 additions & 0 deletions deployment/environment/crib/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package crib

import (
"context"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink/deployment"
"github.com/smartcontractkit/chainlink/deployment/environment/devenv"
Expand Down Expand Up @@ -32,6 +33,7 @@ func NewDeployEnvironmentFromCribOutput(lggr logger.Logger, output DeployOutput)
lggr,
output.AddressBook,
chains,
nil,
output.NodeIDs,
nil, // todo: populate the offchain client using output.DON
func() context.Context { return context.Background() }, deployment.XXXGenerateTestOCRSecrets(),
Expand Down
6 changes: 5 additions & 1 deletion deployment/environment/devenv/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

"github.com/gagliardetto/solana-go"
solRpc "github.com/gagliardetto/solana-go/rpc"

solCommomUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common"
"github.com/smartcontractkit/chainlink/deployment"
)
Expand Down Expand Up @@ -168,7 +169,10 @@ func NewSolChains(logger logger.Logger, configs []ChainConfig) (map[uint64]deplo
return nil, fmt.Errorf("failed to connect to chain %s", chainCfg.ChainName)
}
// TODO: fetch this from chainConfig, together with KeypairPath
adminPrivateKey := deployment.GetSolanaDeployerKey()
adminPrivateKey, err := solana.NewRandomPrivateKey()
if err != nil {
return nil, err
}
chains[selector] = deployment.SolChain{
Selector: selector,
Client: ec,
Expand Down
4 changes: 3 additions & 1 deletion deployment/environment/devenv/don.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import (
"context"
"errors"
"fmt"
chainsel "github.com/smartcontractkit/chain-selectors"
"strconv"
"strings"
"time"

chainsel "github.com/smartcontractkit/chain-selectors"

"github.com/hashicorp/go-multierror"
"github.com/rs/zerolog"
"github.com/sethvargo/go-retry"

nodev1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node"
clclient "github.com/smartcontractkit/chainlink/deployment/environment/nodeclient"
"github.com/smartcontractkit/chainlink/deployment/environment/web/sdk/client"
Expand Down
10 changes: 8 additions & 2 deletions deployment/environment/memory/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"

chainselectors "github.com/smartcontractkit/chain-selectors"

"github.com/smartcontractkit/chainlink-testing-framework/framework"
"github.com/smartcontractkit/chainlink-testing-framework/framework/components/blockchain"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
)
Expand Down Expand Up @@ -105,6 +107,10 @@ func evmChain(t *testing.T, numUsers int) EVMChain {
func solChain(t *testing.T) SolChain {
t.Helper()

// initialize the docker network used by CTF
// TODO: framework.DefaultNetwork(once) is broken for me, use a static name for now
framework.DefaultNetworkName = "chainlink"

deployerKey, err := solana.NewRandomPrivateKey()
require.NoError(t, err)
// TODO: fund this key
Expand All @@ -117,11 +123,11 @@ func solChain(t *testing.T) SolChain {
// TODO: ContractsDir & SolanaPrograms via env vars
}
output, err := blockchain.NewBlockchainNetwork(bcInput)
require.NoError(t, err)

url := output.Nodes[0].HostHTTPUrl
wsURL := output.Nodes[0].HostWSUrl

require.NoError(t, err)

// Wait for api server to boot
client := solRpc.New(url)
var ready bool
Expand Down
8 changes: 5 additions & 3 deletions deployment/environment/memory/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/smartcontractkit/chainlink/deployment"

solRpc "github.com/gagliardetto/solana-go/rpc"

solCommomUtil "github.com/smartcontractkit/chainlink-ccip/chains/solana/utils/common"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
)
Expand Down Expand Up @@ -129,13 +130,13 @@ func NewNodes(t *testing.T, logLevel zapcore.Level, chains map[uint64]deployment
// since we won't run a bootstrapper and a plugin oracle on the same
// chainlink node in production.
for i := 0; i < numBootstraps; i++ {
node := NewNode(t, ports[i], chains, logLevel, true /* bootstrap */, registryConfig)
node := NewNode(t, ports[i], chains, nil, logLevel, true /* bootstrap */, registryConfig)
nodesByPeerID[node.Keys.PeerID.String()] = *node
// Note in real env, this ID is allocated by JD.
}
for i := 0; i < numNodes; i++ {
// grab port offset by numBootstraps, since above loop also takes some ports.
node := NewNode(t, ports[numBootstraps+i], chains, logLevel, false /* bootstrap */, registryConfig)
node := NewNode(t, ports[numBootstraps+i], chains, nil, logLevel, false /* bootstrap */, registryConfig)
nodesByPeerID[node.Keys.PeerID.String()] = *node
// Note in real env, this ID is allocated by JD.
}
Expand Down Expand Up @@ -204,7 +205,8 @@ func NewMemoryChainsSol(t *testing.T) map[uint64]deployment.SolChain {
bytes, err := json.Marshal([]byte(chain.DeployerKey))
require.NoError(t, err)
keypairPath := path.Join(t.TempDir(), "solana-keypair.json")
os.WriteFile(keypairPath, bytes, 0644)
err = os.WriteFile(keypairPath, bytes, 0644)

Check failure on line 208 in deployment/environment/memory/environment.go

View workflow job for this annotation

GitHub Actions / GolangCI Lint (deployment)

G306: Expect WriteFile permissions to be 0600 or less (gosec)
require.NoError(t, err)

newSolChain := deployment.SolChain{
Selector: solChainSelector,
Expand Down
2 changes: 1 addition & 1 deletion deployment/environment/memory/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
func TestNode(t *testing.T) {
chains, _ := NewMemoryChains(t, 3, 5)
ports := freeport.GetN(t, 1)
node := NewNode(t, ports[0], chains, zapcore.DebugLevel, false, deployment.CapabilityRegistryConfig{})
node := NewNode(t, ports[0], chains, nil, zapcore.DebugLevel, false, deployment.CapabilityRegistryConfig{})
// We expect 3 transmitter keys
keys, err := node.App.GetKeyStore().Eth().GetAll(tests.Context(t))
require.NoError(t, err)
Expand Down
7 changes: 4 additions & 3 deletions deployment/environment/web/sdk/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/Khan/genqlient/graphql"
"github.com/sethvargo/go-retry"
"net/http"
"strings"
"time"

"github.com/Khan/genqlient/graphql"
"github.com/sethvargo/go-retry"

"github.com/smartcontractkit/chainlink/deployment/environment/web/sdk/client/doer"
"github.com/smartcontractkit/chainlink/deployment/environment/web/sdk/internal/generated"
)
Expand Down Expand Up @@ -61,7 +62,7 @@ func New(baseURI string, creds Credentials) (Client, error) {
endpoints: ep,
credentials: creds,
}

err := retry.Do(context.Background(), retry.WithMaxDuration(10*time.Second, retry.NewFibonacci(2*time.Second)), func(ctx context.Context) error {
err := c.login()
if err != nil {
Expand Down
13 changes: 2 additions & 11 deletions deployment/solana_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,22 +55,13 @@ func (c SolChain) Name() string {
return chainInfo.ChainName
}

type SolClient interface {
}

type ContractDeploySolana struct {
ProgramID *solana.PublicKey // We leave this incase a Go binding doesn't have Address()
Tv TypeAndVersion
Err error
}

func DeploySolProgramCLI(chain SolChain, programName string) (string, error) {
func (c SolChain) DeployProgram(programName string) (string, error) {
programFile := fmt.Sprintf("%s/%s.so", deployBinPath, programName)
programKeyPair := fmt.Sprintf("%s/%s-keypair.json", deployBinPath, programName)

// Construct the CLI command: solana program deploy
// TODO: @terry doing this on the fly
cmd := exec.Command("solana", "program", "deploy", programFile, "--keypair", chain.KeypairPath, "--program-id", programKeyPair)
cmd := exec.Command("solana", "program", "deploy", programFile, "--keypair", c.KeypairPath, "--program-id", programKeyPair)

// Capture the command output
var stdout, stderr bytes.Buffer
Expand Down

0 comments on commit 7a5f109

Please sign in to comment.