Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Updated TestChainComponents to utilize ChainWriter #993

Open
wants to merge 25 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
95b3038
Added Address searcher for decoded data
silaslenihan Oct 25, 2024
320b3d6
Introduced new Solana config
silaslenihan Oct 28, 2024
957bc88
Completed iteration of ChainWriter config
silaslenihan Oct 29, 2024
fe9946f
Created sample configuration for execute method
silaslenihan Oct 30, 2024
b4a11d2
Cleaned up exec config and added comments
silaslenihan Oct 30, 2024
deaba61
Added commit report config example
silaslenihan Nov 4, 2024
fb906a2
Updated ChainWriter implementation to reflect new design changes
silaslenihan Nov 15, 2024
1b873b8
Added codec implementation
silaslenihan Nov 18, 2024
b9ab05c
updated CCIP example
silaslenihan Nov 19, 2024
fe4d467
unit tests for lookups
silaslenihan Nov 21, 2024
4db5108
Added utils to their own package
silaslenihan Nov 21, 2024
b45d396
Updated lookup tests and helpers
silaslenihan Nov 25, 2024
f5a3174
Removed helpers_test
silaslenihan Nov 25, 2024
c53ce3a
refactored ccip example
silaslenihan Nov 25, 2024
5a76e2c
Completed chained lookup integration test
silaslenihan Nov 26, 2024
5b17978
ChainWriter unit tests (#948)
amit-momin Dec 9, 2024
f6aa6d9
merged with develop
silaslenihan Dec 11, 2024
0723ba6
Removed write_test and moved logic to contract_reader_interface test …
silaslenihan Dec 12, 2024
f9a3e7e
addressed feedback comments
silaslenihan Dec 13, 2024
fea1487
solved conflicts between TXM changes and unit test changes
silaslenihan Dec 19, 2024
8ddccaf
updated comments and slight tweaks
silaslenihan Dec 20, 2024
cf148a9
Updated PDALookups Seeds field and fixed default accounts
silaslenihan Dec 27, 2024
bfa1f8d
Updated codec usage
silaslenihan Dec 30, 2024
52c4ef4
updated comments and slight tweaks
silaslenihan Dec 20, 2024
d7ed88e
Got ChainComponentsTests working with ChainWriter
silaslenihan Dec 27, 2024
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
36 changes: 18 additions & 18 deletions contracts/generated/contract_reader_interface/Initialize.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions contracts/programs/contract-reader-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ pub mod contract_reader_interface {
#[derive(Accounts)]
#[instruction(test_idx: u64)]
pub struct Initialize<'info> {
#[account(mut)]
pub signer: Signer<'info>,

// derived test PDA
#[account(
init,
Expand All @@ -44,9 +47,6 @@ pub struct Initialize<'info> {
bump)]
pub data: Account<'info, DataAccount>,

#[account(mut)]
pub signer: Signer<'info>,

pub system_program: Program<'info, System>,
}

Expand Down
178 changes: 101 additions & 77 deletions integration-tests/relayinterface/chain_components_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"context"
"encoding/binary"
"encoding/json"
"io"
"os"
"path/filepath"
"sync"
Expand All @@ -17,15 +16,18 @@ import (
"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/rpc"
"github.com/gagliardetto/solana-go/rpc/ws"
"github.com/gagliardetto/solana-go/text"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"

commoncodec "github.com/smartcontractkit/chainlink-common/pkg/codec"
commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
commontestutils "github.com/smartcontractkit/chainlink-common/pkg/loop/testutils"
"github.com/smartcontractkit/chainlink-common/pkg/services/servicetest"
"github.com/smartcontractkit/chainlink-common/pkg/types"
. "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with .
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"

"github.com/smartcontractkit/chainlink-solana/pkg/solana/codec"
Expand All @@ -34,7 +36,11 @@ import (
"github.com/smartcontractkit/chainlink-solana/integration-tests/solclient"
"github.com/smartcontractkit/chainlink-solana/integration-tests/utils"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/chainreader"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/chainwriter"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/client"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/config"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/txm"
keyMocks "github.com/smartcontractkit/chainlink-solana/pkg/solana/txm/mocks"
solanautils "github.com/smartcontractkit/chainlink-solana/pkg/solana/utils"
)

Expand Down Expand Up @@ -127,14 +133,17 @@ type SolanaChainComponentsInterfaceTesterHelper[T TestingT[T]] interface {
Context(t T) context.Context
Logger(t T) logger.Logger
GetJSONEncodedIDL(t T) []byte
CreateAccount(t T, value uint64) solana.PublicKey
CreateAccount(t T, it SolanaChainComponentsInterfaceTester[T], value uint64) solana.PublicKey
TXM() *txm.TxManager
SolanaClient() *client.Client
}

type SolanaChainComponentsInterfaceTester[T TestingT[T]] struct {
TestSelectionSupport
Helper SolanaChainComponentsInterfaceTesterHelper[T]
cr *chainreader.SolanaChainReaderService
contractReaderConfig config.ContractReader
chainWriterConfig chainwriter.ChainWriterConfig
}

func (it *SolanaChainComponentsInterfaceTester[T]) Setup(t T) {
Expand Down Expand Up @@ -173,6 +182,41 @@ func (it *SolanaChainComponentsInterfaceTester[T]) Setup(t T) {
},
},
}

