Skip to content

Commit

Permalink
Merge branch 'develop' into NONEVM-746-LogPoller-ObservedORM
Browse files Browse the repository at this point in the history
  • Loading branch information
DylanTinianov authored Mar 3, 2025
2 parents e9ea5ca + c202462 commit 6d2a258
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 22 deletions.
6 changes: 3 additions & 3 deletions pkg/solana/chainwriter/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,16 +112,16 @@ func GetDebugIDAtLocation(args any, location string) (string, error) {
return "", errors.New("no debug ID found at location: " + location)
}
// there should only be one debug ID, others will be ignored.
debugID := string(debugIDList[0])
debugID := ccipocr3.Bytes32(debugIDList[0])

return debugID, nil
return debugID.String(), nil
}

func errorWithDebugID(err error, debugID string) error {
if debugID == "" {
return err
}
return fmt.Errorf("Debug ID: %s: Error: %s", debugID, err)
return fmt.Errorf("Debug ID: %s: Error: %w", debugID, err)
}

// traversePath recursively traverses the given structure based on the provided path.
Expand Down
34 changes: 19 additions & 15 deletions pkg/solana/chainwriter/lookups.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func (l Lookup) Resolve(ctx context.Context, args any, derivedTableMap map[strin
func (ac AccountConstant) Resolve() ([]*solana.AccountMeta, error) {
address, err := solana.PublicKeyFromBase58(ac.Address)
if err != nil {
return nil, fmt.Errorf("error getting account from constant: %w", err)
return nil, lookupErrWithName(ac.Name, fmt.Errorf("error getting account from constant: %w", err))
}
return []*solana.AccountMeta{
{
Expand All @@ -153,18 +153,18 @@ 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("%w: %v", ErrLookupNotFoundAtLocation, err)
return nil, lookupErrWithName(al.Name, fmt.Errorf("%w: %v", ErrLookupNotFoundAtLocation, err))
}

var metas []*solana.AccountMeta
signerIndexes, err := resolveBitMap(al.IsSigner, args, len(derivedValues))
if err != nil {
return nil, err
return nil, lookupErrWithName(al.Name, fmt.Errorf("failed to resolve signer bit map: %w", err))
}

writerIndexes, err := resolveBitMap(al.IsWritable, args, len(derivedValues))
if err != nil {
return nil, err
return nil, lookupErrWithName(al.Name, fmt.Errorf("failed to resolve writer bit map: %w", err))
}

for i, address := range derivedValues {
Expand Down Expand Up @@ -230,7 +230,7 @@ func (alt AccountsFromLookupTable) Resolve(derivedTableMap map[string]map[string
for publicKey, metas := range innerMap {
for _, index := range alt.IncludeIndexes {
if index < 0 || index >= len(metas) {
return nil, fmt.Errorf("invalid index %d for account %s in lookup table %s", index, publicKey, alt.LookupTableName)
return nil, lookupErrWithName(alt.LookupTableName, fmt.Errorf("invalid index %d for account %s", index, publicKey))
}
result = append(result, metas[index])
}
Expand All @@ -242,17 +242,17 @@ func (alt AccountsFromLookupTable) Resolve(derivedTableMap map[string]map[string
func (pda PDALookups) Resolve(ctx context.Context, args any, derivedTableMap map[string]map[string][]*solana.AccountMeta, client client.MultiClient) ([]*solana.AccountMeta, error) {
publicKeys, err := GetAddresses(ctx, args, []Lookup{pda.PublicKey}, derivedTableMap, client)
if err != nil {
return nil, fmt.Errorf("error getting public key for PDALookups: %w", err)
return nil, lookupErrWithName(pda.Name, fmt.Errorf("error getting public key for PDALookups: %w", err))
}

seeds, err := getSeedBytesCombinations(ctx, pda, args, derivedTableMap, client)
if err != nil {
return nil, fmt.Errorf("error getting seeds for PDALookups: %w", err)
return nil, lookupErrWithName(pda.Name, fmt.Errorf("error getting seeds for PDALookups: %w", err))
}

pdas, err := generatePDAs(publicKeys, seeds, pda)
if err != nil {
return nil, fmt.Errorf("error generating PDAs: %w", err)
return nil, lookupErrWithName(pda.Name, fmt.Errorf("error generating PDAs: %w", err))
}

if pda.InternalField.Location == "" {
Expand All @@ -268,37 +268,37 @@ func (pda PDALookups) Resolve(ctx context.Context, args any, derivedTableMap map
})

if err != nil || accountInfo == nil || accountInfo.Value == nil {
return nil, fmt.Errorf("error fetching account info for PDA account: %s, error: %w", accountMeta.PublicKey.String(), err)
return nil, lookupErrWithName(pda.Name, fmt.Errorf("error fetching account info for PDA account: %s, error: %w", accountMeta.PublicKey.String(), err))
}

var idlCodec codec.IDL
if err = json.Unmarshal([]byte(pda.InternalField.IDL), &idlCodec); err != nil {
return nil, fmt.Errorf("failed to unmarshal IDL for PDA: %s, error: %w", pda.Name, err)
return nil, lookupErrWithName(pda.Name, fmt.Errorf("failed to unmarshal IDL: %w", err))
}

internalType := pda.InternalField.TypeName

idlDef, err := codec.FindDefinitionFromIDL(codec.ChainConfigTypeAccountDef, internalType, idlCodec)
if err != nil {
return nil, fmt.Errorf("error finding definition for type %s: %w", internalType, err)
return nil, lookupErrWithName(pda.Name, fmt.Errorf("error finding definition for type %s: %w", internalType, err))
}

input, err := codec.CreateCodecEntry(idlDef, internalType, idlCodec, nil)
if err != nil {
return nil, fmt.Errorf("failed to create codec entry for method %s, error: %w", internalType, err)
return nil, lookupErrWithName(pda.Name, fmt.Errorf("failed to create codec entry for type %s, error: %w", internalType, err))
}

decoded, _, err := input.Decode(accountInfo.Value.Data.GetBinary())
if err != nil {
return nil, fmt.Errorf("error decoding account data: %w", err)
return nil, lookupErrWithName(pda.Name, fmt.Errorf("error decoding account data: %w", err))
}

value, err := GetValuesAtLocation(decoded, pda.InternalField.Location)
if err != nil {
return nil, fmt.Errorf("error getting value at location: %w", err)
return nil, lookupErrWithName(pda.Name, fmt.Errorf("error getting value at location %s: %w", pda.InternalField.Location, err))
}
if len(value) > 1 {
return nil, fmt.Errorf("multiple values found at location: %s", pda.InternalField.Location)
return nil, lookupErrWithName(pda.Name, fmt.Errorf("multiple values found at location %s", pda.InternalField.Location))
}

result = append(result, &solana.AccountMeta{
Expand Down Expand Up @@ -416,3 +416,7 @@ func generatePDAs(

return results, nil
}

func lookupErrWithName(name string, err error) error {
return fmt.Errorf("lookup: %s, err: %w", name, err)
}
2 changes: 2 additions & 0 deletions pkg/solana/codec/anchoridl.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ type IdlTypeDefTyKind string
const (
IdlTypeDefTyKindStruct IdlTypeDefTyKind = "struct"
IdlTypeDefTyKindEnum IdlTypeDefTyKind = "enum"
IdlTypeDefTyKindCustom IdlTypeDefTyKind = "custom"
)

type IdlTypeDefTyStruct struct {
Expand All @@ -380,6 +381,7 @@ type IdlTypeDefTy struct {

Fields *IdlTypeDefStruct `json:"fields,omitempty"`
Variants IdlEnumVariantSlice `json:"variants,omitempty"`
Codec string `json:"codec,omitempty"`
}

type IdlEnumVariantSlice []IdlEnumVariant
Expand Down
72 changes: 72 additions & 0 deletions pkg/solana/codec/onramp_address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package codec

import (
"fmt"
"reflect"

"github.com/smartcontractkit/chainlink-common/pkg/codec/encodings"
"github.com/smartcontractkit/chainlink-common/pkg/types"
)

func NewOnRampAddress(builder encodings.Builder) encodings.TypeCodec {
return &onRampAddress{
intEncoder: builder.Uint32(),
}
}

type onRampAddress struct {
intEncoder encodings.TypeCodec
}

var _ encodings.TypeCodec = &onRampAddress{}

func (d *onRampAddress) Encode(value any, into []byte) ([]byte, error) {
bi, ok := value.([]byte)
if !ok {
return nil, fmt.Errorf("%w: expected []byte, got %T", types.ErrInvalidType, value)
}

length := len(bi)
if length > 64 {
return nil, fmt.Errorf("%w: expected []byte to be 64 bytes or less, got %v", types.ErrInvalidType, length)
}
// assert 64 bytes or less
var buf [64]byte
copy(buf[:], bi)

// 64 bytes, padded, then len u32
into = append(into, buf[:]...)
return d.intEncoder.Encode(uint32(length), into)
}

func (d *onRampAddress) Decode(encoded []byte) (any, []byte, error) {
buf := encoded[0:64]
encoded = encoded[64:]

// decode uint32 len
l, bytes, err := d.intEncoder.Decode(encoded)
if err != nil {
return nil, bytes, err
}

length, ok := l.(uint32)
if !ok {
return nil, bytes, fmt.Errorf("expected uint32, got %T", l)
}

return buf[:length], bytes, nil
}

func (d *onRampAddress) GetType() reflect.Type {
return reflect.TypeOf([]byte{})
}

func (d *onRampAddress) Size(val int) (int, error) {
// 64 bytes + uint32
return 64 + 4, nil
}

func (d *onRampAddress) FixedSize() (int, error) {
// 64 bytes + uint32
return 64 + 4, nil
}
59 changes: 59 additions & 0 deletions pkg/solana/codec/option.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package codec

import (
"fmt"
"reflect"

"github.com/smartcontractkit/chainlink-common/pkg/codec/encodings"
commonencodings "github.com/smartcontractkit/chainlink-common/pkg/codec/encodings"
)

func NewOption(codec commonencodings.TypeCodec) encodings.TypeCodec {
return &option{
codec,
}
}

type option struct {
codec encodings.TypeCodec
}

var _ encodings.TypeCodec = &option{}

func (d *option) Encode(value any, into []byte) ([]byte, error) {
// encoding is either 0 for None, or 1, bytes... for Some(val)
if value == nil {
return append(into, 0), nil
}

into = append(into, 1)
return d.codec.Encode(value, into)
}

func (d *option) Decode(encoded []byte) (any, []byte, error) {
prefix := encoded[0]
bytes := encoded[1:]

// encoding is either 0 for None, or 1, bytes... for Some(val)
if prefix == 0 {
return reflect.Zero(d.codec.GetType()).Interface(), encoded[1:], nil
}

if prefix != 1 {
return nil, encoded, fmt.Errorf("expected either 0 or 1, got %v", prefix)
}

return d.codec.Decode(bytes)
}

func (d *option) GetType() reflect.Type {
return d.codec.GetType()
}

func (d *option) Size(val int) (int, error) {
return d.codec.Size(val)
}

func (d *option) FixedSize() (int, error) {
return d.codec.FixedSize()
}
11 changes: 9 additions & 2 deletions pkg/solana/codec/solana.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,13 @@ func createCodecType(
return name, nil, fmt.Errorf("%w: variants are not supported", commontypes.ErrInvalidConfig)
}
return name, refs.builder.Uint8(), nil
case IdlTypeDefTyKindCustom:
switch def.Type.Codec {
case "onramp_address":
return name, NewOnRampAddress(refs.builder), nil
default:
return name, nil, fmt.Errorf(unknownIDLFormat, commontypes.ErrInvalidConfig, def.Type.Codec)
}
default:
return name, nil, fmt.Errorf(unknownIDLFormat, commontypes.ErrInvalidConfig, def.Type.Kind)
}
Expand Down Expand Up @@ -301,8 +308,8 @@ func processFieldType(parentTypeName string, idlType IdlType, refs *codecRefs) (
return getCodecByStringType(idlType.GetString(), refs.builder)
case idlType.IsIdlTypeOption():
// Go doesn't have an `Option` type; use pointer to type instead
// this should be automatic in the codec
return processFieldType(parentTypeName, idlType.GetIdlTypeOption().Option, refs)
inner, err := processFieldType(parentTypeName, idlType.GetIdlTypeOption().Option, refs)
return NewOption(inner), err
case idlType.IsIdlTypeDefined():
return asDefined(parentTypeName, idlType.GetIdlTypeDefined(), refs)
case idlType.IsArray():
Expand Down
4 changes: 2 additions & 2 deletions pkg/solana/codec/solana_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func TestNewIDLAccountCodec(t *testing.T) {
bts, err := entry.Encode(ctx, expected, testutils.TestStructWithNestedStruct)

// length of fields + discriminator
require.Equal(t, 262, len(bts))
require.Equal(t, 263, len(bts))
require.NoError(t, err)

var decoded testutils.StructWithNestedStruct
Expand Down Expand Up @@ -73,7 +73,7 @@ func TestNewIDLDefinedTypesCodecCodec(t *testing.T) {
bts, err := entry.Encode(ctx, expected, testutils.TestStructWithNestedStructType)

// length of fields without a discriminator
require.Equal(t, 254, len(bts))
require.Equal(t, 255, len(bts))

require.NoError(t, err)

Expand Down

0 comments on commit 6d2a258

Please sign in to comment.