Skip to content

Commit

Permalink
Added location parsing for IsWritable and IsSignable on AccountLookups
Browse files Browse the repository at this point in the history
  • Loading branch information
silaslenihan committed Jan 16, 2025
1 parent 74b7a72 commit fa4f975
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 25 deletions.
132 changes: 125 additions & 7 deletions integration-tests/relayinterface/lookups_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ func TestAccountLookups(t *testing.T) {
lookupConfig := chainwriter.AccountLookup{
Name: "TestAccount",
Location: "Inner.Address",
IsSigner: true,
IsWritable: true,
IsSigner: chainwriter.MetaBool{Value: true},
IsWritable: chainwriter.MetaBool{Value: true},
}
result, err := lookupConfig.Resolve(ctx, testArgs, nil, nil)
require.NoError(t, err)
Expand Down Expand Up @@ -96,8 +96,8 @@ func TestAccountLookups(t *testing.T) {
lookupConfig := chainwriter.AccountLookup{
Name: "TestAccount",
Location: "Inner.Address",
IsSigner: true,
IsWritable: true,
IsSigner: chainwriter.MetaBool{Value: true},
IsWritable: chainwriter.MetaBool{Value: true},
}
result, err := lookupConfig.Resolve(ctx, testArgs, nil, nil)
require.NoError(t, err)
Expand All @@ -117,12 +117,130 @@ func TestAccountLookups(t *testing.T) {
lookupConfig := chainwriter.AccountLookup{
Name: "InvalidAccount",
Location: "Invalid.Directory",
IsSigner: true,
IsWritable: true,
IsSigner: chainwriter.MetaBool{Value: true},
IsWritable: chainwriter.MetaBool{Value: true},
}
_, err := lookupConfig.Resolve(ctx, testArgs, nil, nil)
require.Error(t, err)
})

t.Run("AccountLookup works with MetaBool lookups", func(t *testing.T) {
type InnerAccountArgs struct {
Accounts []*solana.AccountMeta
}

type TestAccountArgs struct {
Inner InnerAccountArgs
}

accounts := [3]*solana.AccountMeta{}

for i := 0; i < 3; i++ {
accounts[i] = &solana.AccountMeta{
PublicKey: chainwriter.GetRandomPubKey(t),
IsSigner: true,
IsWritable: false,
}
}

lookupConfig := chainwriter.AccountLookup{
Name: "InvalidAccount",
Location: "Inner.Accounts.PublicKey",
IsSigner: chainwriter.MetaBool{Location: "Inner.Accounts.IsSigner"},
IsWritable: chainwriter.MetaBool{Location: "Inner.Accounts.IsWritable"},
}

args := TestAccountArgs{
Inner: InnerAccountArgs{
Accounts: accounts[:],
},
}

result, err := lookupConfig.Resolve(ctx, args, nil, nil)
require.NoError(t, err)

for i, meta := range result {
require.Equal(t, accounts[i], meta)
}
})

t.Run("AccountLookup works with MetaBool lookups when a field is missing", func(t *testing.T) {
type InnerAccountArgs struct {
Accounts []*solana.AccountMeta
}

type TestAccountArgs struct {
Inner InnerAccountArgs
}

accounts := [3]*solana.AccountMeta{}

for i := 0; i < 3; i++ {
accounts[i] = &solana.AccountMeta{
PublicKey: chainwriter.GetRandomPubKey(t),
IsWritable: true,
}
}

lookupConfig := chainwriter.AccountLookup{
Name: "InvalidAccount",
Location: "Inner.Accounts.PublicKey",
IsSigner: chainwriter.MetaBool{Location: "Inner.Accounts.IsSigner"},
IsWritable: chainwriter.MetaBool{Location: "Inner.Accounts.IsWritable"},
}

args := TestAccountArgs{
Inner: InnerAccountArgs{
Accounts: accounts[:],
},
}

result, err := lookupConfig.Resolve(ctx, args, nil, nil)
require.NoError(t, err)

for i, meta := range result {
require.Equal(t, accounts[i], meta)
}
})

t.Run("AccountLookup works with MetaBool lookups when a field is missing", func(t *testing.T) {
type InnerAccountArgs struct {
Accounts []*solana.AccountMeta
}

type TestAccountArgs struct {
Inner InnerAccountArgs
}

accounts := [3]*solana.AccountMeta{}

for i := 0; i < 3; i++ {
accounts[i] = &solana.AccountMeta{
PublicKey: chainwriter.GetRandomPubKey(t),
IsWritable: true,
}
}

lookupConfig := chainwriter.AccountLookup{
Name: "InvalidAccount",
Location: "Inner.Accounts.PublicKey",
IsSigner: chainwriter.MetaBool{Location: "Inner.Accounts.IsSigner"},
IsWritable: chainwriter.MetaBool{Location: "Inner.Accounts.IsWritable"},
}

args := TestAccountArgs{
Inner: InnerAccountArgs{
Accounts: accounts[:],
},
}

result, err := lookupConfig.Resolve(ctx, args, nil, nil)
require.NoError(t, err)

for i, meta := range result {
require.Equal(t, accounts[i], meta)
}
})
}