it.chainWriterConfig = chainwriter.ChainWriterConfig{
Programs: map[string]chainwriter.ProgramConfig{
AnyContractName: {
IDL: string(it.Helper.GetJSONEncodedIDL(t)),
Methods: map[string]chainwriter.MethodConfig{
"initialize": {
FromAddress: solana.MustPrivateKeyFromBase58(solclient.DefaultPrivateKeysSolValidator[1]).PublicKey().String(),
InputModifications: nil,
ChainSpecificName: "initialize",
LookupTables: chainwriter.LookupTables{},
Accounts: []chainwriter.Lookup{
chainwriter.PDALookups{
Name: "Account",
PublicKey: chainwriter.AccountConstant{
Name: "ProgramID",
Address: programPubKey,
},
Seeds: []chainwriter.Seed{
{Static: []byte("data")},
{Dynamic: chainwriter.AccountLookup{
Name: "TestIDX",
Location: "TestIdx",
}},
},
IsWritable: true,
IsSigner: false,
},
},
DebugIDLocation: "",
},
},
},
},
}
}

func (it *SolanaChainComponentsInterfaceTester[T]) Name() string {
Expand Down Expand Up @@ -204,14 +248,18 @@ func (it *SolanaChainComponentsInterfaceTester[T]) GetContractReader(t T) types.
}

func (it *SolanaChainComponentsInterfaceTester[T]) GetContractWriter(t T) types.ContractWriter {
return nil
cw, err := chainwriter.NewSolanaChainWriterService(it.Helper.Logger(t), it.Helper.SolanaClient(), *it.Helper.TXM(), nil, it.chainWriterConfig)
require.NoError(t, err)

servicetest.Run(t, cw)
return cw
}

func (it *SolanaChainComponentsInterfaceTester[T]) GetBindings(t T) []types.BoundContract {
// Create a new account with fresh state for each test
return []types.BoundContract{
{Name: AnyContractName, Address: it.Helper.CreateAccount(t, AnyValueToReadWithoutAnArgument).String()},
{Name: AnySecondContractName, Address: it.Helper.CreateAccount(t, AnyDifferentValueToReadWithoutAnArgument).String()},
{Name: AnyContractName, Address: it.Helper.CreateAccount(t, *it, AnyValueToReadWithoutAnArgument).String()},
{Name: AnySecondContractName, Address: it.Helper.CreateAccount(t, *it, AnyDifferentValueToReadWithoutAnArgument).String()},
}
}

Expand All @@ -234,6 +282,8 @@ type helper struct {
idlBts []byte
nonce uint64
nonceMu sync.Mutex
txm txm.TxManager
sc *client.Client
}

