Skip to content

Commit

Permalink
[NONEVM-1091] - Refactor/Setup CR init and cfg and codec init (#991)
Browse files Browse the repository at this point in the history
* Refactor CR init and cfg

* Fix most of the interface tests

* Fix nil idlType handling and update test IDL names

* lint and fix CR integration tests cfg

* Improve Contract Reader cfg handling

* Standardize var name 4 read mapping to genericName<>chainSpecificName

* Revert Solana codec encoder from LenientCodecFromTypeCodec to strict

* lint

* Improve panic handling and add a test for lenient decoding

* Remove account info opts from CR

* lint
  • Loading branch information
ilija42 authored Dec 30, 2024
1 parent e2ff830 commit 4d88833
Show file tree
Hide file tree
Showing 21 changed files with 538 additions and 425 deletions.
68 changes: 36 additions & 32 deletions integration-tests/relayinterface/chain_components_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package relayinterface
import (
"context"
"encoding/binary"
"encoding/json"
"io"
"os"
"path/filepath"
Expand All @@ -19,14 +20,16 @@ import (
"github.com/gagliardetto/solana-go/text"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink-common/pkg/codec"
commoncodec "github.com/smartcontractkit/chainlink-common/pkg/codec"
"github.com/smartcontractkit/chainlink-common/pkg/logger"
commontestutils "github.com/smartcontractkit/chainlink-common/pkg/loop/testutils"
"github.com/smartcontractkit/chainlink-common/pkg/types"
. "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with .
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"

"github.com/smartcontractkit/chainlink-solana/pkg/solana/codec"

contract "github.com/smartcontractkit/chainlink-solana/contracts/generated/contract_reader_interface"
"github.com/smartcontractkit/chainlink-solana/integration-tests/solclient"
"github.com/smartcontractkit/chainlink-solana/integration-tests/utils"
Expand Down Expand Up @@ -105,15 +108,15 @@ func RunChainComponentsInLoopSolanaTests[T TestingT[T]](t T, it ChainComponentsI
func RunContractReaderSolanaTests[T TestingT[T]](t T, it *SolanaChainComponentsInterfaceTester[T]) {
RunContractReaderInterfaceTests(t, it, false, true)

testCases := []Testcase[T]{}
var testCases []Testcase[T]

RunTests(t, it, testCases)
}

func RunContractReaderInLoopTests[T TestingT[T]](t T, it ChainComponentsInterfaceTester[T]) {
RunContractReaderInterfaceTests(t, it, false, true)

testCases := []Testcase[T]{}
var testCases []Testcase[T]

RunTests(t, it, testCases)
}
Expand All @@ -129,50 +132,41 @@ type SolanaChainComponentsInterfaceTesterHelper[T TestingT[T]] interface {

type SolanaChainComponentsInterfaceTester[T TestingT[T]] struct {
TestSelectionSupport
Helper SolanaChainComponentsInterfaceTesterHelper[T]
cr *chainreader.SolanaChainReaderService
chainReaderConfig config.ChainReader
Helper SolanaChainComponentsInterfaceTesterHelper[T]
cr *chainreader.SolanaChainReaderService
contractReaderConfig config.ContractReader
}

func (it *SolanaChainComponentsInterfaceTester[T]) Setup(t T) {
t.Cleanup(func() {})

it.chainReaderConfig = config.ChainReader{
Namespaces: map[string]config.ChainReaderMethods{
it.contractReaderConfig = config.ContractReader{
Namespaces: map[string]config.ChainContractReader{
AnyContractName: {
Methods: map[string]config.ChainDataReader{
IDL: mustUnmarshalIDL(t, string(it.Helper.GetJSONEncodedIDL(t))),
Reads: map[string]config.ReadDefinition{
MethodReturningUint64: {
AnchorIDL: string(it.Helper.GetJSONEncodedIDL(t)),
Encoding: config.EncodingTypeBorsh,
Procedure: config.ChainReaderProcedure{
IDLAccount: "DataAccount",
OutputModifications: codec.ModifiersConfig{
&codec.PropertyExtractorConfig{FieldName: "U64Value"},
},
ChainSpecificName: "DataAccount",
ReadType: config.Account,
OutputModifications: commoncodec.ModifiersConfig{
&commoncodec.PropertyExtractorConfig{FieldName: "U64Value"},
},
},
MethodReturningUint64Slice: {
AnchorIDL: string(it.Helper.GetJSONEncodedIDL(t)),
Encoding: config.EncodingTypeBorsh,
Procedure: config.ChainReaderProcedure{
IDLAccount: "DataAccount",
OutputModifications: codec.ModifiersConfig{
&codec.PropertyExtractorConfig{FieldName: "U64Slice"},
},
ChainSpecificName: "DataAccount",
OutputModifications: commoncodec.ModifiersConfig{
&commoncodec.PropertyExtractorConfig{FieldName: "U64Slice"},
},
},
},
},
AnySecondContractName: {
Methods: map[string]config.ChainDataReader{
IDL: mustUnmarshalIDL(t, string(it.Helper.GetJSONEncodedIDL(t))),
Reads: map[string]config.ReadDefinition{
MethodReturningUint64: {
AnchorIDL: string(it.Helper.GetJSONEncodedIDL(t)),
Encoding: config.EncodingTypeBorsh,
Procedure: config.ChainReaderProcedure{
IDLAccount: "DataAccount",
OutputModifications: codec.ModifiersConfig{
&codec.PropertyExtractorConfig{FieldName: "U64Value"},
},
ChainSpecificName: "DataAccount",
OutputModifications: commoncodec.ModifiersConfig{
&commoncodec.PropertyExtractorConfig{FieldName: "U64Value"},
},
},
},
Expand All @@ -199,7 +193,7 @@ func (it *SolanaChainComponentsInterfaceTester[T]) GetContractReader(t T) types.
return it.cr
}

svc, err := chainreader.NewChainReaderService(it.Helper.Logger(t), it.Helper.RPCClient(), it.chainReaderConfig)
svc, err := chainreader.NewChainReaderService(it.Helper.Logger(t), it.Helper.RPCClient(), it.contractReaderConfig)

require.NoError(t, err)
require.NoError(t, svc.Start(ctx))
Expand Down Expand Up @@ -423,3 +417,13 @@ func setupTestValidator(t *testing.T, upgradeAuthority string) (string, string)

return client.SetupLocalSolNodeWithFlags(t, flags...)
}

func mustUnmarshalIDL[T TestingT[T]](t T, rawIDL string) codec.IDL {
var idl codec.IDL
if err := json.Unmarshal([]byte(rawIDL), &idl); err != nil {
t.Errorf("failed to unmarshal test IDL", err)
t.FailNow()
}

return idl
}
30 changes: 16 additions & 14 deletions pkg/solana/chainreader/account_read_binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,32 @@ import (
"context"

"github.com/gagliardetto/solana-go"
"github.com/gagliardetto/solana-go/rpc"

"github.com/smartcontractkit/chainlink-common/pkg/types"

"github.com/smartcontractkit/chainlink-solana/pkg/solana/codec"
)

// accountReadBinding provides decoding and reading Solana Account data using a defined codec. The
// `idlAccount` refers to the account name in the IDL for which the codec has a type mapping.
// accountReadBinding provides decoding and reading Solana Account data using a defined codec.
type accountReadBinding struct {
idlAccount string
codec types.RemoteCodec
key solana.PublicKey
opts *rpc.GetAccountInfoOpts
namespace, genericName string
codec types.RemoteCodec
key solana.PublicKey
}

func newAccountReadBinding(acct string, codec types.RemoteCodec, opts *rpc.GetAccountInfoOpts) *accountReadBinding {
func newAccountReadBinding(namespace, genericName string) *accountReadBinding {
return &accountReadBinding{
idlAccount: acct,
codec: codec,
opts: opts,
namespace: namespace,
genericName: genericName,
}
}

var _ readBinding = &accountReadBinding{}

func (b *accountReadBinding) SetCodec(codec types.RemoteCodec) {
b.codec = codec
}

func (b *accountReadBinding) SetAddress(key solana.PublicKey) {
b.key = key
}
Expand All @@ -36,10 +38,10 @@ func (b *accountReadBinding) GetAddress() solana.PublicKey {
return b.key
}

func (b *accountReadBinding) CreateType(_ bool) (any, error) {
return b.codec.CreateType(b.idlAccount, false)
func (b *accountReadBinding) CreateType(forEncoding bool) (any, error) {
return b.codec.CreateType(codec.WrapItemType(forEncoding, b.namespace, b.genericName, codec.ChainConfigTypeAccountDef), forEncoding)
}

func (b *accountReadBinding) Decode(ctx context.Context, bts []byte, outVal any) error {
return b.codec.Decode(ctx, bts, outVal, b.idlAccount)
return b.codec.Decode(ctx, bts, outVal, codec.WrapItemType(false, b.namespace, b.genericName, codec.ChainConfigTypeAccountDef))
}
1 change: 0 additions & 1 deletion pkg/solana/chainreader/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ func doMethodBatchCall(ctx context.Context, client MultipleAccountGetter, bindin
results[idx].err,
binding.Decode(ctx, data[idx], results[idx].returnVal),
)

continue
}

Expand Down
9 changes: 9 additions & 0 deletions pkg/solana/chainreader/bindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
type readBinding interface {
SetAddress(solana.PublicKey)
GetAddress() solana.PublicKey
SetCodec(types.RemoteCodec)
CreateType(bool) (any, error)
Decode(context.Context, []byte, any) error
}
Expand Down Expand Up @@ -70,3 +71,11 @@ func (b namespaceBindings) Bind(binding types.BoundContract) error {

return nil
}

func (b namespaceBindings) SetCodec(codec types.RemoteCodec) {
for _, nbs := range b {
for _, rb := range nbs {
rb.SetCodec(codec)
}
}
}
2 changes: 2 additions & 0 deletions pkg/solana/chainreader/bindings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ type mockBinding struct {
mock.Mock
}

func (_m *mockBinding) SetCodec(_ types.RemoteCodec) {}

func (_m *mockBinding) SetAddress(_ solana.PublicKey) {}

func (_m *mockBinding) GetAddress() solana.PublicKey {
Expand Down
Loading

0 comments on commit 4d88833

Please sign in to comment.