Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/deployment-memory-solana' into t…
Browse files Browse the repository at this point in the history
…t/homeChain
  • Loading branch information
tt-cll committed Jan 8, 2025
2 parents 954fef1 + 75bf435 commit 715f213
Show file tree
Hide file tree
Showing 17 changed files with 360 additions and 410 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("ccip_router")
programID, err := chain.DeployProgram("ccip_router")
if err != nil {
return fmt.Errorf("failed to deploy program: %v", err)
}
Expand Down
109 changes: 13 additions & 96 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,11 +74,8 @@ func setDevNet(keypairPath string) error {

// TestDeployProgram is a test for deploying the Solana program.
func TestDeployProgram(t *testing.T) {
// 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
// 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 @@ -105,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("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 @@ -120,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 @@ -142,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 @@ -226,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("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 @@ -272,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 @@ -282,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)
}
1 change: 1 addition & 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
10 changes: 7 additions & 3 deletions 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 @@ -167,15 +168,18 @@ func NewSolChains(logger logger.Logger, configs []ChainConfig) (map[uint64]deplo
if ec == nil {
return nil, fmt.Errorf("failed to connect to chain %s", chainCfg.ChainName)
}
// chainInfo, err := deployment.ChainInfo(selector)
// TODO: fetch this from chainConfig, together with KeypairPath
adminPrivateKey, err := solana.NewRandomPrivateKey()
if err != nil {
return nil, fmt.Errorf("failed to get chain info for chain %s: %w", chainCfg.ChainName, err)
return nil, err
}
adminPrivateKey := deployment.GetSolanaDeployerKey()
chains[selector] = deployment.SolChain{
Selector: selector,
Client: ec,
URL: chainCfg.HTTPRPCs[0],
WSURL: chainCfg.WSRPCs[0],
DeployerKey: &adminPrivateKey,
KeypairPath: "TODO",
Confirm: func(instructions []solana.Instruction, opts ...solCommomUtil.TxModifier) error {
_, err := solCommomUtil.SendAndConfirm(
context.Background(), ec, instructions, adminPrivateKey, solRpc.CommitmentConfirmed, opts...,
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
78 changes: 44 additions & 34 deletions deployment/environment/memory/chain.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package memory

import (
"bytes"
"math/big"
"os/exec"
"strconv"
"testing"
"time"
Expand All @@ -13,14 +11,19 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient/simulated"
"github.com/gagliardetto/solana-go"
solRpc "github.com/gagliardetto/solana-go/rpc"
"github.com/hashicorp/consul/sdk/freeport"
"github.com/stretchr/testify/require"
"github.com/test-go/testify/assert"

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

"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 All @@ -30,6 +33,13 @@ type EVMChain struct {
Users []*bind.TransactOpts
}

type SolChain struct {
Backend *solRpc.Client
URL string
WSURL string
DeployerKey solana.PrivateKey
}

func fundAddress(t *testing.T, from *bind.TransactOpts, to common.Address, amount *big.Int, backend *simulated.Backend) {
ctx := tests.Context(t)
nonce, err := backend.Client().PendingNonceAt(ctx, from.From)
Expand Down Expand Up @@ -96,43 +106,38 @@ func evmChain(t *testing.T, numUsers int) EVMChain {

// TODO: make it random port to support multiple chains
// TODO: add dynamic users and admin like done in evmChain
func solChain(t *testing.T) (string, string) {
func solChain(t *testing.T) SolChain {
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(),

// 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

port := freeport.GetOne(t)

bcInput := &blockchain.Input{
Type: "solana",
// TODO: randomize port
ChainID: chainselectors.SOLANA_DEVNET.ChainID,
PublicKey: deployerKey.PublicKey().String(),
Port: strconv.Itoa(port),
// TODO: ContractsDir & SolanaPrograms via env vars
}
output, err := blockchain.NewBlockchainNetwork(bcInput)
require.NoError(t, err)

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())
}
}
})
url := output.Nodes[0].HostHTTPUrl
wsURL := output.Nodes[0].HostWSUrl

// Wait for api server to boot
client := solRpc.New(url)
var ready bool
for i := 0; i < 30; i++ {
time.Sleep(time.Second)
client := solRpc.New(url)
out, err := client.GetHealth(tests.Context(t))
if err != nil || out != solRpc.HealthOk {
t.Logf("API server not ready yet (attempt %d)\n", i+1)
Expand All @@ -142,10 +147,15 @@ func solChain(t *testing.T) (string, string) {
break
}
if !ready {
t.Logf("Cmd output: %s\nCmd error: %s\n", stdOut.String(), stdErr.String())
t.Logf("solana-test-validator is not ready after 30 attempts")
}
require.True(t, ready)
t.Logf("solana-test-validator is ready at %s", url)

return url, wsURL
return SolChain{
Backend: client,
URL: url,
WSURL: wsURL,
DeployerKey: deployerKey,
}
}
Loading

0 comments on commit 715f213

Please sign in to comment.