func (h *helper) Init(t *testing.T) {
Expand All @@ -250,6 +300,27 @@ func (h *helper) Init(t *testing.T) {

solanautils.FundAccounts(t, []solana.PrivateKey{privateKey}, h.rpcClient)

cfg := config.NewDefault()
cfg.Chain.TxRetentionTimeout = commonconfig.MustNewDuration(10 * time.Minute)
solanaClient, err := client.NewClient(h.rpcURL, cfg, 5*time.Second, nil)
require.NoError(t, err)

h.sc = solanaClient

loader := commonutils.NewLazyLoad(func() (client.ReaderWriter, error) { return solanaClient, nil })
mkey := keyMocks.NewSimpleKeystore(t)
mkey.On("Sign", mock.Anything, privateKey.PublicKey().String(), mock.Anything).Return(func(_ context.Context, _ string, data []byte) []byte {
sig, _ := privateKey.Sign(data)
return sig[:]
}, nil)
lggr := logger.Test(t)

txm := txm.NewTxm("localnet", loader, nil, cfg, mkey, lggr)
err = txm.Start(tests.Context(t))
require.NoError(t, err)

h.txm = txm

pubkey, err := solana.PublicKeyFromBase58(programPubKey)
require.NoError(t, err)

Expand All @@ -261,6 +332,14 @@ func (h *helper) RPCClient() *chainreader.RPCClientWrapper {
return &chainreader.RPCClientWrapper{Client: h.rpcClient}
}

func (h *helper) TXM() *txm.TxManager {
return &h.txm
}

func (h *helper) SolanaClient() *client.Client {
return h.sc
}

func (h *helper) Context(t *testing.T) context.Context {
return tests.Context(t)
}
Expand Down Expand Up @@ -292,7 +371,7 @@ func (h *helper) GetJSONEncodedIDL(t *testing.T) []byte {
return h.idlBts
}

func (h *helper) CreateAccount(t *testing.T, value uint64) solana.PublicKey {
func (h *helper) CreateAccount(t *testing.T, it SolanaChainComponentsInterfaceTester[*testing.T], value uint64) solana.PublicKey {
t.Helper()

// avoid collisions in parallel tests
Expand All @@ -307,90 +386,35 @@ func (h *helper) CreateAccount(t *testing.T, value uint64) solana.PublicKey {
pubKey, _, err := solana.FindProgramAddress([][]byte{[]byte("data"), bts}, h.programID)
require.NoError(t, err)

// Getting the default localnet private key
privateKey, err := solana.PrivateKeyFromBase58(solclient.DefaultPrivateKeysSolValidator[1])
require.NoError(t, err)

h.runInitialize(t, nonce, value, pubKey, func(key solana.PublicKey) *solana.PrivateKey {
return &privateKey
}, privateKey.PublicKey())
h.runInitialize(t, it, nonce, value)

return pubKey
}

type InitializeArgs struct {
TestIdx uint64
Value uint64
}

func (h *helper) runInitialize(
t *testing.T,
it SolanaChainComponentsInterfaceTester[*testing.T],
nonce uint64,
value uint64,
data solana.PublicKey,
signerFunc func(key solana.PublicKey) *solana.PrivateKey,
payer solana.PublicKey,
) {
t.Helper()

inst, err := contract.NewInitializeInstruction(nonce*value, value, data, payer, solana.SystemProgramID).ValidateAndBuild()
require.NoError(t, err)
cw := it.GetContractWriter(t)

h.sendInstruction(t, inst, signerFunc, payer)
}

func (h *helper) sendInstruction(
t *testing.T,
inst *contract.Instruction,
signerFunc func(key solana.PublicKey) *solana.PrivateKey,
payer solana.PublicKey,
) {
t.Helper()

ctx := tests.Context(t)

recent, err := h.rpcClient.GetLatestBlockhash(ctx, rpc.CommitmentFinalized)
require.NoError(t, err)

tx, err := solana.NewTransaction(
[]solana.Instruction{
inst,
},
recent.Value.Blockhash,
solana.TransactionPayer(payer),
)
require.NoError(t, err)

_, err = tx.EncodeTree(text.NewTreeEncoder(io.Discard, "Initialize"))
require.NoError(t, err)

_, err = tx.Sign(signerFunc)
require.NoError(t, err)

sig, err := h.rpcClient.SendTransactionWithOpts(
ctx, tx,
rpc.TransactionOpts{
PreflightCommitment: rpc.CommitmentConfirmed,
},
)
require.NoError(t, err)

h.waitForTX(t, sig, rpc.CommitmentFinalized)
}

func (h *helper) waitForTX(t *testing.T, sig solana.Signature, commitment rpc.CommitmentType) {
t.Helper()

sub, err := h.wsClient.SignatureSubscribe(
sig,
commitment,
)
require.NoError(t, err)
args := InitializeArgs{
TestIdx: nonce * value,
Value: value,
}

defer sub.Unsubscribe()
buf := make([]byte, 8)
binary.LittleEndian.PutUint64(buf, nonce*value)

res, err := sub.Recv()
require.NoError(t, err)

if res.Value.Err != nil {
t.Logf("transaction confirmation failed: %v", res.Value.Err)
t.FailNow()
}
SubmitTransactionToCW(t, &it, cw, "initialize", args, types.BoundContract{Name: AnyContractName, Address: h.programID.String()}, types.Finalized)
}

func mustUnmarshalIDL[T TestingT[T]](t T, rawIDL string) codec.IDL {
Expand Down
Loading
Loading