Skip to content

Commit

Permalink
Added ExtraArgs ComputeLimit to CCIP Execute transform func
Browse files Browse the repository at this point in the history
  • Loading branch information
silaslenihan committed Feb 25, 2025
1 parent edc18d1 commit 1827cf6
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 34 deletions.
1 change: 0 additions & 1 deletion integration-tests/relayinterface/chain_components_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,6 @@ func RunChainWriterTests[T WrappedTestingT[T]](t T, it *SolanaChainComponentsInt
testIdx := binary.LittleEndian.AppendUint64([]byte{}, idx)
dataPDAAccount, _, err := solana.FindProgramAddress([][]byte{[]byte("data"), testIdx}, solana.MustPublicKeyFromBase58(bound.Address))
require.NoError(t, err)
fmt.Println("Data PDA Account", dataPDAAccount.Bytes())

// append random addresses to lookup table address list
lookupTableAddresses := make([]solana.PublicKey, 0, 10)
Expand Down
11 changes: 9 additions & 2 deletions pkg/solana/chainwriter/chain_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/smartcontractkit/chainlink-solana/pkg/solana/codec"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/fees"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/txm"
txmutils "github.com/smartcontractkit/chainlink-solana/pkg/solana/txm/utils"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/utils"
)

Expand Down Expand Up @@ -383,14 +384,15 @@ func (s *SolanaChainWriterService) SubmitTransaction(ctx context.Context, contra
// Filter the lookup table addresses based on which accounts are actually used
filteredLookupTableMap := s.FilterLookupTableAddresses(accounts, derivedTableMap, staticTableMap)

computeLimit := uint32(0)
// Transform args if necessary
if methodConfig.ArgsTransform != "" {
transformFunc, tfErr := FindTransform(methodConfig.ArgsTransform)
if tfErr != nil {
return errorWithDebugID(fmt.Errorf("error finding transform function: %w", tfErr), debugID)
}
s.lggr.Debugw("Applying args transformation", "contract", contractName, "method", method)
args, accounts, err = transformFunc(ctx, args, accounts, derivedTableMap)
args, accounts, computeLimit, err = transformFunc(ctx, args, accounts, derivedTableMap)
if err != nil {
return errorWithDebugID(fmt.Errorf("error transforming args: %w", err), debugID)
}
Expand Down Expand Up @@ -436,8 +438,13 @@ func (s *SolanaChainWriterService) SubmitTransaction(ctx context.Context, contra
}

s.lggr.Debugw("Sending main transaction", "contract", contractName, "method", method)

options := []txmutils.SetTxConfig{}
if computeLimit != 0 {
options = append(options, txmutils.SetComputeUnitLimit(computeLimit))
}
// Enqueue transaction
if err = s.txm.Enqueue(ctx, methodConfig.FromAddress, tx, &transactionID, blockhash.Value.LastValidBlockHeight); err != nil {
if err = s.txm.Enqueue(ctx, methodConfig.FromAddress, tx, &transactionID, blockhash.Value.LastValidBlockHeight, options...); err != nil {
return errorWithDebugID(fmt.Errorf("error enqueuing transaction: %w", err), debugID)
}

Expand Down
13 changes: 12 additions & 1 deletion pkg/solana/chainwriter/chain_writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
clientmocks "github.com/smartcontractkit/chainlink-solana/pkg/solana/client/mocks"
feemocks "github.com/smartcontractkit/chainlink-solana/pkg/solana/fees/mocks"
txmMocks "github.com/smartcontractkit/chainlink-solana/pkg/solana/txm/mocks"
txmutils "github.com/smartcontractkit/chainlink-solana/pkg/solana/txm/utils"
)

type Arguments struct {
Expand Down Expand Up @@ -927,7 +928,14 @@ func TestChainWriter_CCIPOfframp(t *testing.T) {
require.Len(t, tokenIndexes, 1)
require.Equal(t, uint8(3), tokenIndexes[0])
return true
}), &txID, mock.Anything).Return(nil).Once()
}), &txID, mock.Anything, mock.AnythingOfType("utils.SetTxConfig")).Return(nil).Run(func(args mock.Arguments) {
setComputeLimit, ok := args[5].(txmutils.SetTxConfig)
require.True(t, ok)

txConfig := &txmutils.TxConfig{}
setComputeLimit(txConfig)
require.Equal(t, uint32(500), txConfig.ComputeUnitLimit)
}).Once()

