Skip to content

Commit

Permalink
temp
Browse files Browse the repository at this point in the history
  • Loading branch information
ilija42 committed Dec 11, 2024
1 parent 8a04b89 commit 5b636b9
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 25 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ require (
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0
golang.org/x/sync v0.8.0
golang.org/x/text v0.18.0
)

require (
Expand Down Expand Up @@ -124,6 +123,7 @@ require (
golang.org/x/net v0.29.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/term v0.24.0 // indirect
golang.org/x/text v0.18.0 // indirect
golang.org/x/time v0.3.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
Expand Down
146 changes: 133 additions & 13 deletions pkg/solana/codec/codec_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package codec_test

import (
"bytes"
_ "embed"
"encoding/json"
"fmt"
"math/big"
"reflect"
"slices"
"strings"
"testing"

bin "github.com/gagliardetto/binary"
Expand All @@ -16,6 +21,7 @@ import (
clcommontypes "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-solana/pkg/solana/codec"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/codec/generated/test_item_type"
"github.com/smartcontractkit/chainlink-solana/pkg/solana/codec/testutils"
)

Expand All @@ -34,14 +40,8 @@ type codecInterfaceTester struct {
func (it *codecInterfaceTester) Setup(_ *testing.T) {}

func (it *codecInterfaceTester) GetAccountBytes(i int) []byte {
account := [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// fuzz tests can make -ve numbers
if i < 0 {
i = -i
}
account[i%20] += byte(i)
account[(i+3)%20] += byte(i + 3)
return account[:]
pk, _ := solana.NewRandomPrivateKey()
return pk.PublicKey().Bytes()
}

func (it *codecInterfaceTester) GetAccountString(i int) string {
Expand All @@ -57,11 +57,56 @@ func (it *codecInterfaceTester) EncodeFields(t *testing.T, request *EncodeReques
}

func encodeFieldsOnItem(t *testing.T, request *EncodeRequest) ocr2types.Report {
borshBytes, err := bin.MarshalBorsh(argsFromTestStruct(request.TestStructs[0]))
if err != nil {
t.Errorf(err.Error())
buf := new(bytes.Buffer)
if err := encodeRequestToTestStruct(request).MarshalWithEncoder(bin.NewBorshEncoder(buf)); err != nil {
require.NoError(t, err)
}
return borshBytes
return buf.Bytes()
}

func encodeRequestToTestStruct(request *EncodeRequest) test_item_type.TestStruct {
byt := [32]byte{}
for i, v := range request.TestStructs[0].OracleIDs {
byt[i] = byte(v)
}

k, _ := solana.PublicKeyFromBase58(request.TestStructs[0].AccountStruct.AccountStr)

accs := make([]solana.PublicKey, len(request.TestStructs[0].Accounts))
for i, v := range request.TestStructs[0].Accounts {
accs[i] = solana.PublicKeyFromBytes(v)
}

testStruct := test_item_type.TestStruct{
Field: *request.TestStructs[0].Field,
OracleId: uint8(request.TestStructs[0].OracleID),
OracleIds: byt,
AccountStruct: test_item_type.AccountStruct{
Account: solana.PublicKeyFromBytes(request.TestStructs[0].AccountStruct.Account),
AccountStr: k,
},
Accounts: accs,
DifferentField: request.TestStructs[0].DifferentField,
BigField: bin.Int128{
Lo: request.TestStructs[0].BigField.Uint64(),
Hi: new(big.Int).Rsh(request.TestStructs[0].BigField, 64).Uint64(),
},
NestedDynamicStruct: test_item_type.NestedDynamic{
FixedBytes: request.TestStructs[0].NestedDynamicStruct.FixedBytes,
Inner: test_item_type.InnerDynamic{
IntVal: int64(request.TestStructs[0].NestedDynamicStruct.Inner.I),
S: request.TestStructs[0].NestedDynamicStruct.Inner.S,
},
},
NestedStaticStruct: test_item_type.NestedStatic{
FixedBytes: request.TestStructs[0].NestedStaticStruct.FixedBytes,
Inner: test_item_type.InnerStatic{
IntVal: int64(request.TestStructs[0].NestedStaticStruct.Inner.I),
A: solana.PublicKeyFromBytes(request.TestStructs[0].NestedStaticStruct.Inner.A),
},
},
}
return testStruct
}

func encodeFieldsOnSliceOrArray(t *testing.T, request *EncodeRequest) []byte {
Expand All @@ -79,7 +124,7 @@ func encodeFieldsOnSliceOrArray(t *testing.T, request *EncodeRequest) []byte {
args[0] = tmp
}

borshBytes, err := bin.MarshalBorsh(argsFromTestStruct(request.TestStructs[0]))
borshBytes, err := bin.MarshalBorsh(cpy)
if err != nil {
t.Errorf(err.Error())
}
Expand All @@ -101,6 +146,7 @@ func (it *codecInterfaceTester) GetCodec(t *testing.T) clcommontypes.Codec {

if k != sizeItemType && k != NilType {
entry.ModifierConfigs = commoncodec.ModifiersConfig{
&commoncodec.DropModifierConfig{Fields: []string{"DiscriminatorTestStruct"}},
&commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedDynamicStruct.Inner.IntVal": "I"}},
&commoncodec.RenameModifierConfig{Fields: map[string]string{"NestedStaticStruct.Inner.IntVal": "I"}},
}
Expand All @@ -111,6 +157,8 @@ func (it *codecInterfaceTester) GetCodec(t *testing.T) clcommontypes.Codec {
Fields: []string{"AccountStruct.AccountStr"},
Modifier: codec.SolanaAddressModifier{},
}
//cpy {Field:0 OracleID:1 OracleIDs:[2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] AccountStruct:{Account:[230 246 124 140 101 222 233 141 21 37 83 232 157 45 101 15 165 209 220 244 224 64 240 236 28 111 178 18 51 245 55 105] AccountStr:5rujdkG6iAzdtzf1JPjGF82tjeSwqM1QV4KCtrqaSNrX} Accounts:[[202 126 200 254 65 52 23 23 136 249 239 73 81 38 216 127 205 238 235 253 174 61 44 136 35 46 156 74 233 63 28 226] [202 195 18 0 144 219 77 163 99 129 127 77 185 142 8 121 12 253 71 49 75 123 189 213 118 119 129 87 26 74 71 177]] DifferentField:field0 BigField:{} NestedDynamicStruct:{FixedBytes:[0 1] Inner:{I:0 S:field0}} NestedStaticStruct:{FixedBytes:[0 1] Inner:{I:0 A:[3 134 218 122 6 116 161 93 12 75 126 131 168 213 211 126 159 168 145 110 168 226 230 212 110 87 25 251 255 78 130 55]}}}
//to encode: {DiscriminatorTestStruct:nil Field:0 DifferentField:field0 OracleId:1 OracleIds:[2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] AccountStruct:{Account:[230 246 124 140 101 222 233 141 21 37 83 232 157 45 101 15 165 209 220 244 224 64 240 236 28 111 178 18 51 245 55 105] AccountStr:[72 55 213 199 102 214 15 160 144 134 159 170 4 211 4 50 206 167 85 101 28 99 67 254 12 247 191 123 214 119 110 228]} Accounts:[[202 126 200 254 65 52 23 23 136 249 239 73 81 38 216 127 205 238 235 253 174 61 44 136 35 46 156 74 233 63 28 226] [202 195 18 0 144 219 77 163 99 129 127 77 185 142 8 121 12 253 71 49 75 123 189 213 118 119 129 87 26 74 71 177]] BigField:{} NestedDynamicStruct:{FixedBytes:[0 1] Inner:{IntVal:0 S:field0}} NestedStaticStruct:{FixedBytes:[0 1] Inner:{IntVal:0 A:[3 134 218 122 6 116 161 93 12 75 126 131 168 213 211 126 159 168 145 110 168 226 230 212 110 87 25 251 255 78 130 55]}}}

entry.ModifierConfigs = append(entry.ModifierConfigs, addressByteModifier)
}
Expand Down Expand Up @@ -261,3 +309,75 @@ var codecDefs = map[string]string{
//TestItemWithConfigExtra: itemWithConfigExtraJSONIDL,
//NilType: nilTypeJSONIDL,
}

// LogFields recursively logs fields of a struct or pointer to a struct with tight formatting.
func LogFields(v interface{}) {
logFields(reflect.ValueOf(v), "")
}

func logFields(v reflect.Value, indent string) {
str := valueToString(v)
fmt.Printf("%s%s\n", indent, str)
}

func valueToString(v reflect.Value) string {
// Resolve pointers to their underlying value
for v.Kind() == reflect.Ptr {
if v.IsNil() {
return "nil"
}
v = v.Elem()
}

switch v.Kind() {
case reflect.Struct:
t := v.Type()
var fields []string
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
fieldType := t.Field(i)

// Skip unexported fields
if !field.CanInterface() {
continue
}

fieldName := fieldType.Name
fieldValue := valueToString(field)
fields = append(fields, fmt.Sprintf("%s:%s", fieldName, fieldValue))
}
return fmt.Sprintf("{%s}", strings.Join(fields, " "))
case reflect.Map:
if v.Len() == 0 {
return "{}"
}
var pairs []string
for _, key := range v.MapKeys() {
value := v.MapIndex(key)
keyStr := valueToString(key)
valueStr := valueToString(value)
pairs = append(pairs, fmt.Sprintf("%s:%s", keyStr, valueStr))
}
return fmt.Sprintf("map[%s]", strings.Join(pairs, " "))
case reflect.Slice, reflect.Array:
if v.Len() == 0 {
return "[]"
}
var elems []string
for i := 0; i < v.Len(); i++ {
elem := v.Index(i)
elemStr := valueToString(elem)
elems = append(elems, elemStr)
}
return fmt.Sprintf("[%s]", strings.Join(elems, " "))
case reflect.Invalid:
return "nil"
default:
// Check if the value can be interfaced
if v.CanInterface() {
return fmt.Sprintf("%v", v.Interface())
} else {
return "<unexported>"
}
}
}
14 changes: 7 additions & 7 deletions pkg/solana/codec/discriminator.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ const discriminatorLength = 8

func NewDiscriminator(name string) encodings.TypeCodec {
sum := sha256.Sum256([]byte("account:" + name))
return &discriminator{hashPrefix: sum[:discriminatorLength]}
return &Discriminator{hashPrefix: sum[:discriminatorLength]}
}

type discriminator struct {
type Discriminator struct {
hashPrefix []byte
}

func (d discriminator) Encode(value any, into []byte) ([]byte, error) {
func (d Discriminator) Encode(value any, into []byte) ([]byte, error) {
if value == nil {
return append(into, d.hashPrefix...), nil
}
Expand All @@ -44,7 +44,7 @@ func (d discriminator) Encode(value any, into []byte) ([]byte, error) {
return append(into, *raw...), nil
}

func (d discriminator) Decode(encoded []byte) (any, []byte, error) {
func (d Discriminator) Decode(encoded []byte) (any, []byte, error) {
raw, remaining, err := encodings.SafeDecode(encoded, discriminatorLength, func(raw []byte) []byte { return raw })
if err != nil {
return nil, nil, err
Expand All @@ -57,15 +57,15 @@ func (d discriminator) Decode(encoded []byte) (any, []byte, error) {
return &raw, remaining, nil
}

func (d discriminator) GetType() reflect.Type {
func (d Discriminator) GetType() reflect.Type {
// Pointer type so that nil can inject values and so that the NamedCodec won't wrap with no-nil pointer.
return reflect.TypeOf(&[]byte{})
}

func (d discriminator) Size(_ int) (int, error) {
func (d Discriminator) Size(_ int) (int, error) {
return discriminatorLength, nil
}

func (d discriminator) FixedSize() (int, error) {
func (d Discriminator) FixedSize() (int, error) {
return discriminatorLength, nil
}
75 changes: 75 additions & 0 deletions pkg/solana/codec/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"reflect"
"strings"

"github.com/smartcontractkit/chainlink-common/pkg/codec"
commontypes "github.com/smartcontractkit/chainlink-common/pkg/types"
Expand Down Expand Up @@ -39,6 +40,8 @@ func (e *encoder) Encode(_ context.Context, item any, itemType string) (res []by
}
}

fmt.Printf("about to log these: ")
LogFields(item)
return info.Encode(item, nil)
}

Expand All @@ -49,3 +52,75 @@ func (e *encoder) GetMaxEncodingSize(_ context.Context, n int, itemType string)
}
return entry.GetCodecType().Size(n)
}

// LogFields recursively logs fields of a struct or pointer to a struct with tight formatting.
func LogFields(v interface{}) {
logFields(reflect.ValueOf(v), "")
}

func logFields(v reflect.Value, indent string) {
str := valueToString(v)
fmt.Printf("%s%s\n", indent, str)
}

func valueToString(v reflect.Value) string {
// Resolve pointers to their underlying value
for v.Kind() == reflect.Ptr {
if v.IsNil() {
return "nil"
}
v = v.Elem()
}

switch v.Kind() {
case reflect.Struct:
t := v.Type()
var fields []string
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
fieldType := t.Field(i)

// Skip unexported fields
if !field.CanInterface() {
continue
}

fieldName := fieldType.Name
fieldValue := valueToString(field)
fields = append(fields, fmt.Sprintf("%s:%s", fieldName, fieldValue))
}
return fmt.Sprintf("{%s}", strings.Join(fields, " "))
case reflect.Map:
if v.Len() == 0 {
return "{}"
}
var pairs []string
for _, key := range v.MapKeys() {
value := v.MapIndex(key)
keyStr := valueToString(key)
valueStr := valueToString(value)
pairs = append(pairs, fmt.Sprintf("%s:%s", keyStr, valueStr))
}
return fmt.Sprintf("map[%s]", strings.Join(pairs, " "))
case reflect.Slice, reflect.Array:
if v.Len() == 0 {
return "[]"
}
var elems []string
for i := 0; i < v.Len(); i++ {
elem := v.Index(i)
elemStr := valueToString(elem)
elems = append(elems, elemStr)
}
return fmt.Sprintf("[%s]", strings.Join(elems, " "))
case reflect.Invalid:
return "nil"
default:
// Check if the value can be interfaced
if v.CanInterface() {
return fmt.Sprintf("%v", v.Interface())
} else {
return "<unexported>"
}
}
}
3 changes: 1 addition & 2 deletions pkg/solana/codec/solana.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (s solanaCodec) CreateType(itemType string, forEncoding bool) (any, error)

// we don't need double pointers, and they can also mess up reflection variable creation and mapstruct decode
if def.GetType().Kind() == reflect.Pointer {
return reflect.New(def.GetCodecType().GetType()).Elem().Interface(), nil
return reflect.New(def.GetCodecType().GetType().Elem()).Interface(), nil
}

return reflect.New(def.GetType()).Interface(), nil
Expand Down Expand Up @@ -224,7 +224,6 @@ func asStruct(
return name, nil, err
}

fmt.Println("no caser ", fieldName)
named[idx+desLen] = commonencodings.NamedTypeCodec{Name: fieldName, Codec: typedCodec}
}

Expand Down
1 change: 1 addition & 0 deletions pkg/solana/codec/testutils/itemArray1TypeIDL.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
{ "name": "OracleIds", "type": { "array": ["u8", 32] } },
{ "name": "AccountStruct", "type": { "defined": "AccountStruct" } },
{ "name": "Accounts", "type": { "vec": "publicKey" } },
{ "name": "DifferentField", "type": "string" },
{ "name": "BigField", "type": "i128" },
{ "name": "NestedDynamicStruct", "type": { "defined": "NestedDynamic" } },
{ "name": "NestedStaticStruct", "type": { "defined": "NestedStatic" } }
Expand Down
Loading

0 comments on commit 5b636b9

Please sign in to comment.