Skip to content

Commit

Permalink
Specify Ignorable Errors for Optional Lookups (#1091)
Browse files Browse the repository at this point in the history
Co-authored-by: Jonghyeon Park <[email protected]>
  • Loading branch information
silaslenihan and jadepark-dev authored Feb 20, 2025
1 parent e8b2d8a commit 3333854
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 12 deletions.
42 changes: 35 additions & 7 deletions integration-tests/relayinterface/lookups_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func TestAccountLookups(t *testing.T) {
IsWritable: chainwriter.MetaBool{Value: true},
}}
_, err := lookupConfig.AccountLookup.Resolve(testArgs)
require.Error(t, err)
require.ErrorIs(t, err, chainwriter.ErrLookupNotFoundAtLocation)
})

t.Run("AccountLookup works with MetaBool bitmap lookups", func(t *testing.T) {
Expand Down Expand Up @@ -360,8 +360,7 @@ func TestPDALookups(t *testing.T) {
}

_, err := pdaLookup.Resolve(ctx, args, nil, client.MultiClient{})
require.Error(t, err)
require.Contains(t, err.Error(), "key not found")
require.ErrorIs(t, err, chainwriter.ErrGettingSeedAtLocation)
})

t.Run("PDALookup resolves valid PDA with address lookup seeds", func(t *testing.T) {
Expand Down Expand Up @@ -569,6 +568,21 @@ func TestLookupTables(t *testing.T) {
require.Contains(t, err.Error(), "error fetching account info for table") // Example error message
})

t.Run("Derived lookup table fails with invalid table name", func(t *testing.T) {
derivedTableMap := map[string]map[string][]*solana.AccountMeta{
"DerivedTable": {},
}
accountsFromLookupTable := chainwriter.Lookup{
AccountsFromLookupTable: &chainwriter.AccountsFromLookupTable{
LookupTableName: "InvalidTable",
IncludeIndexes: []int{},
},
}

_, err = accountsFromLookupTable.Resolve(ctx, nil, derivedTableMap, multiClient)
require.ErrorIs(t, err, chainwriter.ErrLookupTableNotFound)
})

t.Run("Static lookup table fails with invalid address", func(t *testing.T) {
invalidTable := chainwriter.GetRandomPubKey(t)

Expand Down Expand Up @@ -608,8 +622,15 @@ func TestLookupTables(t *testing.T) {
derivedTableMap, _, err := cw.ResolveLookupTables(ctx, testArgs, lookupConfig)
require.NoError(t, err)

addresses, ok := derivedTableMap["DerivedTable"][table.String()]
require.True(t, ok)
accountsFromLookupTable := chainwriter.Lookup{
AccountsFromLookupTable: &chainwriter.AccountsFromLookupTable{
LookupTableName: "DerivedTable",
IncludeIndexes: []int{},
},
}

addresses, err := accountsFromLookupTable.Resolve(ctx, nil, derivedTableMap, multiClient)
require.NoError(t, err)
for i, address := range addresses {
require.Equal(t, pubKeys[i], address.PublicKey)
}
Expand Down Expand Up @@ -654,8 +675,15 @@ func TestLookupTables(t *testing.T) {
derivedTableMap, _, err := cw.ResolveLookupTables(ctx, args, lookupConfig)
require.NoError(t, err)

addresses, ok := derivedTableMap["DerivedTable"][lookupTable.String()]
require.True(t, ok)
accountsFromLookupTable := chainwriter.Lookup{
AccountsFromLookupTable: &chainwriter.AccountsFromLookupTable{
LookupTableName: "DerivedTable",
IncludeIndexes: []int{},
},
}

addresses, err := accountsFromLookupTable.Resolve(ctx, args, derivedTableMap, multiClient)
require.NoError(t, err)
for i, address := range addresses {
require.Equal(t, lookupKeys[i], address.PublicKey)
}
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 @@ -155,7 +155,7 @@ func GetAddresses(ctx context.Context, args any, accounts []Lookup, derivedTable
var addresses []*solana.AccountMeta
for _, accountConfig := range accounts {
meta, err := accountConfig.Resolve(ctx, args, derivedTableMap, client)
if accountConfig.Optional && err != nil {
if accountConfig.Optional && err != nil && isIgnorableError(err) {
// skip optional accounts if they are not found
continue
}
Expand All @@ -167,6 +167,13 @@ func GetAddresses(ctx context.Context, args any, accounts []Lookup, derivedTable
return addresses, nil
}

// These errors are ignorable if the lookup is optional.
func isIgnorableError(err error) bool {
return errors.Is(err, ErrLookupNotFoundAtLocation) ||
errors.Is(err, ErrLookupTableNotFound) ||
errors.Is(err, ErrGettingSeedAtLocation)
}

// FilterLookupTableAddresses takes a list of accounts and two lookup table maps
// (one for derived tables, one for static tables) and filters out any addresses that are
// not used by the accounts. It returns a map of only those lookup table
Expand Down Expand Up @@ -460,7 +467,7 @@ func (s *SolanaChainWriterService) ResolveLookupTables(ctx context.Context, args
// Load the lookup table - note: This could be multiple tables if the lookup is a PDALookups that resolves to more
// than one address
lookupTableMap, err := s.loadTable(ctx, args, derivedLookup)
if derivedLookup.Optional && err != nil {
if derivedLookup.Optional && err != nil && isIgnorableError(err) {
continue
}
if err != nil {
Expand Down
12 changes: 9 additions & 3 deletions pkg/solana/chainwriter/lookups.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ import (
"github.com/smartcontractkit/chainlink-solana/pkg/solana/codec"
)

var (
ErrLookupNotFoundAtLocation = fmt.Errorf("error getting account from lookup")
ErrLookupTableNotFound = fmt.Errorf("lookup table not found")
ErrGettingSeedAtLocation = fmt.Errorf("error getting address seed for location")
)

type Lookup struct {
Optional bool
AccountConstant *AccountConstant `json:"accountConstant,omitempty"`
Expand Down Expand Up @@ -146,7 +152,7 @@ func (ac AccountConstant) Resolve() ([]*solana.AccountMeta, error) {
func (al AccountLookup) Resolve(args any) ([]*solana.AccountMeta, error) {
derivedValues, err := GetValuesAtLocation(args, al.Location)
if err != nil {
return nil, fmt.Errorf("error getting account from lookup: %w", err)
return nil, fmt.Errorf("%w: %v", ErrLookupNotFoundAtLocation, err)
}

var metas []*solana.AccountMeta
Expand Down Expand Up @@ -206,7 +212,7 @@ func (alt AccountsFromLookupTable) Resolve(derivedTableMap map[string]map[string
// Fetch the inner map for the specified lookup table name
innerMap, ok := derivedTableMap[alt.LookupTableName]
if !ok {
return nil, fmt.Errorf("lookup table not found: %s", alt.LookupTableName)
return nil, fmt.Errorf("%w: %s", ErrLookupTableNotFound, alt.LookupTableName)
}

var result []*solana.AccountMeta
Expand Down Expand Up @@ -332,7 +338,7 @@ func getSeedBytesCombinations(
// Get value from a location (This doesn't have to be an address, it can be any value)
bytes, err := GetValuesAtLocation(args, lookupSeed.Location)
if err != nil {
return nil, fmt.Errorf("error getting address seed for location %q: %w", lookupSeed.Location, err)
return nil, fmt.Errorf("%w %q: %w", ErrGettingSeedAtLocation, lookupSeed.Location, err)
}
// append each byte array to the expansions
for _, b := range bytes {
Expand Down

0 comments on commit 3333854

Please sign in to comment.