// stripped back report just for purposes of example
abstractReport := ccipocr3.ExecutePluginReportSingleChain{
Expand All @@ -938,6 +946,9 @@ func TestChainWriter_CCIPOfframp(t *testing.T) {
DestTokenAddress: destTokenAddr.Bytes(),
},
},
ExtraArgsDecoded: map[string]any{
"ComputeUnits": uint32(500),
},
},
},
}
Expand Down
41 changes: 24 additions & 17 deletions pkg/solana/chainwriter/transform_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,17 @@ import (

"github.com/gagliardetto/solana-go"
"github.com/mitchellh/mapstructure"
"github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/ccip_offramp"
"github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3"
)

type ReportPostTransform struct {
ReportContext [2][32]byte
Report []byte
Info ccipocr3.ExecuteReportInfo
AbstractReport ccip_offramp.ExecutionReportSingleChain
TokenIndexes []byte
ReportContext [2][32]byte
Report []byte
Info ccipocr3.ExecuteReportInfo
TokenIndexes []byte
}

func FindTransform(id string) (func(context.Context, any, solana.AccountMetaSlice, map[string]map[string][]*solana.AccountMeta) (any, solana.AccountMetaSlice, error), error) {
func FindTransform(id string) (func(context.Context, any, solana.AccountMetaSlice, map[string]map[string][]*solana.AccountMeta) (any, solana.AccountMetaSlice, uint32, error), error) {
switch id {
case "CCIPExecute":
return CCIPExecuteArgsTransform, nil
Expand All @@ -32,19 +30,28 @@ func FindTransform(id string) (func(context.Context, any, solana.AccountMetaSlic

// This Transform function looks up the token pool addresses in the accounts slice and augments the args
// with the indexes of the token pool addresses in the accounts slice.
func CCIPExecuteArgsTransform(ctx context.Context, args any, accounts solana.AccountMetaSlice, tableMap map[string]map[string][]*solana.AccountMeta) (any, solana.AccountMetaSlice, error) {
func CCIPExecuteArgsTransform(ctx context.Context, args any, accounts solana.AccountMetaSlice, tableMap map[string]map[string][]*solana.AccountMeta) (any, solana.AccountMetaSlice, uint32, error) {
var argsTransformed ReportPostTransform
err := mapstructure.Decode(args, &argsTransformed)
if err != nil {
return nil, nil, err
return nil, nil, 0, err
}

if len(argsTransformed.Info.AbstractReports) != 1 || len(argsTransformed.Info.AbstractReports[0].Messages) != 1 {
return nil, nil, 0, fmt.Errorf("Expected 1 report with 1 message")
}

computeUnits := argsTransformed.Info.AbstractReports[0].Messages[0].ExtraArgsDecoded["ComputeUnits"]
if computeUnits == nil {
return nil, nil, 0, errors.New("missing ComputeUnits in ExtraArgs")
}

registryTables, exists := tableMap["PoolLookupTable"]
// If PoolLookupTable does not exist in the table map, token indexes are not needed
// Return with empty TokenIndexes
if !exists {
argsTransformed.TokenIndexes = []byte{}
return argsTransformed, accounts, nil
return argsTransformed, accounts, computeUnits.(uint32), nil
}

tokenPoolAddresses := []solana.PublicKey{}
Expand All @@ -57,36 +64,36 @@ func CCIPExecuteArgsTransform(ctx context.Context, args any, accounts solana.Acc
for _, address := range tokenPoolAddresses {
if account.PublicKey == address {
if i > 255 {
return nil, nil, fmt.Errorf("index %d out of range for uint8", i)
return nil, nil, 0, fmt.Errorf("index %d out of range for uint8", i)
}
tokenIndexes = append(tokenIndexes, uint8(i)) //nolint:gosec
}
}
}

if len(tokenIndexes) != len(tokenPoolAddresses) {
return nil, nil, fmt.Errorf("missing token pools in accounts")
return nil, nil, 0, fmt.Errorf("missing token pools in accounts")
}

argsTransformed.TokenIndexes = tokenIndexes
return argsTransformed, accounts, nil
return argsTransformed, accounts, computeUnits.(uint32), nil
}

// This Transform function trims off the GlobalState account from commit transactions if there are no token or gas price updates
func CCIPCommitAccountTransform(ctx context.Context, args any, accounts solana.AccountMetaSlice, _ map[string]map[string][]*solana.AccountMeta) (any, solana.AccountMetaSlice, error) {
func CCIPCommitAccountTransform(ctx context.Context, args any, accounts solana.AccountMetaSlice, _ map[string]map[string][]*solana.AccountMeta) (any, solana.AccountMetaSlice, uint32, error) {
var tokenPriceVals, gasPriceVals [][]byte
var err error
tokenPriceVals, err = GetValuesAtLocation(args, "Info.TokenPrices.TokenID")
if err != nil && !errors.Is(err, errFieldNotFound) {
return nil, nil, fmt.Errorf("error getting values at location: %w", err)
return nil, nil, 0, fmt.Errorf("error getting values at location: %w", err)
}
gasPriceVals, err = GetValuesAtLocation(args, "Info.GasPrices.ChainSel")
if err != nil && !errors.Is(err, errFieldNotFound) {
return nil, nil, fmt.Errorf("error getting values at location: %w", err)
return nil, nil, 0, fmt.Errorf("error getting values at location: %w", err)
}
transformedAccounts := accounts
if len(tokenPriceVals) == 0 && len(gasPriceVals) == 0 {
transformedAccounts = accounts[:len(accounts)-1]
}
return args, transformedAccounts, nil
return args, transformedAccounts, 0, nil
}
71 changes: 58 additions & 13 deletions pkg/solana/chainwriter/transform_registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"testing"

"github.com/gagliardetto/solana-go"
"github.com/smartcontractkit/chainlink-ccip/chains/solana/gobindings/ccip_offramp"
"github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
"github.com/stretchr/testify/require"
Expand All @@ -13,10 +12,9 @@ import (
)

type ReportPreTransform struct {
ReportContext [2][32]byte
Report []byte
Info ccipocr3.ExecuteReportInfo
AbstractReport ccip_offramp.ExecutionReportSingleChain
ReportContext [2][32]byte
Report []byte
Info ccipocr3.ExecuteReportInfo
}

func Test_CCIPExecuteArgsTransform(t *testing.T) {
Expand All @@ -33,14 +31,17 @@ func Test_CCIPExecuteArgsTransform(t *testing.T) {
TokenAmounts: []ccipocr3.RampTokenAmount{{
DestTokenAddress: ccipocr3.UnknownAddress(destTokenAddr.Bytes()),
}},
ExtraArgsDecoded: map[string]any{
"ComputeUnits": uint32(500),
},
}},
}},
},
}

accounts := []*solana.AccountMeta{{PublicKey: poolKeys[0]}, {PublicKey: poolKeys[1]}}

t.Run("CCIPExecute ArgsTransform includes token indexes", func(t *testing.T) {
t.Run("CCIPExecute ArgsTransform includes token indexes and computeUnits", func(t *testing.T) {
tableMap := make(map[string]map[string][]*solana.AccountMeta)
tableMap["PoolLookupTable"] = make(map[string][]*solana.AccountMeta)
lookupTablePubkey := chainwriter.GetRandomPubKey(t)
Expand All @@ -51,8 +52,10 @@ func Test_CCIPExecuteArgsTransform(t *testing.T) {
}
tableMap["PoolLookupTable"][lookupTablePubkey.String()] = poolKeysMeta

transformedArgs, newAccounts, err := chainwriter.CCIPExecuteArgsTransform(ctx, args, accounts, tableMap)
transformedArgs, newAccounts, computeUnits, err := chainwriter.CCIPExecuteArgsTransform(ctx, args, accounts, tableMap)
require.NoError(t, err)

require.Equal(t, computeUnits, uint32(500))
// Accounts should be unchanged
require.Len(t, newAccounts, 2)
typedArgs, ok := transformedArgs.(chainwriter.ReportPostTransform)
Expand All @@ -62,8 +65,10 @@ func Test_CCIPExecuteArgsTransform(t *testing.T) {
})

t.Run("CCIPExecute ArgsTransform includes empty token indexes if lookup table not found", func(t *testing.T) {
transformedArgs, newAccounts, err := chainwriter.CCIPExecuteArgsTransform(ctx, args, accounts, nil)
transformedArgs, newAccounts, computeUnits, err := chainwriter.CCIPExecuteArgsTransform(ctx, args, accounts, nil)
require.NoError(t, err)
require.Equal(t, computeUnits, uint32(500))

// Accounts should be unchanged
require.Len(t, newAccounts, 2)
typedArgs, ok := transformedArgs.(chainwriter.ReportPostTransform)
Expand All @@ -75,17 +80,57 @@ func Test_CCIPExecuteArgsTransform(t *testing.T) {
t.Run("CCIPExecute ArgsTransform does not get args that conform to ReportPreTransform", func(t *testing.T) {
args := struct {
ReportContext [2][32]uint8
Report []uint8
Info ccipocr3.ExecuteReportInfo
}{
ReportContext: [2][32]uint8{},
Report: []uint8{},
Info: ccipocr3.ExecuteReportInfo{
AbstractReports: []ccipocr3.ExecutePluginReportSingleChain{{
Messages: []ccipocr3.Message{{
ExtraArgsDecoded: map[string]any{
"ComputeUnits": uint32(500),
},
}},
}},
},
}
transformedArgs, newAccounts, err := chainwriter.CCIPExecuteArgsTransform(ctx, args, accounts, nil)
transformedArgs, newAccounts, computeUnits, err := chainwriter.CCIPExecuteArgsTransform(ctx, args, accounts, nil)
require.NoError(t, err)

require.Equal(t, computeUnits, uint32(500))
_, ok := transformedArgs.(chainwriter.ReportPostTransform)
require.True(t, ok)
require.Len(t, newAccounts, 2)
})

t.Run("CCIPExecute ArgsTransform fails with empty Info", func(t *testing.T) {
args := struct {
ReportContext [2][32]uint8
Report []uint8
Info ccipocr3.ExecuteReportInfo
}{
ReportContext: [2][32]uint8{},
Report: []uint8{},
Info: ccipocr3.ExecuteReportInfo{},
}
_, _, _, err := chainwriter.CCIPExecuteArgsTransform(ctx, args, accounts, nil)
require.Contains(t, err.Error(), "Expected 1 report with 1 message")
})

t.Run("CCIPExecute ArgsTransform fails with multiple reports", func(t *testing.T) {
args := struct {
ReportContext [2][32]uint8
Report []uint8
Info ccipocr3.ExecuteReportInfo
}{
ReportContext: [2][32]uint8{},
Report: []uint8{},
Info: ccipocr3.ExecuteReportInfo{
AbstractReports: []ccipocr3.ExecutePluginReportSingleChain{{}, {}},
},
}
_, _, _, err := chainwriter.CCIPExecuteArgsTransform(ctx, args, accounts, nil)
require.Contains(t, err.Error(), "Expected 1 report with 1 message")
})
}

func Test_CCIPCommitAccountTransform(t *testing.T) {
Expand All @@ -101,7 +146,7 @@ func Test_CCIPCommitAccountTransform(t *testing.T) {
},
}
accounts := []*solana.AccountMeta{{PublicKey: key1}, {PublicKey: key2}}
_, newAccounts, err := chainwriter.CCIPCommitAccountTransform(ctx, args, accounts, nil)
_, newAccounts, _, err := chainwriter.CCIPCommitAccountTransform(ctx, args, accounts, nil)
require.NoError(t, err)
require.Len(t, newAccounts, 2)
})
Expand All @@ -112,7 +157,7 @@ func Test_CCIPCommitAccountTransform(t *testing.T) {
Info: ccipocr3.CommitReportInfo{},
}
accounts := []*solana.AccountMeta{{PublicKey: key1}, {PublicKey: key2}}
_, newAccounts, err := chainwriter.CCIPCommitAccountTransform(ctx, args, accounts, nil)
_, newAccounts, _, err := chainwriter.CCIPCommitAccountTransform(ctx, args, accounts, nil)
require.NoError(t, err)
require.Len(t, newAccounts, 1)
})
Expand Down

0 comments on commit 1827cf6

Please sign in to comment.