Skip to content

Commit

Permalink
Updated PDALookups Seeds field and fixed default accounts
Browse files Browse the repository at this point in the history
  • Loading branch information
silaslenihan committed Dec 27, 2024
1 parent f6302ac commit a9dceaa
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 75 deletions.
24 changes: 12 additions & 12 deletions integration-tests/relayinterface/lookups_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ func TestPDALookups(t *testing.T) {
pdaLookup := chainwriter.PDALookups{
Name: "TestPDA",
PublicKey: chainwriter.AccountConstant{Name: "ProgramID", Address: programID.String()},
Seeds: []chainwriter.Lookup{
chainwriter.AccountConstant{Name: "seed", Address: seed.String()},
Seeds: []chainwriter.Seed{
{Dynamic: chainwriter.AccountConstant{Name: "seed", Address: seed.String()}},
},
IsSigner: false,
IsWritable: true,
Expand Down Expand Up @@ -175,9 +175,9 @@ func TestPDALookups(t *testing.T) {
pdaLookup := chainwriter.PDALookups{
Name: "TestPDA",
PublicKey: chainwriter.AccountConstant{Name: "ProgramID", Address: programID.String()},
Seeds: []chainwriter.Lookup{
chainwriter.AccountLookup{Name: "seed1", Location: "test_seed"},
chainwriter.AccountLookup{Name: "seed2", Location: "another_seed"},
Seeds: []chainwriter.Seed{
{Dynamic: chainwriter.AccountLookup{Name: "seed1", Location: "test_seed"}},
{Dynamic: chainwriter.AccountLookup{Name: "seed2", Location: "another_seed"}},
},
IsSigner: false,
IsWritable: true,
Expand All @@ -198,8 +198,8 @@ func TestPDALookups(t *testing.T) {
pdaLookup := chainwriter.PDALookups{
Name: "TestPDA",
PublicKey: chainwriter.AccountConstant{Name: "ProgramID", Address: programID.String()},
Seeds: []chainwriter.Lookup{
chainwriter.AccountLookup{Name: "seed1", Location: "MissingSeed"},
Seeds: []chainwriter.Seed{
{Dynamic: chainwriter.AccountLookup{Name: "seed1", Location: "MissingSeed"}},
},
IsSigner: false,
IsWritable: true,
Expand Down Expand Up @@ -233,9 +233,9 @@ func TestPDALookups(t *testing.T) {
pdaLookup := chainwriter.PDALookups{
Name: "TestPDA",
PublicKey: chainwriter.AccountConstant{Name: "ProgramID", Address: programID.String()},
Seeds: []chainwriter.Lookup{
chainwriter.AccountLookup{Name: "seed1", Location: "test_seed"},
chainwriter.AccountLookup{Name: "seed2", Location: "another_seed"},
Seeds: []chainwriter.Seed{
{Dynamic: chainwriter.AccountLookup{Name: "seed1", Location: "test_seed"}},
{Dynamic: chainwriter.AccountLookup{Name: "seed2", Location: "another_seed"}},
},
IsSigner: false,
IsWritable: true,
Expand Down Expand Up @@ -403,8 +403,8 @@ func TestLookupTables(t *testing.T) {
Accounts: chainwriter.PDALookups{
Name: "DataAccountPDA",
PublicKey: chainwriter.AccountConstant{Name: "WriteTest", Address: programID.String()},
Seeds: []chainwriter.Lookup{
chainwriter.AccountLookup{Name: "seed1", Location: "seed1"},
Seeds: []chainwriter.Seed{
{Dynamic: chainwriter.AccountLookup{Name: "seed1", Location: "seed1"}},
},
IsSigner: false,
IsWritable: false,
Expand Down
44 changes: 22 additions & 22 deletions pkg/solana/chainwriter/ccip_example_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ func TestConfig() {
IsWritable: false,
},
// Seeds would be used if the user needed to look up addresses to use as seeds, which isn't the case here.
Seeds: []Lookup{
AccountLookup{Location: "Message.TokenAmounts.DestTokenAddress"},
Seeds: []Seed{
{Dynamic: AccountLookup{Location: "Message.TokenAmounts.DestTokenAddress"}},
},
IsSigner: false,
IsWritable: false,
Expand Down Expand Up @@ -86,9 +86,9 @@ func TestConfig() {
IsWritable: false,
},
// Similar to the RegistryTokenState above, the user is looking up PDA accounts based on the dest tokens.
Seeds: []Lookup{
AccountLookup{Location: "Message.TokenAmounts.DestTokenAddress"},
AccountLookup{Location: "Message.Header.DestChainSelector"},
Seeds: []Seed{
{Dynamic: AccountLookup{Location: "Message.TokenAmounts.DestTokenAddress"}},
{Dynamic: AccountLookup{Location: "Message.Header.DestChainSelector"}},
},
IsSigner: false,
IsWritable: false,
Expand Down Expand Up @@ -120,13 +120,13 @@ func TestConfig() {
IsWritable: false,
},
// The seed is the receiver address.
Seeds: []Lookup{
AccountLookup{
Seeds: []Seed{
{Dynamic: AccountLookup{
Name: "Receiver",
Location: "Message.Receiver",
IsSigner: false,
IsWritable: false,
},
}},
},
},
// Account constant
Expand All @@ -146,8 +146,8 @@ func TestConfig() {
IsWritable: false,
},
// The seed, once again, is the destination token address.
Seeds: []Lookup{
AccountLookup{Location: "Message.TokenAmounts.DestTokenAddress"},
Seeds: []Seed{
{Dynamic: AccountLookup{Location: "Message.TokenAmounts.DestTokenAddress"}},
},
IsSigner: false,
IsWritable: false,
Expand Down Expand Up @@ -175,9 +175,9 @@ func TestConfig() {
IsSigner: false,
IsWritable: false,
},
Seeds: []Lookup{
AccountLookup{Location: "Message.Header.DestChainSelector"},
AccountLookup{Location: "Message.Header.SourceChainSelector"},
Seeds: []Seed{
{Dynamic: AccountLookup{Location: "Message.Header.DestChainSelector"}},
{Dynamic: AccountLookup{Location: "Message.Header.SourceChainSelector"}},
},
IsSigner: false,
IsWritable: false,
Expand All @@ -191,11 +191,11 @@ func TestConfig() {
IsSigner: false,
IsWritable: false,
},
Seeds: []Lookup{
AccountLookup{
Seeds: []Seed{
{Dynamic: AccountLookup{
// The seed is the merkle root of the report, as passed into the input params.
Location: "args.MerkleRoot",
},
}},
},
IsSigner: false,
IsWritable: false,
Expand All @@ -211,9 +211,9 @@ func TestConfig() {
},
// In this case, the user configured multiple seeds. These will be used in conjunction
// with the public key to generate one or multiple PDA accounts.
Seeds: []Lookup{
AccountLookup{Location: "Message.Receiver"},
AccountLookup{Location: "Message.Header.DestChainSelector"},
Seeds: []Seed{
{Dynamic: AccountLookup{Location: "Message.Receiver"}},
{Dynamic: AccountLookup{Location: "Message.Header.DestChainSelector"}},
},
},
// Account constant
Expand Down Expand Up @@ -284,11 +284,11 @@ func TestConfig() {
IsSigner: false,
IsWritable: false,
},
Seeds: []Lookup{
AccountLookup{
Seeds: []Seed{
{Dynamic: AccountLookup{
// The seed is the merkle root of the report, as passed into the input params.
Location: "args.MerkleRoots",
},
}},
},
IsSigner: false,
IsWritable: false,
Expand Down
14 changes: 9 additions & 5 deletions pkg/solana/chainwriter/chain_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,22 +80,22 @@ func parseIDLCodecs(config ChainWriterConfig) (map[string]types.Codec, error) {
for program, programConfig := range config.Programs {
var idl codec.IDL
if err := json.Unmarshal([]byte(programConfig.IDL), &idl); err != nil {
return nil, fmt.Errorf("failed to unmarshal IDL: %w", err)
return nil, fmt.Errorf("failed to unmarshal IDL for program: %s, error: %w", program, err)
}
idlCodec, err := codec.NewIDLInstructionsCodec(idl, binary.LittleEndian())
if err != nil {
return nil, fmt.Errorf("failed to create codec from IDL: %w", err)
return nil, fmt.Errorf("failed to create codec from IDL for program: %s, error: %w", program, err)
}
for method, methodConfig := range programConfig.Methods {
if methodConfig.InputModifications != nil {
modConfig, err := methodConfig.InputModifications.ToModifier(codec.DecoderHooks...)
if err != nil {
return nil, fmt.Errorf("failed to create input modifications: %w", err)
return nil, fmt.Errorf("failed to create input modifications for method %s.%s, error: %w", program, method, err)
}
// add mods to codec
idlCodec, err = codec.NewNamedModifierCodec(idlCodec, method, modConfig)
if err != nil {
return nil, fmt.Errorf("failed to create named codec: %w", err)
return nil, fmt.Errorf("failed to create named codec for method %s.%s, error: %w", program, method, err)
}
}
}
Expand Down Expand Up @@ -250,6 +250,10 @@ func (s *SolanaChainWriterService) SubmitTransaction(ctx context.Context, contra

codec := s.codecs[contractName]
encodedPayload, err := codec.Encode(ctx, args, method)

discriminator := GetDiscriminator(methodConfig.ChainSpecificName)
encodedPayload = append(discriminator[:], encodedPayload...)

if err != nil {
return errorWithDebugID(fmt.Errorf("error encoding transaction payload: %w", err), debugID)
}
Expand Down Expand Up @@ -302,7 +306,7 @@ func (s *SolanaChainWriterService) SubmitTransaction(ctx context.Context, contra
}

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

Expand Down
24 changes: 12 additions & 12 deletions pkg/solana/chainwriter/chain_writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ func TestChainWriter_GetAddresses(t *testing.T) {
Accounts: chainwriter.PDALookups{
Name: "DataAccountPDA",
PublicKey: chainwriter.AccountConstant{Name: "WriteTest", Address: programID.String()},
Seeds: []chainwriter.Lookup{
Seeds: []chainwriter.Seed{
// extract seed2 for PDA lookup
chainwriter.AccountLookup{Name: "seed2", Location: "seed2"},
{Dynamic: chainwriter.AccountLookup{Name: "seed2", Location: "seed2"}},
},
IsSigner: derivedTablePdaLookupMeta.IsSigner,
IsWritable: derivedTablePdaLookupMeta.IsWritable,
Expand Down Expand Up @@ -129,9 +129,9 @@ func TestChainWriter_GetAddresses(t *testing.T) {
chainwriter.PDALookups{
Name: "DataAccountPDA",
PublicKey: chainwriter.AccountConstant{Name: "WriteTest", Address: solana.SystemProgramID.String()},
Seeds: []chainwriter.Lookup{
Seeds: []chainwriter.Seed{
// extract seed1 for PDA lookup
chainwriter.AccountLookup{Name: "seed1", Location: "seed1"},
{Dynamic: chainwriter.AccountLookup{Name: "seed1", Location: "seed1"}},
},
IsSigner: pdaLookupMeta.IsSigner,
IsWritable: pdaLookupMeta.IsWritable,
Expand Down Expand Up @@ -272,9 +272,9 @@ func TestChainWriter_FilterLookupTableAddresses(t *testing.T) {
Accounts: chainwriter.PDALookups{
Name: "DataAccountPDA",
PublicKey: chainwriter.AccountConstant{Name: "WriteTest", Address: programID.String()},
Seeds: []chainwriter.Lookup{
Seeds: []chainwriter.Seed{
// extract seed1 for PDA lookup
chainwriter.AccountLookup{Name: "seed1", Location: "seed1"},
{Dynamic: chainwriter.AccountLookup{Name: "seed1", Location: "seed1"}},
},
IsSigner: true,
IsWritable: true,
Expand All @@ -289,9 +289,9 @@ func TestChainWriter_FilterLookupTableAddresses(t *testing.T) {
Accounts: chainwriter.PDALookups{
Name: "MiscPDA",
PublicKey: chainwriter.AccountConstant{Name: "UnusedAccount", Address: unusedProgramID.String()},
Seeds: []chainwriter.Lookup{
Seeds: []chainwriter.Seed{
// extract seed2 for PDA lookup
chainwriter.AccountLookup{Name: "seed2", Location: "seed2"},
{Dynamic: chainwriter.AccountLookup{Name: "seed2", Location: "seed2"}},
},
IsSigner: true,
IsWritable: true,
Expand Down Expand Up @@ -428,9 +428,9 @@ func TestChainWriter_SubmitTransaction(t *testing.T) {
Accounts: chainwriter.PDALookups{
Name: "DataAccountPDA",
PublicKey: chainwriter.AccountConstant{Name: "WriteTest", Address: programID.String()},
Seeds: []chainwriter.Lookup{
Seeds: []chainwriter.Seed{
// extract seed2 for PDA lookup
chainwriter.AccountLookup{Name: "seed2", Location: "seed2"},
{Dynamic: chainwriter.AccountLookup{Name: "seed2", Location: "seed2"}},
},
IsSigner: false,
IsWritable: false,
Expand Down Expand Up @@ -459,9 +459,9 @@ func TestChainWriter_SubmitTransaction(t *testing.T) {
chainwriter.PDALookups{
Name: "DataAccountPDA",
PublicKey: chainwriter.AccountConstant{Name: "WriteTest", Address: solana.SystemProgramID.String()},
Seeds: []chainwriter.Lookup{
Seeds: []chainwriter.Seed{
// extract seed1 for PDA lookup
chainwriter.AccountLookup{Name: "seed1", Location: "seed1"},
{Dynamic: chainwriter.AccountLookup{Name: "seed1", Location: "seed1"}},
},
IsSigner: false,
IsWritable: false,
Expand Down
6 changes: 5 additions & 1 deletion pkg/solana/chainwriter/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package chainwriter
import (
"context"
"crypto/sha256"
"encoding/binary"
"errors"
"fmt"
"reflect"
Expand Down Expand Up @@ -41,12 +42,15 @@ func GetValuesAtLocation(args any, location string) ([][]byte, error) {
if err != nil {
return nil, err
}

for _, value := range addressList {
if byteArray, ok := value.([]byte); ok {
vals = append(vals, byteArray)
} else if address, ok := value.(solana.PublicKey); ok {
vals = append(vals, address.Bytes())
} else if num, ok := value.(uint64); ok {
buf := make([]byte, 8)
binary.LittleEndian.PutUint64(buf, num)
vals = append(vals, buf)
} else {
return nil, fmt.Errorf("invalid value format at path: %s", location)
}
Expand Down
57 changes: 34 additions & 23 deletions pkg/solana/chainwriter/lookups.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,19 @@ type AccountLookup struct {
IsWritable bool
}

type Seed struct {
Static []byte // Static seed value
Dynamic Lookup // Dynamic lookup for seed
}

// PDALookups generates Program Derived Addresses (PDA) by combining a derived public key with one or more seeds.
type PDALookups struct {
Name string
// The public key of the PDA to be combined with seeds. If there are multiple PublicKeys
// there will be multiple PDAs generated by combining each PublicKey with the seeds.
PublicKey Lookup
// Seeds to be derived from an additional lookup
Seeds []Lookup
Seeds []Seed
IsSigner bool
IsWritable bool
// OPTIONAL: On-chain location and type of desired data from PDA (e.g. a sub-account of the data account)
Expand Down Expand Up @@ -210,29 +215,35 @@ func getSeedBytes(ctx context.Context, lookup PDALookups, args any, derivedTable
var seedBytes [][]byte

for _, seed := range lookup.Seeds {
if lookupSeed, ok := seed.(AccountLookup); ok {
// 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: %w", err)
}
// validate seed length
for _, b := range bytes {
if len(b) > solana.MaxSeedLength {
return nil, fmt.Errorf("seed byte array exceeds maximum length of %d: got %d bytes", solana.MaxSeedLength, len(b))
if seed.Static != nil {
seedBytes = append(seedBytes, seed.Static)
}
if seed.Dynamic != nil {
dynamicSeed := seed.Dynamic
if lookupSeed, ok := dynamicSeed.(AccountLookup); ok {
// Get value from a location (This doens'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: %w", err)
}
// validate seed length
for _, b := range bytes {
if len(b) > solana.MaxSeedLength {
return nil, fmt.Errorf("seed byte array exceeds maximum length of %d: got %d bytes", solana.MaxSeedLength, len(b))
}
seedBytes = append(seedBytes, b)
}
} else {
// Get address seeds from the lookup
seedAddresses, err := GetAddresses(ctx, args, []Lookup{dynamicSeed}, derivedTableMap, reader)
if err != nil {
return nil, fmt.Errorf("error getting address seed: %w", err)
}
seedBytes = append(seedBytes, b)
}
} else {
// Get address seeds from the lookup
seedAddresses, err := GetAddresses(ctx, args, []Lookup{seed}, derivedTableMap, reader)
if err != nil {
return nil, fmt.Errorf("error getting address seed: %w", err)
}

// Add each address seed as bytes
for _, address := range seedAddresses {
seedBytes = append(seedBytes, address.PublicKey.Bytes())
// Add each address seed as bytes
for _, address := range seedAddresses {
seedBytes = append(seedBytes, address.PublicKey.Bytes())
}
}
}
}
Expand Down Expand Up @@ -266,7 +277,7 @@ func (s *SolanaChainWriterService) ResolveLookupTables(ctx context.Context, args

// Read derived lookup tables
for _, derivedLookup := range lookupTables.DerivedLookupTables {
// Load the lookup table - note: This could be multiple tables if the lookup is a PDALookups that resovles to more
// 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, s.reader, derivedTableMap)
if err != nil {
Expand Down

0 comments on commit a9dceaa

Please sign in to comment.