Skip to content

Commit

Permalink
progress
Browse files Browse the repository at this point in the history
  • Loading branch information
ilija42 committed Dec 12, 2024
1 parent 28a8b69 commit 47ae4ae
Show file tree
Hide file tree
Showing 12 changed files with 499 additions and 501 deletions.
50 changes: 25 additions & 25 deletions pkg/solana/codec/codec_entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
42 changes: 21 additions & 21 deletions pkg/solana/codec/codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand Down Expand Up @@ -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)
}
Expand All @@ -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{},
Expand All @@ -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},
}
Expand Down
127 changes: 93 additions & 34 deletions pkg/solana/codec/solana.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
}
Expand All @@ -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) {
Expand Down Expand Up @@ -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)
Expand All @@ -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 {
Expand All @@ -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
Expand Down
28 changes: 14 additions & 14 deletions pkg/solana/codec/testutils/converters.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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,
Expand All @@ -50,7 +50,7 @@ func EncodeRequestToTestStruct(request *interfacetests.EncodeRequest) test_item_
},
},
}
return testStruct
return testItem
}

func bigIntToBinInt128(val *big.Int) bin.Int128 {
Expand Down Expand Up @@ -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),
}
}

Expand Down
Loading

0 comments on commit 47ae4ae

Please sign in to comment.