Skip to content

Commit

Permalink
Updated MetaBool to use a bitmap location rather than a bool location
Browse files Browse the repository at this point in the history
  • Loading branch information
silaslenihan committed Jan 17, 2025
1 parent d9cec54 commit a4766df
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 128 deletions.
110 changes: 22 additions & 88 deletions integration-tests/relayinterface/lookups_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

type InnerAccountArgs struct {
Accounts []*solana.AccountMeta
Bitmap uint64
}

type TestAccountArgs struct {
Expand Down Expand Up @@ -132,27 +133,29 @@ func TestAccountLookups(t *testing.T) {
require.Error(t, err)
})

t.Run("AccountLookup works with MetaBool lookups", func(t *testing.T) {
t.Run("AccountLookup works with MetaBool bitmap lookups", func(t *testing.T) {
accounts := [3]*solana.AccountMeta{}

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

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

args := TestAccountArgs{
Inner: InnerAccountArgs{
Accounts: accounts[:],
// should be 101... so {true, false, true}
Bitmap: 5,
},
}

Expand All @@ -164,79 +167,10 @@ func TestAccountLookups(t *testing.T) {
}
})

t.Run("AccountLookup works with MetaBool lookups when a meta field is missing", func(t *testing.T) {
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 in a different location", func(t *testing.T) {
type TestAccountArgsExtended struct {
Inner InnerAccountArgs
ExternalBool bool
}

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

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

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

args := TestAccountArgsExtended{
Inner: InnerAccountArgs{
Accounts: accounts[:],
},
ExternalBool: true,
}

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 fails with MetaBool due to an invalid number of Meta lookups", func(t *testing.T) {
t.Run("AccountLookup fails with MetaBool due to an invalid number of bitmaps", func(t *testing.T) {
type TestAccountArgsExtended struct {
Inner InnerAccountArgs
ExternalBools []bool
Inner InnerAccountArgs
Bitmaps []uint64
}

accounts := [3]*solana.AccountMeta{}
Expand All @@ -252,22 +186,22 @@ func TestAccountLookups(t *testing.T) {
lookupConfig := chainwriter.AccountLookup{
Name: "InvalidAccount",
Location: "Inner.Accounts.PublicKey",
IsSigner: chainwriter.MetaBool{Location: "ExternalBools"},
IsWritable: chainwriter.MetaBool{Location: "ExternalBools"},
IsSigner: chainwriter.MetaBool{BitmapLocation: "Bitmaps"},
IsWritable: chainwriter.MetaBool{BitmapLocation: "Bitmaps"},
}

args := TestAccountArgsExtended{
Inner: InnerAccountArgs{
Accounts: accounts[:],
},
ExternalBools: []bool{true, true},
Bitmaps: []uint64{5, 3},
}

_, err := lookupConfig.Resolve(ctx, args, nil, nil)
require.Contains(t, err.Error(), "boolean array length 2 doesn't match pubkey count 3 for location")
require.Contains(t, err.Error(), "bitmap value is not a single value")
})

t.Run("AccountLookup fails with MetaBool with an Invalid Location", func(t *testing.T) {
t.Run("AccountLookup fails with MetaBool with an Invalid BitmapLocation", func(t *testing.T) {
accounts := [3]*solana.AccountMeta{}

for i := 0; i < 3; i++ {
Expand All @@ -280,8 +214,8 @@ func TestAccountLookups(t *testing.T) {
lookupConfig := chainwriter.AccountLookup{
Name: "InvalidAccount",
Location: "Inner.Accounts.PublicKey",
IsSigner: chainwriter.MetaBool{Location: "Invalid.IsSigner"},
IsWritable: chainwriter.MetaBool{Location: "Invalid.IsWritable"},
IsSigner: chainwriter.MetaBool{BitmapLocation: "Invalid.Bitmap"},
IsWritable: chainwriter.MetaBool{BitmapLocation: "Invalid.Bitmap"},
}

args := TestAccountArgs{
Expand All @@ -291,10 +225,10 @@ func TestAccountLookups(t *testing.T) {
}

_, err := lookupConfig.Resolve(ctx, args, nil, nil)
require.Contains(t, err.Error(), "error reading bools from location")
require.Contains(t, err.Error(), "error reading bitmap from location")
})

t.Run("AccountLookup fails when MetaBool is an invalid type", func(t *testing.T) {
t.Run("AccountLookup fails when MetaBool Bitmap is an invalid type", func(t *testing.T) {
accounts := [3]*solana.AccountMeta{}

for i := 0; i < 3; i++ {
Expand All @@ -307,8 +241,8 @@ func TestAccountLookups(t *testing.T) {
lookupConfig := chainwriter.AccountLookup{
Name: "InvalidAccount",
Location: "Inner.Accounts.PublicKey",
IsSigner: chainwriter.MetaBool{Location: "Inner"},
IsWritable: chainwriter.MetaBool{Location: "Inner"},
IsSigner: chainwriter.MetaBool{BitmapLocation: "Inner"},
IsWritable: chainwriter.MetaBool{BitmapLocation: "Inner"},
}

args := TestAccountArgs{
Expand Down
6 changes: 0 additions & 6 deletions pkg/solana/chainwriter/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,6 @@ 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, type: %s", location, reflect.TypeOf(value).String())
}
Expand Down
65 changes: 31 additions & 34 deletions pkg/solana/chainwriter/lookups.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package chainwriter

import (
"context"
"encoding/binary"
"fmt"
"reflect"

Expand Down Expand Up @@ -29,14 +30,14 @@ type AccountConstant struct {
type AccountLookup struct {
Name string
Location string
// IsSigner and IsWritable can either be a constant bool or a location to a bool
// IsSigner and IsWritable can either be a constant bool or a location to a bitmap which decides the bools
IsSigner MetaBool
IsWritable MetaBool
}

type MetaBool struct {
Value bool
Location string
Value bool
BitmapLocation string
}

type Seed struct {
Expand Down Expand Up @@ -107,18 +108,22 @@ func (al AccountLookup) Resolve(
}

var metas []*solana.AccountMeta
signerIndexes, err := resolveBitMap(al.IsSigner, args, len(derivedValues))
if err != nil {
return nil, err
}

writerIndexes, err := resolveBitMap(al.IsWritable, args, len(derivedValues))
if err != nil {
return nil, err
}

for i, address := range derivedValues {
// Resolve isSigner for this particular pubkey
isSigner, err := resolveMetaBool(al.IsSigner, args, i, len(derivedValues))
if err != nil {
return nil, err
}
isSigner := signerIndexes[i]

// Resolve isWritable
isWritable, err := resolveMetaBool(al.IsWritable, args, i, len(derivedValues))
if err != nil {
return nil, err
}
isWritable := writerIndexes[i]

metas = append(metas, &solana.AccountMeta{
PublicKey: solana.PublicKeyFromBytes(address),
Expand All @@ -130,38 +135,30 @@ func (al AccountLookup) Resolve(
return metas, nil
}

func resolveMetaBool(mb MetaBool, args any, pubkeyIndex, pubkeysCount int) (bool, error) {
if mb.Location == "" {
return mb.Value, nil
func resolveBitMap(mb MetaBool, args any, length int) ([]bool, error) {
result := make([]bool, length)
if mb.BitmapLocation == "" {
for i := 0; i < length; i++ {
result[i] = mb.Value
}
return result, nil
}

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

if len(boolVals) == 0 {
return false, fmt.Errorf("no boolean found at location '%s'", mb.Location)
if len(bitmapVals) != 1 {
return []bool{}, fmt.Errorf("bitmap value is not a single value: %v, length: %d", bitmapVals, len(bitmapVals))
}

// boolVals should always equal the number of pubkeys or 1
if len(boolVals) != pubkeysCount && len(boolVals) != 1 {
return false, fmt.Errorf(
"boolean array length %d doesn't match pubkey count %d for location '%s'",
len(boolVals), pubkeysCount, mb.Location,
)
bitmapInt := binary.LittleEndian.Uint64(bitmapVals[0])
for i := 0; i < length; i++ {
result[i] = bitmapInt&(1<<i) > 0
}

// a single boolean value is valid to apply to all pubkeys
data := boolVals[0]

if len(boolVals) > 1 {
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
return result, nil
}

func (alt AccountsFromLookupTable) Resolve(_ context.Context, _ any, derivedTableMap map[string]map[string][]*solana.AccountMeta, _ client.Reader) ([]*solana.AccountMeta, error) {
Expand Down

0 comments on commit a4766df

Please sign in to comment.