From aa71d847eef9e5eaf997e9cd4be5e483daf2a2f2 Mon Sep 17 00:00:00 2001 From: Silas Lenihan Date: Mon, 27 Jan 2025 11:16:58 -0500 Subject: [PATCH] Updated PDALookup internal field to use codec --- go.sum | 4 + pkg/solana/chainwriter/ccip_example_config.go | 2 - pkg/solana/chainwriter/chain_writer_test.go | 176 +++++++++++------- 3 files changed, 116 insertions(+), 66 deletions(-) diff --git a/go.sum b/go.sum index a7806718e..6116fab5c 100644 --- a/go.sum +++ b/go.sum @@ -606,6 +606,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -617,6 +618,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.7.5/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= diff --git a/pkg/solana/chainwriter/ccip_example_config.go b/pkg/solana/chainwriter/ccip_example_config.go index 5f0e01b5c..cd7a844a6 100644 --- a/pkg/solana/chainwriter/ccip_example_config.go +++ b/pkg/solana/chainwriter/ccip_example_config.go @@ -1,8 +1,6 @@ package chainwriter import ( - "reflect" - "github.com/gagliardetto/solana-go" "github.com/smartcontractkit/chainlink-common/pkg/codec" ) diff --git a/pkg/solana/chainwriter/chain_writer_test.go b/pkg/solana/chainwriter/chain_writer_test.go index b23a0f4d9..9c984b69a 100644 --- a/pkg/solana/chainwriter/chain_writer_test.go +++ b/pkg/solana/chainwriter/chain_writer_test.go @@ -587,14 +587,6 @@ func TestChainWriter_SubmitTransaction(t *testing.T) { func TestChainWriter_CCIPRouter(t *testing.T) { t.Parallel() - ctx := tests.Context(t) - // mock client - rw := clientmocks.NewReaderWriter(t) - // mock estimator - ge := feemocks.NewEstimator(t) - // mock txm - txm := txmMocks.NewTxManager(t) - // setup admin key adminPk, err := solana.NewRandomPrivateKey() require.NoError(t, err) @@ -603,16 +595,9 @@ func TestChainWriter_CCIPRouter(t *testing.T) { routerAddr := chainwriter.GetRandomPubKey(t) destTokenAddr := chainwriter.GetRandomPubKey(t) - pda, _, err := solana.FindProgramAddress([][]byte{[]byte("token_admin_registry"), destTokenAddr.Bytes()}, routerAddr) - require.NoError(t, err) - - lookupTable := mockTokenAdminRegistryLookupTable(t, rw, pda) - poolKeys := []solana.PublicKey{destTokenAddr} poolKeys = append(poolKeys, chainwriter.CreateTestPubKeys(t, 3)...) - mockFetchLookupTableAddresses(t, rw, lookupTable, poolKeys) - // simplified CCIP Config - does not contain full account list ccipCWConfig := chainwriter.ChainWriterConfig{ Programs: map[string]chainwriter.ProgramConfig{ @@ -625,7 +610,7 @@ func TestChainWriter_CCIPRouter(t *testing.T) { Fields: map[string]string{"ReportContextByteWords": "ReportContext"}, }, &codec.RenameModifierConfig{ - Fields: map[string]string{"ExecutionReport": "AbstractReport"}, + Fields: map[string]string{"RawExecutionReport": "Report"}, }, }, ChainSpecificName: "execute", @@ -662,27 +647,70 @@ func TestChainWriter_CCIPRouter(t *testing.T) { }, }, }, + "commit": { + FromAddress: admin.String(), + InputModifications: []codec.ModifierConfig{ + &codec.RenameModifierConfig{ + Fields: map[string]string{"ReportContextByteWords": "ReportContext"}, + }, + &codec.RenameModifierConfig{ + Fields: map[string]string{"RawReport": "Report"}, + }, + }, + ChainSpecificName: "commit", + ArgsTransform: "", + LookupTables: chainwriter.LookupTables{}, + Accounts: []chainwriter.Lookup{ + chainwriter.AccountConstant{ + Name: "testAcc1", + Address: chainwriter.GetRandomPubKey(t).String(), + }, + chainwriter.AccountConstant{ + Name: "testAcc2", + Address: chainwriter.GetRandomPubKey(t).String(), + }, + chainwriter.AccountConstant{ + Name: "testAcc3", + Address: chainwriter.GetRandomPubKey(t).String(), + }, + }, + }, }, IDL: ccipRouterIDL, }, }, } - // initialize chain writer - cw, err := chainwriter.NewSolanaChainWriterService(testutils.NewNullLogger(), rw, txm, ge, ccipCWConfig) - require.NoError(t, err) + ctx := tests.Context(t) + // mock client + rw := clientmocks.NewReaderWriter(t) + // mock estimator + ge := feemocks.NewEstimator(t) - t.Run("ArgsTransform works", func(t *testing.T) { - txID := uuid.NewString() - recentBlockHash := solana.Hash{} + t.Run("CCIP execute is encoded successfully and ArgsTransform is applied correctly.", func(t *testing.T) { + // mock txm + txm := txmMocks.NewTxManager(t) + // initialize chain writer + cw, err := chainwriter.NewSolanaChainWriterService(testutils.NewNullLogger(), rw, txm, ge, ccipCWConfig) + require.NoError(t, err) + recentBlockHash := solana.Hash{} rw.On("LatestBlockhash", mock.Anything).Return(&rpc.GetLatestBlockhashResult{Value: &rpc.LatestBlockhashResult{Blockhash: recentBlockHash, LastValidBlockHeight: uint64(100)}}, nil).Once() + + pda, _, err := solana.FindProgramAddress([][]byte{[]byte("token_admin_registry"), destTokenAddr.Bytes()}, routerAddr) + require.NoError(t, err) + + lookupTable := mockTokenAdminRegistryLookupTable(t, rw, pda) + + mockFetchLookupTableAddresses(t, rw, lookupTable, poolKeys) + + txID := uuid.NewString() txm.On("Enqueue", mock.Anything, admin.String(), mock.MatchedBy(func(tx *solana.Transaction) bool { txData := tx.Message.Instructions[0].Data payload := txData[8:] var decoded ccip_router.Execute dec := ag_binary.NewBorshDecoder(payload) - err := dec.Decode(&decoded) + err = dec.Decode(&decoded) require.NoError(t, err) tokenIndexes := *decoded.TokenIndexes @@ -692,63 +720,83 @@ func TestChainWriter_CCIPRouter(t *testing.T) { return true }), &txID, mock.Anything).Return(nil).Once() - abstractReport := ccip_router.ExecutionReportSingleChain{ - SourceChainSelector: 1, - Message: ccip_router.Any2SVMRampMessage{ - Header: ccip_router.RampMessageHeader{ - MessageId: ccipocr3.Bytes32{0x1}, - SourceChainSelector: 1, - DestChainSelector: 2, - SequenceNumber: 1, - Nonce: 0, - }, - Sender: admin.Bytes(), - Data: ccipocr3.Bytes{0x1}, - LogicReceiver: chainwriter.GetRandomPubKey(t), - TokenReceiver: admin, - TokenAmounts: []ccip_router.Any2SVMTokenTransfer{ - { - SourcePoolAddress: chainwriter.GetRandomPubKey(t).Bytes(), - DestTokenAddress: destTokenAddr, - ExtraData: ccipocr3.Bytes{0x1}, - Amount: ccip_router.CrossChainAmount{LeBytes: [32]uint8{0x1}}, - DestGasAmount: 2, - }, - }, - ExtraArgs: ccip_router.SVMExtraArgs{ - ComputeUnits: 1, - IsWritableBitmap: 6, - Accounts: []solana.PublicKey{ - chainwriter.GetRandomPubKey(t), + // stripped back report just for purposes of example + abstractReport := ccipocr3.ExecutePluginReportSingleChain{ + Messages: []ccipocr3.Message{ + { + TokenAmounts: []ccipocr3.RampTokenAmount{ + { + DestTokenAddress: destTokenAddr.Bytes(), + }, }, }, - OnRampAddress: []byte{0x1}, }, - OffchainTokenData: [][]byte{{0x1}}, - Proofs: [][32]byte{{0x1}}, } // Marshal the abstract report to json just for testing purposes. - encodededReport, err := json.Marshal(abstractReport) + encodedReport, err := json.Marshal(abstractReport) require.NoError(t, err) args := chainwriter.ReportPreTransform{ - ReportContext: [3][32]uint8{{0x01, 0x02, 0x03}}, - Report: encodededReport, + ReportContext: [2][32]byte{{0x01}, {0x02}}, + Report: encodedReport, Info: ccipocr3.ExecuteReportInfo{ - { - ChainSel: 1, - OnRampAddress: chainwriter.GetRandomPubKey(t).Bytes(), - SeqNumsRange: ccipocr3.NewSeqNumRange(1, 2), - MerkleRoot: [32]byte{0x01, 0x02, 0x03}, - }, + MerkleRoots: []ccipocr3.MerkleRootChain{}, + AbstractReports: []ccipocr3.ExecutePluginReportSingleChain{abstractReport}, }, - AbstractReport: abstractReport, } submitErr := cw.SubmitTransaction(ctx, "ccip_router", "execute", args, txID, routerAddr.String(), nil, nil) require.NoError(t, submitErr) }) + + t.Run("CCIP commit is encoded successfully", func(t *testing.T) { + // mock txm + txm := txmMocks.NewTxManager(t) + // initialize chain writer + cw, err := chainwriter.NewSolanaChainWriterService(testutils.NewNullLogger(), rw, txm, ge, ccipCWConfig) + require.NoError(t, err) + + recentBlockHash := solana.Hash{} + rw.On("LatestBlockhash", mock.Anything).Return(&rpc.GetLatestBlockhashResult{Value: &rpc.LatestBlockhashResult{Blockhash: recentBlockHash, LastValidBlockHeight: uint64(100)}}, nil).Once() + + type CommitArgs struct { + ReportContext [2][32]byte + Report []byte + Rs [][32]byte + Ss [][32]byte + RawVs [32]byte + Info ccipocr3.CommitReportInfo + } + + txID := uuid.NewString() + + // TODO: Replace with actual type from ccipocr3 + args := CommitArgs{ + ReportContext: [2][32]byte{{0x01}, {0x02}}, + Report: []byte{0x01, 0x02}, + Rs: [][32]byte{{0x01, 0x02}}, + Ss: [][32]byte{{0x01, 0x02}}, + RawVs: [32]byte{0x01, 0x02}, + Info: ccipocr3.CommitReportInfo{ + RemoteF: 1, + MerkleRoots: []ccipocr3.MerkleRootChain{}, + }, + } + + txm.On("Enqueue", mock.Anything, admin.String(), mock.MatchedBy(func(tx *solana.Transaction) bool { + txData := tx.Message.Instructions[0].Data + payload := txData[8:] + var decoded ccip_router.Commit + dec := ag_binary.NewBorshDecoder(payload) + err := dec.Decode(&decoded) + require.NoError(t, err) + return true + }), &txID, mock.Anything).Return(nil).Once() + + submitErr := cw.SubmitTransaction(ctx, "ccip_router", "commit", args, txID, routerAddr.String(), nil, nil) + require.NoError(t, submitErr) + }) } func TestChainWriter_CCIPRouter(t *testing.T) {