func TestPDALookups(t *testing.T) {
Expand Down Expand Up @@ -435,7 +553,7 @@ func TestLookupTables(t *testing.T) {
Accounts: chainwriter.AccountLookup{
Name: "TestLookupTable",
Location: "Inner.Address",
IsSigner: true,
IsSigner: chainwriter.MetaBool{Value: true},
},
},
},
Expand Down
12 changes: 6 additions & 6 deletions pkg/solana/chainwriter/ccip_example_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ func TestConfig() {
AccountLookup{
Name: "TokenAccount",
Location: "Message.TokenAmounts.DestTokenAddress",
IsSigner: false,
IsWritable: false,
IsSigner: MetaBool{Value: false},
IsWritable: MetaBool{Value: false},
},
// PDA Account Lookup - Based on an account lookup and an address lookup
PDALookups{
Expand All @@ -116,16 +116,16 @@ func TestConfig() {
PublicKey: AccountLookup{
Name: "TokenAccount",
Location: "Message.TokenAmounts.DestTokenAddress",
IsSigner: false,
IsWritable: false,
IsSigner: MetaBool{Value: false},
IsWritable: MetaBool{Value: false},
},
// The seed is the receiver address.
Seeds: []Seed{
{Dynamic: AccountLookup{
Name: "Receiver",
Location: "Message.Receiver",
IsSigner: false,
IsWritable: false,
IsSigner: MetaBool{Value: false},
IsWritable: MetaBool{Value: false},
}},
},
},
Expand Down
8 changes: 4 additions & 4 deletions pkg/solana/chainwriter/chain_writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ func TestChainWriter_GetAddresses(t *testing.T) {
chainwriter.AccountLookup{
Name: "LookupTable",
Location: "LookupTable",
IsSigner: accountLookupMeta.IsSigner,
IsWritable: accountLookupMeta.IsWritable,
IsSigner: chainwriter.MetaBool{Value: accountLookupMeta.IsSigner},
IsWritable: chainwriter.MetaBool{Value: accountLookupMeta.IsWritable},
},
chainwriter.PDALookups{
Name: "DataAccountPDA",
Expand Down Expand Up @@ -463,8 +463,8 @@ func TestChainWriter_SubmitTransaction(t *testing.T) {
chainwriter.AccountLookup{
Name: "LookupTable",
Location: "LookupTable",
IsSigner: false,
IsWritable: false,
IsSigner: chainwriter.MetaBool{Value: false},
IsWritable: chainwriter.MetaBool{Value: false},
},
chainwriter.PDALookups{
Name: "DataAccountPDA",
Expand Down
8 changes: 7 additions & 1 deletion pkg/solana/chainwriter/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,14 @@ func GetValuesAtLocation(args any, location string) ([][]byte, error) {
buf := make([]byte, 8)
binary.LittleEndian.PutUint64(buf, num)
vals = append(vals, buf)
} else if boolean, ok := value.(bool); ok {
if boolean {
vals = append(vals, []byte{0x01})
} else {
vals = append(vals, []byte{0x00})
}
} else {
return nil, fmt.Errorf("invalid value format at path: %s", location)
return nil, fmt.Errorf("invalid value format at path: %s, type: %s", location, reflect.TypeOf(value).String())
}
}

Expand Down
68 changes: 61 additions & 7 deletions pkg/solana/chainwriter/lookups.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,13 @@ type AccountConstant struct {
type AccountLookup struct {
Name string
Location string
IsSigner bool
IsWritable bool
IsSigner MetaBool
IsWritable MetaBool
}

type MetaBool struct {
Value bool
Location string
}

type Seed struct {
Expand Down Expand Up @@ -89,23 +94,72 @@ func (ac AccountConstant) Resolve(_ context.Context, _ any, _ map[string]map[str
}, nil
}

func (al AccountLookup) Resolve(_ context.Context, args any, _ map[string]map[string][]*solana.AccountMeta, _ client.Reader) ([]*solana.AccountMeta, error) {
func (al AccountLookup) Resolve(
_ context.Context,
args any,
_ map[string]map[string][]*solana.AccountMeta,
_ client.Reader,
) ([]*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("error getting account from '%s': %w", al.Location, err)
}

var metas []*solana.AccountMeta
for _, address := range derivedValues {
pubkeysCount := len(derivedValues)
for i, address := range derivedValues {
// Resolve isSigner for this particular pubkey
isSigner, err := resolveMetaBool(al.IsSigner, args, i, pubkeysCount)
if err != nil {
return nil, err
}

// Resolve isWritable
isWritable, err := resolveMetaBool(al.IsWritable, args, i, pubkeysCount)
if err != nil {
return nil, err
}

metas = append(metas, &solana.AccountMeta{
PublicKey: solana.PublicKeyFromBytes(address),
IsSigner: al.IsSigner,
IsWritable: al.IsWritable,
IsSigner: isSigner,
IsWritable: isWritable,
})
}

return metas, nil
}

func resolveMetaBool(mb MetaBool, args any, pubkeyIndex, pubkeysCount int) (bool, error) {
if mb.Location == "" {
return mb.Value, nil
}

boolVals, err := GetValuesAtLocation(args, mb.Location)
if err != nil {
return false, fmt.Errorf("error reading bools from location '%s': %w", mb.Location, err)
}

if len(boolVals) == 0 {
return false, fmt.Errorf("no boolean found at location '%s'", mb.Location)
}

// boolVals should always equal the number of pubkeys (or zero) since bools default to false
if len(boolVals) != pubkeysCount {
return false, fmt.Errorf(
"boolean array length %d doesn't match pubkey count %d for location '%s'",
len(boolVals), pubkeysCount, mb.Location,
)
}

// Convert the i-th item to a bool
data := boolVals[pubkeyIndex]
if len(data) == 0 {
return false, fmt.Errorf("missing data for boolean at index %d in location '%s'", pubkeyIndex, mb.Location)
}
return data[0] != 0, nil
}

func (alt AccountsFromLookupTable) Resolve(_ context.Context, _ any, derivedTableMap map[string]map[string][]*solana.AccountMeta, _ client.Reader) ([]*solana.AccountMeta, error) {
// Fetch the inner map for the specified lookup table name
innerMap, ok := derivedTableMap[alt.LookupTableName]
Expand Down

0 comments on commit fa4f975

Please sign in to comment.