From 47ae4aeb5955b9e38f758bd978e7b1ec4ba9f976 Mon Sep 17 00:00:00 2001 From: ilija Date: Thu, 12 Dec 2024 18:03:37 -0500 Subject: [PATCH] progress --- pkg/solana/codec/codec_entry.go | 50 ++-- pkg/solana/codec/codec_test.go | 42 +-- pkg/solana/codec/solana.go | 127 +++++--- pkg/solana/codec/testutils/converters.go | 28 +- .../test_item_slice_type/TestItemSliceType.go | 110 +++++++ .../test_item_slice_type/instructions.go | 118 ++++++++ .../itemSliceTypeIDL.json | 185 ++++++------ .../testutils/test_item_slice_type/types.go | 283 ------------------ .../testutils/test_item_type/accounts.go | 14 +- .../testutils/test_item_type/itemIDL.json | 13 +- pkg/solana/codec/testutils/types.go | 19 +- pkg/solana/codec/types.go | 11 +- 12 files changed, 499 insertions(+), 501 deletions(-) create mode 100644 pkg/solana/codec/testutils/test_item_slice_type/TestItemSliceType.go create mode 100644 pkg/solana/codec/testutils/test_item_slice_type/instructions.go delete mode 100644 pkg/solana/codec/testutils/test_item_slice_type/types.go diff --git a/pkg/solana/codec/codec_entry.go b/pkg/solana/codec/codec_entry.go index bd24ea3d8..1139cf7f6 100644 --- a/pkg/solana/codec/codec_entry.go +++ b/pkg/solana/codec/codec_entry.go @@ -16,31 +16,31 @@ type Entry interface { Modifier() codec.Modifier } -// TODO this can also be an event entry, but anchor-go defines events differently, maybe just have a separate struct and method that satisfy entry interface for events. -func NewEntry(idlAccount IdlTypeDef, idlTypes IdlTypeDefSlice, includeDiscriminator bool, mod codec.Modifier, builder commonencodings.Builder) (Entry, error) { - refs := &codecRefs{ - builder: builder, - codecs: make(map[string]commonencodings.TypeCodec), - typeDefs: idlTypes, - dependencies: make(map[string][]string), - } - - if mod == nil { - mod = codec.MultiModifier{} - } - - _, accCodec, err := createCodecType(idlAccount, refs, false) - if err != nil { - return nil, err - } - - entry := &codecEntry{name: idlAccount.Name, includeDiscriminator: includeDiscriminator, codecType: accCodec, typ: accCodec.GetType(), mod: mod} - if entry.includeDiscriminator { - entry.Discriminator = commonencodings.NamedTypeCodec{Name: "Discriminator" + idlAccount.Name, Codec: NewDiscriminator(idlAccount.Name)} - } - - return entry, nil -} +//// TODO this can also be an event entry, but anchor-go defines events differently, maybe just have a separate struct and method that satisfy entry interface for events. +//func NewEntry(idlAccount IdlTypeDef, idlTypes IdlTypeDefSlice, includeDiscriminator bool, mod codec.Modifier, builder commonencodings.Builder) (Entry, error) { +// refs := &codecRefs{ +// builder: builder, +// codecs: make(map[string]commonencodings.TypeCodec), +// typeDefs: idlTypes, +// dependencies: make(map[string][]string), +// } +// +// if mod == nil { +// mod = codec.MultiModifier{} +// } +// +// _, accCodec, err := createCodecType(idlAccount, refs, false) +// if err != nil { +// return nil, err +// } +// +// entry := &codecEntry{name: idlAccount.Name, includeDiscriminator: includeDiscriminator, codecType: accCodec, typ: accCodec.GetType(), mod: mod} +// if entry.includeDiscriminator { +// entry.Discriminator = commonencodings.NamedTypeCodec{Name: "Discriminator" + idlAccount.Name, Codec: NewDiscriminator(idlAccount.Name)} +// } +// +// return entry, nil +//} type codecEntry struct { name string diff --git a/pkg/solana/codec/codec_test.go b/pkg/solana/codec/codec_test.go index 3fc121cb0..7e27b83b2 100644 --- a/pkg/solana/codec/codec_test.go +++ b/pkg/solana/codec/codec_test.go @@ -16,6 +16,7 @@ import ( . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with . "github.com/smartcontractkit/chainlink-solana/pkg/solana/codec" "github.com/smartcontractkit/chainlink-solana/pkg/solana/codec/testutils" + "github.com/smartcontractkit/chainlink-solana/pkg/solana/codec/testutils/test_item_slice_type" "github.com/smartcontractkit/chainlink-solana/pkg/solana/codec/testutils/test_item_type" ) @@ -52,21 +53,29 @@ func (it *codecInterfaceTester) EncodeFields(t *testing.T, request *EncodeReques func encodeFieldsOnItem(t *testing.T, request *EncodeRequest) ocr2types.Report { buf := new(bytes.Buffer) - if err := testutils.EncodeRequestToTestStruct(request).MarshalWithEncoder(bin.NewBorshEncoder(buf)); err != nil { + if err := testutils.EncodeRequestToTestItem(request).MarshalWithEncoder(bin.NewBorshEncoder(buf)); err != nil { require.NoError(t, err) } return buf.Bytes() } -func encodeFieldsOnSliceOrArray(_ *testing.T, request *EncodeRequest) []byte { +func encodeFieldsOnSliceOrArray(t *testing.T, request *EncodeRequest) []byte { args := make([]any, 1) switch request.TestOn { + case testutils.TestItemSliceType: + testItemSlice := []test_item_type.TestItem{testutils.ToInternalType(request.TestStructs[0])} + buf := new(bytes.Buffer) + if err := test_item_slice_type.NewTestItemSliceTypeInstructionBuilder().SetTestItemSliceType(testItemSlice).Build().MarshalWithEncoder(bin.NewBorshEncoder(buf)); err != nil { + require.NoError(t, err) + return nil + } + return buf.Bytes() case testutils.TestItemArray1Type: - args[0] = [1]test_item_type.TestStruct{testutils.ToInternalType(request.TestStructs[0])} + args[0] = [1]test_item_type.TestItem{testutils.ToInternalType(request.TestStructs[0])} case testutils.TestItemArray2Type: - args[0] = [2]test_item_type.TestStruct{testutils.ToInternalType(request.TestStructs[0]), testutils.ToInternalType(request.TestStructs[1])} + args[0] = [2]test_item_type.TestItem{testutils.ToInternalType(request.TestStructs[0]), testutils.ToInternalType(request.TestStructs[1])} default: - tmp := make([]test_item_type.TestStruct, len(request.TestStructs)) + tmp := make([]test_item_type.TestItem, len(request.TestStructs)) for i, ts := range request.TestStructs { tmp[i] = testutils.ToInternalType(ts) } @@ -78,29 +87,20 @@ func encodeFieldsOnSliceOrArray(_ *testing.T, request *EncodeRequest) []byte { func (it *codecInterfaceTester) GetCodec(t *testing.T) clcommontypes.Codec { codecConfig := codec.Config{Configs: map[string]codec.ChainConfig{}} - testStruct := CreateTestStruct[*testing.T](0, it) + TestItem := CreateTestStruct[*testing.T](0, it) for k, v := range testutils.CodecDefs { entry := codecConfig.Configs[k] - entry.IDL = v + entry.IDL = v.IDL + entry.Type = v.ItemType - if slices.Contains([]string{testutils.TestItemSliceType, testutils.TestItemArray1Type, testutils.TestItemArray2Type}, k) { - entry.ModifierConfigs = commoncodec.ModifiersConfig{ - &commoncodec.RenameModifierConfig{Fields: map[string]string{"Items.NestedDynamicStruct.Inner.IntVal": "I"}}, - &commoncodec.RenameModifierConfig{Fields: map[string]string{"Items.NestedStaticStruct.Inner.IntVal": "I"}}, - &commoncodec.AddressBytesToStringModifierConfig{ - Fields: []string{"Items.AccountStruct.AccountStr"}, - Modifier: codec.SolanaAddressModifier{}, - }, - &commoncodec.WrapperModifierConfig{Fields: map[string]string{"Items.NestedStaticStruct.Inner.IntVal": "I"}}, - } - } else if k != testutils.SizeItemType && k != testutils.NilType { + if k != testutils.SizeItemType && k != testutils.NilType { entry.ModifierConfigs = commoncodec.ModifiersConfig{ &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}}, &commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}}, } } - if slices.Contains([]string{testutils.TestItemType, testutils.TestItemWithConfigExtra}, k) { + if slices.Contains([]string{testutils.TestItemType, testutils.TestItemSliceType, testutils.TestItemWithConfigExtra}, k) { addressByteModifier := &commoncodec.AddressBytesToStringModifierConfig{ Fields: []string{"AccountStruct.AccountStr"}, Modifier: codec.SolanaAddressModifier{}, @@ -111,8 +111,8 @@ func (it *codecInterfaceTester) GetCodec(t *testing.T) clcommontypes.Codec { if k == testutils.TestItemWithConfigExtra { hardCode := &commoncodec.HardCodeModifierConfig{ OnChainValues: map[string]any{ - "BigField": testStruct.BigField.String(), - "AccountStruct.Account": solana.PublicKeyFromBytes(testStruct.AccountStruct.Account), + "BigField": TestItem.BigField.String(), + "AccountStruct.Account": solana.PublicKeyFromBytes(TestItem.AccountStruct.Account), }, OffChainValues: map[string]any{"ExtraField": anyExtraValue}, } diff --git a/pkg/solana/codec/solana.go b/pkg/solana/codec/solana.go index 203f1ad39..109c3980d 100644 --- a/pkg/solana/codec/solana.go +++ b/pkg/solana/codec/solana.go @@ -85,50 +85,94 @@ func NewCodec(conf Config) (commontypes.RemoteCodec, error) { DecoderDefs: map[string]Entry{}, } - for k, v := range conf.Configs { + for typeName, cfg := range conf.Configs { var idl IDL - if err := json.Unmarshal([]byte(v.IDL), &idl); err != nil { + var codecType commonencodings.TypeCodec + + if err := json.Unmarshal([]byte(cfg.IDL), &idl); err != nil { return nil, err } - mod, err := v.ModifierConfigs.ToModifier(DecoderHooks...) + refs := &codecRefs{ + builder: binary.LittleEndian(), + codecs: make(map[string]commonencodings.TypeCodec), + typeDefs: idl.Types, + dependencies: make(map[string][]string), + } + + mod, err := cfg.ModifierConfigs.ToModifier(DecoderHooks...) if err != nil { return nil, err } - var newEntry Entry - if v.AccountDef != nil && v.EventDef != nil { - return nil, fmt.Errorf("can't have both account and event definitions in codec config") - } else if v.AccountDef != nil { - newEntry, err = NewEntry(*v.AccountDef, idl.Types, true, mod, binary.LittleEndian()) + if mod == nil { + mod = commoncodec.MultiModifier{} + } + + includeDiscriminator := true + switch cfg.Type { + case ChainConfigTypeAccountDef: + var account *IdlTypeDef + for _, acc := range idl.Accounts { + if acc.Name == typeName { + account = &acc + break + } + } + + if account == nil { + return nil, fmt.Errorf("account %s not found in IDL", typeName) + } + + _, codecType, err = createCodecType(*account, refs, false) if err != nil { return nil, err } - } else { - // TODO - return nil, fmt.Errorf("event definition parsing is not implemented") - } - parsed.EncoderDefs[k] = newEntry - parsed.DecoderDefs[k] = newEntry - } - return parsed.ToCodec() -} + includeDiscriminator = true + case ChainConfigTypeInstructionDef: + var instruction *IdlInstruction + for _, i := range idl.Instructions { + fmt.Println("instructions ", i) + if i.Name == typeName { + instruction = &i + break + } + } -func NewNamedModifierCodec(original commontypes.RemoteCodec, itemType string, modifier commoncodec.Modifier) (commontypes.RemoteCodec, error) { - mod, err := commoncodec.NewByItemTypeModifier(map[string]commoncodec.Modifier{itemType: modifier}) - if err != nil { - return nil, err - } + if instruction == nil { + return nil, fmt.Errorf("instruction %s not found in IDL", typeName) + } - modCodec, err := commoncodec.NewModifierCodec(original, mod, DecoderHooks...) - if err != nil { - return nil, err + _, codecType, err = asStruct(instruction.Args, refs, instruction.Name, false, true) + if err != nil { + return nil, err + } + + //includeDiscriminator = true + case ChainConfigTypeEventDef: + return nil, fmt.Errorf("TODO, unimplemented type: %s", cfg.Type) + default: + return nil, fmt.Errorf("unknown type: %s", cfg.Type) + } + + entry := &codecEntry{name: typeName, includeDiscriminator: includeDiscriminator, codecType: codecType, typ: codecType.GetType(), mod: mod} + if entry.includeDiscriminator { + fmt.Println("Yes? ", typeName) + fmt.Println("discriminator ", "Discriminator"+typeName) + entry.Discriminator = commonencodings.NamedTypeCodec{Name: "Discriminator" + typeName, Codec: NewDiscriminator(typeName)} + } + + parsed.EncoderDefs[typeName] = entry + parsed.DecoderDefs[typeName] = entry } - _, err = modCodec.CreateType(itemType, true) + return parsed.ToCodec() +} - return modCodec, err +// NewIDLAccountCodec is for Anchor custom types +func NewIDLAccountCodec(idl IDL, builder commonencodings.Builder) (commontypes.RemoteCodec, error) { + return newIDLCoded(idl, builder, idl.Accounts, true) } func NewIDLInstructionsCodec(idl IDL, builder commonencodings.Builder) (commontypes.RemoteCodec, error) { @@ -141,7 +185,7 @@ func NewIDLInstructionsCodec(idl IDL, builder commonencodings.Builder) (commonty } for _, instruction := range idl.Instructions { - name, instCodec, err := asStruct(instruction.Args, refs, instruction.Name, false) + name, instCodec, err := asStruct(instruction.Args, refs, instruction.Name, false, false) if err != nil { return nil, err } @@ -152,9 +196,20 @@ func NewIDLInstructionsCodec(idl IDL, builder commonencodings.Builder) (commonty return typeCodecs, nil } -// NewIDLAccountCodec is for Anchor custom types -func NewIDLAccountCodec(idl IDL, builder commonencodings.Builder) (commontypes.RemoteCodec, error) { - return newIDLCoded(idl, builder, idl.Accounts, true) +func NewNamedModifierCodec(original commontypes.RemoteCodec, itemType string, modifier commoncodec.Modifier) (commontypes.RemoteCodec, error) { + mod, err := commoncodec.NewByItemTypeModifier(map[string]commoncodec.Modifier{itemType: modifier}) + if err != nil { + return nil, err + } + + modCodec, err := commoncodec.NewModifierCodec(original, mod, DecoderHooks...) + if err != nil { + return nil, err + } + + _, err = modCodec.CreateType(itemType, true) + + return modCodec, err } func NewIDLDefinedTypesCodec(idl IDL, builder commonencodings.Builder) (commontypes.RemoteCodec, error) { @@ -203,16 +258,14 @@ func createCodecType( includeDiscriminator bool, ) (string, commonencodings.TypeCodec, error) { name := def.Name - switch def.Type.Kind { case IdlTypeDefTyKindStruct: - return asStruct(*def.Type.Fields, refs, name, includeDiscriminator) + return asStruct(*def.Type.Fields, refs, name, includeDiscriminator, false) case IdlTypeDefTyKindEnum: variants := def.Type.Variants if !variants.IsAllUint8() { return name, nil, fmt.Errorf("%w: variants are not supported", commontypes.ErrInvalidConfig) } - return name, refs.builder.Uint8(), nil default: return name, nil, fmt.Errorf(unknownIDLFormat, commontypes.ErrInvalidConfig, def.Type.Kind) @@ -224,11 +277,13 @@ func asStruct( refs *codecRefs, name string, // name is the struct name and can be used in dependency checks includeDiscriminator bool, + isInstructionArgs bool, ) (string, commonencodings.TypeCodec, error) { desLen := 0 if includeDiscriminator { desLen = 1 } + named := make([]commonencodings.NamedTypeCodec, len(fields)+desLen) if includeDiscriminator { @@ -246,6 +301,10 @@ func asStruct( named[idx+desLen] = commonencodings.NamedTypeCodec{Name: fieldName, Codec: typedCodec} } + if len(named) == 1 && isInstructionArgs && !includeDiscriminator { + return name, named[0].Codec, nil + } + structCodec, err := commonencodings.NewStructCodec(named) if err != nil { return name, nil, err diff --git a/pkg/solana/codec/testutils/converters.go b/pkg/solana/codec/testutils/converters.go index ae79ca945..c5e351226 100644 --- a/pkg/solana/codec/testutils/converters.go +++ b/pkg/solana/codec/testutils/converters.go @@ -11,7 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-solana/pkg/solana/codec/testutils/test_item_type" ) -func EncodeRequestToTestStruct(request *interfacetests.EncodeRequest) test_item_type.TestStruct { +func EncodeRequestToTestItem(request *interfacetests.EncodeRequest) test_item_type.TestItem { byt := [32]byte{} for i, v := range request.TestStructs[0].OracleIDs { byt[i] = byte(v) @@ -24,7 +24,7 @@ func EncodeRequestToTestStruct(request *interfacetests.EncodeRequest) test_item_ accs[i] = solana.PublicKeyFromBytes(v) } - testStruct := test_item_type.TestStruct{ + testItem := test_item_type.TestItem{ Field: *request.TestStructs[0].Field, OracleId: uint8(request.TestStructs[0].OracleID), OracleIds: byt, @@ -50,7 +50,7 @@ func EncodeRequestToTestStruct(request *interfacetests.EncodeRequest) test_item_ }, }, } - return testStruct + return testItem } func bigIntToBinInt128(val *big.Int) bin.Int128 { @@ -90,17 +90,17 @@ func oracleIDsToBytes(oracleIDs [32]commontypes.OracleID) [32]byte { return convertedIDs } -func ToInternalType(testStruct interfacetests.TestStruct) test_item_type.TestStruct { - return test_item_type.TestStruct{ - Field: *testStruct.Field, - DifferentField: testStruct.DifferentField, - OracleId: byte(testStruct.OracleID), - OracleIds: oracleIDsToBytes(testStruct.OracleIDs), - AccountStruct: accountStructToInternalType(testStruct.AccountStruct), - Accounts: convertAccounts(testStruct.Accounts), - BigField: bigIntToBinInt128(testStruct.BigField), - NestedDynamicStruct: midDynamicToInternalType(testStruct.NestedDynamicStruct), - NestedStaticStruct: midStaticToInternalType(testStruct.NestedStaticStruct), +func ToInternalType(testItem interfacetests.TestStruct) test_item_type.TestItem { + return test_item_type.TestItem{ + Field: *testItem.Field, + DifferentField: testItem.DifferentField, + OracleId: byte(testItem.OracleID), + OracleIds: oracleIDsToBytes(testItem.OracleIDs), + AccountStruct: accountStructToInternalType(testItem.AccountStruct), + Accounts: convertAccounts(testItem.Accounts), + BigField: bigIntToBinInt128(testItem.BigField), + NestedDynamicStruct: midDynamicToInternalType(testItem.NestedDynamicStruct), + NestedStaticStruct: midStaticToInternalType(testItem.NestedStaticStruct), } } diff --git a/pkg/solana/codec/testutils/test_item_slice_type/TestItemSliceType.go b/pkg/solana/codec/testutils/test_item_slice_type/TestItemSliceType.go new file mode 100644 index 000000000..9c508173e --- /dev/null +++ b/pkg/solana/codec/testutils/test_item_slice_type/TestItemSliceType.go @@ -0,0 +1,110 @@ +// Code generated by https://github.com/gagliardetto/anchor-go. DO NOT EDIT. + +package test_item_slice_type + +import ( + "errors" + + ag_binary "github.com/gagliardetto/binary" + ag_solanago "github.com/gagliardetto/solana-go" + ag_format "github.com/gagliardetto/solana-go/text/format" + ag_treeout "github.com/gagliardetto/treeout" + + "github.com/smartcontractkit/chainlink-solana/pkg/solana/codec/testutils/test_item_type" +) + +// TestItemSliceType is the `TestItemSliceType` instruction. +type TestItemSliceType struct { + TestItemSliceType *[]test_item_type.TestItem + + ag_solanago.AccountMetaSlice `bin:"-"` +} + +// NewTestItemSliceTypeInstructionBuilder creates a new `TestItemSliceType` instruction builder. +func NewTestItemSliceTypeInstructionBuilder() *TestItemSliceType { + nd := &TestItemSliceType{ + AccountMetaSlice: make(ag_solanago.AccountMetaSlice, 0), + } + return nd +} + +// SetTestItemSliceType sets the "TestItemSliceType" parameter. +func (inst *TestItemSliceType) SetTestItemSliceType(TestItemSliceType []test_item_type.TestItem) *TestItemSliceType { + inst.TestItemSliceType = &TestItemSliceType + return inst +} + +func (inst TestItemSliceType) Build() *Instruction { + return &Instruction{BaseVariant: ag_binary.BaseVariant{ + Impl: inst, + TypeID: Instruction_TestItemSliceType, + }} +} + +// ValidateAndBuild validates the instruction parameters and accounts; +// if there is a validation error, it returns the error. +// Otherwise, it builds and returns the instruction. +func (inst TestItemSliceType) ValidateAndBuild() (*Instruction, error) { + if err := inst.Validate(); err != nil { + return nil, err + } + return inst.Build(), nil +} + +func (inst *TestItemSliceType) Validate() error { + // Check whether all (required) parameters are set: + { + if inst.TestItemSliceType == nil { + return errors.New("TestItemSliceType parameter is not set") + } + } + + // Check whether all (required) accounts are set: + { + } + return nil +} + +func (inst *TestItemSliceType) EncodeToTree(parent ag_treeout.Branches) { + parent.Child(ag_format.Program(ProgramName, ProgramID)). + // + ParentFunc(func(programBranch ag_treeout.Branches) { + programBranch.Child(ag_format.Instruction("TestItemSliceType")). + // + ParentFunc(func(instructionBranch ag_treeout.Branches) { + + // Parameters of the instruction: + instructionBranch.Child("Params[len=1]").ParentFunc(func(paramsBranch ag_treeout.Branches) { + paramsBranch.Child(ag_format.Param("TestItemSliceType", *inst.TestItemSliceType)) + }) + + // Accounts of the instruction: + instructionBranch.Child("Accounts[len=0]").ParentFunc(func(accountsBranch ag_treeout.Branches) {}) + }) + }) +} + +func (obj TestItemSliceType) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { + // Serialize `TestItemSliceType` param: + err = encoder.Encode(obj.TestItemSliceType) + if err != nil { + return err + } + return nil +} +func (obj *TestItemSliceType) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) { + // Deserialize `TestItemSliceType`: + err = decoder.Decode(&obj.TestItemSliceType) + if err != nil { + return err + } + return nil +} + +// NewTestItemSliceTypeInstruction declares a new TestItemSliceType instruction with the provided parameters and accounts. +func NewTestItemSliceTypeInstruction( + // Parameters: + TestItemSliceType []test_item_type.TestItem) *TestItemSliceType { + return NewTestItemSliceTypeInstructionBuilder(). + SetTestItemSliceType(TestItemSliceType) +} diff --git a/pkg/solana/codec/testutils/test_item_slice_type/instructions.go b/pkg/solana/codec/testutils/test_item_slice_type/instructions.go new file mode 100644 index 000000000..cd7603fe2 --- /dev/null +++ b/pkg/solana/codec/testutils/test_item_slice_type/instructions.go @@ -0,0 +1,118 @@ +// Code generated by https://github.com/gagliardetto/anchor-go. DO NOT EDIT. + +package test_item_slice_type + +import ( + "bytes" + "fmt" + + ag_spew "github.com/davecgh/go-spew/spew" + ag_binary "github.com/gagliardetto/binary" + ag_solanago "github.com/gagliardetto/solana-go" + ag_text "github.com/gagliardetto/solana-go/text" + ag_treeout "github.com/gagliardetto/treeout" +) + +var ProgramID ag_solanago.PublicKey + +func SetProgramID(pubkey ag_solanago.PublicKey) { + ProgramID = pubkey + ag_solanago.RegisterInstructionDecoder(ProgramID, registryDecodeInstruction) +} + +const ProgramName = "TestItemSliceType" + +func init() { + if !ProgramID.IsZero() { + ag_solanago.RegisterInstructionDecoder(ProgramID, registryDecodeInstruction) + } +} + +var ( + Instruction_TestItemSliceType = ag_binary.TypeID([8]byte{252, 0, 175, 183, 86, 235, 217, 80}) +) + +// InstructionIDToName returns the name of the instruction given its ID. +func InstructionIDToName(id ag_binary.TypeID) string { + switch id { + case Instruction_TestItemSliceType: + return "TestItemSliceType" + default: + return "" + } +} + +type Instruction struct { + ag_binary.BaseVariant +} + +func (inst *Instruction) EncodeToTree(parent ag_treeout.Branches) { + if enToTree, ok := inst.Impl.(ag_text.EncodableToTree); ok { + enToTree.EncodeToTree(parent) + } else { + parent.Child(ag_spew.Sdump(inst)) + } +} + +var InstructionImplDef = ag_binary.NewVariantDefinition( + ag_binary.AnchorTypeIDEncoding, + []ag_binary.VariantType{ + { + "test_item_slice_type", (*TestItemSliceType)(nil), + }, + }, +) + +func (inst *Instruction) ProgramID() ag_solanago.PublicKey { + return ProgramID +} + +func (inst *Instruction) Accounts() (out []*ag_solanago.AccountMeta) { + return inst.Impl.(ag_solanago.AccountsGettable).GetAccounts() +} + +func (inst *Instruction) Data() ([]byte, error) { + buf := new(bytes.Buffer) + if err := ag_binary.NewBorshEncoder(buf).Encode(inst); err != nil { + return nil, fmt.Errorf("unable to encode instruction: %w", err) + } + return buf.Bytes(), nil +} + +func (inst *Instruction) TextEncode(encoder *ag_text.Encoder, option *ag_text.Option) error { + return encoder.Encode(inst.Impl, option) +} + +func (inst *Instruction) UnmarshalWithDecoder(decoder *ag_binary.Decoder) error { + return inst.BaseVariant.UnmarshalBinaryVariant(decoder, InstructionImplDef) +} + +func (inst *Instruction) MarshalWithEncoder(encoder *ag_binary.Encoder) error { + err := encoder.WriteBytes(inst.TypeID.Bytes(), false) + if err != nil { + return fmt.Errorf("unable to write variant type: %w", err) + } + return encoder.Encode(inst.Impl) +} + +func registryDecodeInstruction(accounts []*ag_solanago.AccountMeta, data []byte) (interface{}, error) { + inst, err := DecodeInstruction(accounts, data) + if err != nil { + return nil, err + } + return inst, nil +} + +func DecodeInstruction(accounts []*ag_solanago.AccountMeta, data []byte) (*Instruction, error) { + inst := new(Instruction) + if err := ag_binary.NewBorshDecoder(data).Decode(inst); err != nil { + return nil, fmt.Errorf("unable to decode instruction: %w", err) + } + if v, ok := inst.Impl.(ag_solanago.AccountsSettable); ok { + err := v.SetAccounts(accounts) + if err != nil { + return nil, fmt.Errorf("unable to set accounts for instruction: %w", err) + } + } + return inst, nil +} diff --git a/pkg/solana/codec/testutils/test_item_slice_type/itemSliceTypeIDL.json b/pkg/solana/codec/testutils/test_item_slice_type/itemSliceTypeIDL.json index 8f4d42bd2..641ffe94e 100644 --- a/pkg/solana/codec/testutils/test_item_slice_type/itemSliceTypeIDL.json +++ b/pkg/solana/codec/testutils/test_item_slice_type/itemSliceTypeIDL.json @@ -1,104 +1,89 @@ - { - "version": "0.1.0", - "name": "test_item_slice_type", - "instructions": [ - { - "name": "ProcessTestItemSliceType", - "accounts": [ - { - "name": "TestItemSlice", - "isMut": true, - "isSigner": false - } - ], - "args": [] - } - ], - "accounts": [ - { - "name": "TestItemSlice", - "type": { - "kind": "struct", - "fields": [ - { - "name": "Items", - "type": { - "vec": { - "defined": "TestItem" - } - } +{ + "version": "0.1.0", + "name": "test_item_slice_type", + "instructions": [ + { + "name": "TestItemSliceType", + "accounts": [], + "args": [ + { + "name": "TestItemSliceType", + "type": { + "vec": { + "defined": "TestItem" } - ] + } } + ] + } + ], + "types": [ + { + "name": "TestItem", + "type": { + "kind": "struct", + "fields": [ + { "name": "Field", "type": "i32" }, + { "name": "DifferentField", "type": "string" }, + { "name": "OracleId", "type": "u8" }, + { "name": "OracleIds", "type": { "array": ["u8", 32] } }, + { "name": "AccountStruct", "type": { "defined": "AccountStruct" } }, + { "name": "Accounts", "type": { "vec": "publicKey" } }, + { "name": "BigField", "type": "i128" }, + { "name": "NestedDynamicStruct", "type": { "defined": "NestedDynamic" } }, + { "name": "NestedStaticStruct", "type": { "defined": "NestedStatic" } } + ] } - ], - "types": [ - { - "name": "TestItem", - "type": { - "kind": "struct", - "fields": [ - { "name": "Field", "type": "i32" }, - { "name": "DifferentField", "type": "string" }, - { "name": "OracleId", "type": "u8" }, - { "name": "OracleIds", "type": { "array": ["u8", 32] } }, - { "name": "AccountStruct", "type": { "defined": "AccountStruct" } }, - { "name": "Accounts", "type": { "vec": "publicKey" } }, - { "name": "BigField", "type": "i128" }, - { "name": "NestedDynamicStruct", "type": { "defined": "NestedDynamic" } }, - { "name": "NestedStaticStruct", "type": { "defined": "NestedStatic" } } - ] - } - }, - { - "name": "AccountStruct", - "type": { - "kind": "struct", - "fields": [ - { "name": "Account", "type": "publicKey" }, - { "name": "AccountStr", "type": "publicKey" } - ] - } - }, - { - "name": "InnerDynamic", - "type": { - "kind": "struct", - "fields": [ - { "name": "IntVal", "type": "i64" }, - { "name": "S", "type": "string" } - ] - } - }, - { - "name": "NestedDynamic", - "type": { - "kind": "struct", - "fields": [ - { "name": "FixedBytes", "type": { "array": ["u8", 2] } }, - { "name": "Inner", "type": { "defined": "InnerDynamic" } } - ] - } - }, - { - "name": "InnerStatic", - "type": { - "kind": "struct", - "fields": [ - { "name": "IntVal", "type": "i64" }, - { "name": "A", "type": "publicKey" } - ] - } - }, - { - "name": "NestedStatic", - "type": { - "kind": "struct", - "fields": [ - { "name": "FixedBytes", "type": { "array": ["u8", 2] } }, - { "name": "Inner", "type": { "defined": "InnerStatic" } } - ] - } + }, + { + "name": "AccountStruct", + "type": { + "kind": "struct", + "fields": [ + { "name": "Account", "type": "publicKey" }, + { "name": "AccountStr", "type": "publicKey" } + ] + } + }, + { + "name": "InnerDynamic", + "type": { + "kind": "struct", + "fields": [ + { "name": "IntVal", "type": "i64" }, + { "name": "S", "type": "string" } + ] + } + }, + { + "name": "NestedDynamic", + "type": { + "kind": "struct", + "fields": [ + { "name": "FixedBytes", "type": { "array": ["u8", 2] } }, + { "name": "Inner", "type": { "defined": "InnerDynamic" } } + ] + } + }, + { + "name": "InnerStatic", + "type": { + "kind": "struct", + "fields": [ + { "name": "IntVal", "type": "i64" }, + { "name": "A", "type": "publicKey" } + ] + } + }, + { + "name": "NestedStatic", + "type": { + "kind": "struct", + "fields": [ + { "name": "FixedBytes", "type": { "array": ["u8", 2] } }, + { "name": "Inner", "type": { "defined": "InnerStatic" } } + ] } - ] - } + } + ] +} diff --git a/pkg/solana/codec/testutils/test_item_slice_type/types.go b/pkg/solana/codec/testutils/test_item_slice_type/types.go deleted file mode 100644 index 16c0ce105..000000000 --- a/pkg/solana/codec/testutils/test_item_slice_type/types.go +++ /dev/null @@ -1,283 +0,0 @@ -// Code generated by https://github.com/gagliardetto/anchor-go. DO NOT EDIT. - -package test_item_slice_type - -import ( - ag_binary "github.com/gagliardetto/binary" - ag_solanago "github.com/gagliardetto/solana-go" -) - -type TestItem struct { - Field int32 - DifferentField string - OracleId uint8 - OracleIds [32]uint8 - AccountStruct AccountStruct - Accounts []ag_solanago.PublicKey - BigField ag_binary.Int128 - NestedDynamicStruct NestedDynamic - NestedStaticStruct NestedStatic -} - -func (obj TestItem) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { - // Serialize `Field` param: - err = encoder.Encode(obj.Field) - if err != nil { - return err - } - // Serialize `DifferentField` param: - err = encoder.Encode(obj.DifferentField) - if err != nil { - return err - } - // Serialize `OracleId` param: - err = encoder.Encode(obj.OracleId) - if err != nil { - return err - } - // Serialize `OracleIds` param: - err = encoder.Encode(obj.OracleIds) - if err != nil { - return err - } - // Serialize `AccountStruct` param: - err = encoder.Encode(obj.AccountStruct) - if err != nil { - return err - } - // Serialize `Accounts` param: - err = encoder.Encode(obj.Accounts) - if err != nil { - return err - } - // Serialize `BigField` param: - err = encoder.Encode(obj.BigField) - if err != nil { - return err - } - // Serialize `NestedDynamicStruct` param: - err = encoder.Encode(obj.NestedDynamicStruct) - if err != nil { - return err - } - // Serialize `NestedStaticStruct` param: - err = encoder.Encode(obj.NestedStaticStruct) - if err != nil { - return err - } - return nil -} - -func (obj *TestItem) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) { - // Deserialize `Field`: - err = decoder.Decode(&obj.Field) - if err != nil { - return err - } - // Deserialize `DifferentField`: - err = decoder.Decode(&obj.DifferentField) - if err != nil { - return err - } - // Deserialize `OracleId`: - err = decoder.Decode(&obj.OracleId) - if err != nil { - return err - } - // Deserialize `OracleIds`: - err = decoder.Decode(&obj.OracleIds) - if err != nil { - return err - } - // Deserialize `AccountStruct`: - err = decoder.Decode(&obj.AccountStruct) - if err != nil { - return err - } - // Deserialize `Accounts`: - err = decoder.Decode(&obj.Accounts) - if err != nil { - return err - } - // Deserialize `BigField`: - err = decoder.Decode(&obj.BigField) - if err != nil { - return err - } - // Deserialize `NestedDynamicStruct`: - err = decoder.Decode(&obj.NestedDynamicStruct) - if err != nil { - return err - } - // Deserialize `NestedStaticStruct`: - err = decoder.Decode(&obj.NestedStaticStruct) - if err != nil { - return err - } - return nil -} - -type AccountStruct struct { - Account ag_solanago.PublicKey - AccountStr ag_solanago.PublicKey -} - -func (obj AccountStruct) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { - // Serialize `Account` param: - err = encoder.Encode(obj.Account) - if err != nil { - return err - } - // Serialize `AccountStr` param: - err = encoder.Encode(obj.AccountStr) - if err != nil { - return err - } - return nil -} - -func (obj *AccountStruct) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) { - // Deserialize `Account`: - err = decoder.Decode(&obj.Account) - if err != nil { - return err - } - // Deserialize `AccountStr`: - err = decoder.Decode(&obj.AccountStr) - if err != nil { - return err - } - return nil -} - -type InnerDynamic struct { - IntVal int64 - S string -} - -func (obj InnerDynamic) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { - // Serialize `IntVal` param: - err = encoder.Encode(obj.IntVal) - if err != nil { - return err - } - // Serialize `S` param: - err = encoder.Encode(obj.S) - if err != nil { - return err - } - return nil -} - -func (obj *InnerDynamic) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) { - // Deserialize `IntVal`: - err = decoder.Decode(&obj.IntVal) - if err != nil { - return err - } - // Deserialize `S`: - err = decoder.Decode(&obj.S) - if err != nil { - return err - } - return nil -} - -type NestedDynamic struct { - FixedBytes [2]uint8 - Inner InnerDynamic -} - -func (obj NestedDynamic) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { - // Serialize `FixedBytes` param: - err = encoder.Encode(obj.FixedBytes) - if err != nil { - return err - } - // Serialize `Inner` param: - err = encoder.Encode(obj.Inner) - if err != nil { - return err - } - return nil -} - -func (obj *NestedDynamic) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) { - // Deserialize `FixedBytes`: - err = decoder.Decode(&obj.FixedBytes) - if err != nil { - return err - } - // Deserialize `Inner`: - err = decoder.Decode(&obj.Inner) - if err != nil { - return err - } - return nil -} - -type InnerStatic struct { - IntVal int64 - A ag_solanago.PublicKey -} - -func (obj InnerStatic) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { - // Serialize `IntVal` param: - err = encoder.Encode(obj.IntVal) - if err != nil { - return err - } - // Serialize `A` param: - err = encoder.Encode(obj.A) - if err != nil { - return err - } - return nil -} - -func (obj *InnerStatic) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) { - // Deserialize `IntVal`: - err = decoder.Decode(&obj.IntVal) - if err != nil { - return err - } - // Deserialize `A`: - err = decoder.Decode(&obj.A) - if err != nil { - return err - } - return nil -} - -type NestedStatic struct { - FixedBytes [2]uint8 - Inner InnerStatic -} - -func (obj NestedStatic) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { - // Serialize `FixedBytes` param: - err = encoder.Encode(obj.FixedBytes) - if err != nil { - return err - } - // Serialize `Inner` param: - err = encoder.Encode(obj.Inner) - if err != nil { - return err - } - return nil -} - -func (obj *NestedStatic) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) { - // Deserialize `FixedBytes`: - err = decoder.Decode(&obj.FixedBytes) - if err != nil { - return err - } - // Deserialize `Inner`: - err = decoder.Decode(&obj.Inner) - if err != nil { - return err - } - return nil -} diff --git a/pkg/solana/codec/testutils/test_item_type/accounts.go b/pkg/solana/codec/testutils/test_item_type/accounts.go index 728945e62..7917c74ce 100644 --- a/pkg/solana/codec/testutils/test_item_type/accounts.go +++ b/pkg/solana/codec/testutils/test_item_type/accounts.go @@ -9,7 +9,7 @@ import ( ag_solanago "github.com/gagliardetto/solana-go" ) -type TestStruct struct { +type TestItem struct { Field int32 OracleId uint8 OracleIds [32]uint8 @@ -21,11 +21,11 @@ type TestStruct struct { NestedStaticStruct NestedStatic } -var TestStructDiscriminator = [8]byte{243, 149, 82, 70, 154, 54, 107, 6} +var TestItemDiscriminator = [8]byte{148, 105, 105, 155, 26, 167, 212, 149} -func (obj TestStruct) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { +func (obj TestItem) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) { // Write account discriminator: - err = encoder.WriteBytes(TestStructDiscriminator[:], false) + err = encoder.WriteBytes(TestItemDiscriminator[:], false) if err != nil { return err } @@ -77,17 +77,17 @@ func (obj TestStruct) MarshalWithEncoder(encoder *ag_binary.Encoder) (err error) return nil } -func (obj *TestStruct) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) { +func (obj *TestItem) UnmarshalWithDecoder(decoder *ag_binary.Decoder) (err error) { // Read and check account discriminator: { discriminator, err := decoder.ReadTypeID() if err != nil { return err } - if !discriminator.Equal(TestStructDiscriminator[:]) { + if !discriminator.Equal(TestItemDiscriminator[:]) { return fmt.Errorf( "wrong discriminator: wanted %s, got %s", - "[243 149 82 70 154 54 107 6]", + "[148 105 105 155 26 167 212 149]", fmt.Sprint(discriminator[:])) } } diff --git a/pkg/solana/codec/testutils/test_item_type/itemIDL.json b/pkg/solana/codec/testutils/test_item_type/itemIDL.json index 529ae23a7..ee2a719cc 100644 --- a/pkg/solana/codec/testutils/test_item_type/itemIDL.json +++ b/pkg/solana/codec/testutils/test_item_type/itemIDL.json @@ -2,21 +2,10 @@ "version": "0.1.0", "name": "test_item_type", "instructions": [ - { - "name": "processTestItemType", - "accounts": [ - { - "name": "TestStruct", - "isMut": true, - "isSigner": false - } - ], - "args": [] - } ], "accounts": [ { - "name": "TestStruct", + "name": "TestItem", "type": { "kind": "struct", "fields": [ diff --git a/pkg/solana/codec/testutils/types.go b/pkg/solana/codec/testutils/types.go index 3bdce672d..eae4bd150 100644 --- a/pkg/solana/codec/testutils/types.go +++ b/pkg/solana/codec/testutils/types.go @@ -6,6 +6,8 @@ import ( "time" "github.com/gagliardetto/solana-go" + + "github.com/smartcontractkit/chainlink-solana/pkg/solana/codec" ) var ( @@ -116,9 +118,20 @@ var itemWithConfigExtraJSONIDL string //go:embed nilTypeIDL.json var nilTypeJSONIDL string -var CodecDefs = map[string]string{ - //TestItemType: itemTypeJSONIDL, - TestItemSliceType: itemSliceTypeJSONIDL, +type CodecDef struct { + IDL string + ItemType codec.ChainConfigType +} + +var CodecDefs = map[string]CodecDef{ + TestItemType: { + IDL: itemTypeJSONIDL, + ItemType: codec.ChainConfigTypeAccountDef, + }, + TestItemSliceType: { + IDL: itemSliceTypeJSONIDL, + ItemType: codec.ChainConfigTypeInstructionDef, + }, //TestItemArray1Type: itemArray1TypeJSONIDL, //TestItemArray2Type: itemArray2TypeJSONIDL, //sizeItemType: sizeItemTypeJSONIDL, diff --git a/pkg/solana/codec/types.go b/pkg/solana/codec/types.go index 16af437af..74c7f952f 100644 --- a/pkg/solana/codec/types.go +++ b/pkg/solana/codec/types.go @@ -2,6 +2,14 @@ package codec import commoncodec "github.com/smartcontractkit/chainlink-common/pkg/codec" +type ChainConfigType string + +const ( + ChainConfigTypeAccountDef ChainConfigType = "account" + ChainConfigTypeInstructionDef ChainConfigType = "instruction" + ChainConfigTypeEventDef ChainConfigType = "event" +) + type Config struct { // Configs key is the type's name for the codec Configs map[string]ChainConfig `json:"configs" toml:"configs"` @@ -9,7 +17,6 @@ type Config struct { type ChainConfig struct { IDL string `json:"IDL" toml:"IDL"` - AccountDef *IdlTypeDef `json:"account" toml:"IDL"` - EventDef *IdlEvent `json:"event" toml:"IDL"` + Type ChainConfigType `json:"type" toml:"type"` ModifierConfigs commoncodec.ModifiersConfig `json:"modifierConfigs,omitempty" toml:"modifierConfigs,omitempty"` }