Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions codec/decode_ptr.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,23 @@ import (
"reflect"
)

// DecodeCustom check if interface has method Decode, if so use that, otherwise use regular scale decoding
func DecodeCustom(in []byte, t interface{}) error {
someType := reflect.TypeOf(t)
_, ok := someType.MethodByName("Decode")
if ok {
meth := reflect.ValueOf(t).MethodByName("Decode")
inVal := []reflect.Value{reflect.ValueOf(in)}
res := meth.Call(inVal)
err := res[0].Interface()
if err != nil {
return err.(error)
}
return nil
}
return DecodePtr(in, t)
}

// DecodePtr is the high level function wrapping the specific type decoding functions
// The results of decode are written to t interface by reference (instead of returning
// value as Decode does)
Expand Down
80 changes: 80 additions & 0 deletions codec/decode_ptr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ package codec

import (
"bytes"
"errors"
"math/big"
"reflect"
"testing"

"github.com/ChainSafe/gossamer/consensus/babe/types"
"github.com/ChainSafe/gossamer/crypto/sr25519"
"github.com/stretchr/testify/require"
)

func TestDecodePtrFixedWidthInts(t *testing.T) {
Expand Down Expand Up @@ -206,3 +211,78 @@ func TestDecodePtrArrays(t *testing.T) {
}
}
}

// test decoding with DecodeCustom on BabeHeader type
func TestDecodeCustom_DecodeBabeHeader(t *testing.T) {
// arbitrary test data
expected := &types.BabeHeader{
VrfOutput: [sr25519.VrfOutputLength]byte{0, 91, 50, 25, 214, 94, 119, 36, 71, 216, 33, 152, 85, 184, 34, 120, 61, 161, 164, 223, 76, 53, 40, 246, 76, 38, 235, 204, 43, 31, 179, 28},
VrfProof: [sr25519.VrfProofLength]byte{120, 23, 235, 159, 115, 122, 207, 206, 123, 232, 75, 243, 115, 255, 131, 181, 219, 241, 200, 206, 21, 22, 238, 16, 68, 49, 86, 99, 76, 139, 39, 0, 102, 106, 181, 136, 97, 141, 187, 1, 234, 183, 241, 28, 27, 229, 133, 8, 32, 246, 245, 206, 199, 142, 134, 124, 226, 217, 95, 30, 176, 246, 5, 3},
BlockProducerIndex: 17,
SlotNumber: 420,
}
encoded := []byte{0, 91, 50, 25, 214, 94, 119, 36, 71, 216, 33, 152, 85, 184, 34, 120, 61, 161, 164, 223, 76, 53, 40, 246, 76, 38, 235, 204, 43, 31, 179, 28, 120, 23, 235, 159, 115, 122, 207, 206, 123, 232, 75, 243, 115, 255, 131, 181, 219, 241, 200, 206, 21, 22, 238, 16, 68, 49, 86, 99, 76, 139, 39, 0, 102, 106, 181, 136, 97, 141, 187, 1, 234, 183, 241, 28, 27, 229, 133, 8, 32, 246, 245, 206, 199, 142, 134, 124, 226, 217, 95, 30, 176, 246, 5, 3, 17, 0, 0, 0, 0, 0, 0, 0, 164, 1, 0, 0, 0, 0, 0, 0}
decodedBabeHeader := new(types.BabeHeader)

err := DecodeCustom(encoded, decodedBabeHeader)
require.Nil(t, err)
require.Equal(t, expected, decodedBabeHeader)
}

// add Decode func to MockTypeA
func (tr *MockTypeA) Decode(in []byte) error {
return DecodePtr(in, tr)
}

// test decoding for MockTypeA (which has Decode func)
func TestDecodeCustom_DecodeMockTypeA(t *testing.T) {
expected := &MockTypeA{A: "hello"}
encoded := []byte{20, 104, 101, 108, 108, 111}
mockType := new(MockTypeA)

err := DecodeCustom(encoded, mockType)
require.Nil(t, err)
require.Equal(t, expected, mockType)
}

// test decoding for MockTypeB (which does not have Decode func)
func TestDecodeCustom_DecodeMockTypeB(t *testing.T) {
expected := &MockTypeB{A: "hello"}
encoded := []byte{20, 104, 101, 108, 108, 111}
mockType := new(MockTypeB)

err := DecodeCustom(encoded, mockType)
require.Nil(t, err)
require.Equal(t, expected, mockType)
}

// add Decode func to MockTypeC which will return fake data (so we'll know when it was called)
func (tr *MockTypeC) Decode(in []byte) error {
tr.A = "goodbye"
return nil
}

// test decoding for MockTypeC (which has Decode func that returns fake data (A: "goodbye"))
func TestDecodeCustom_DecodeMockTypeC(t *testing.T) {
expected := &MockTypeC{A: "goodbye"}
encoded := []byte{20, 104, 101, 108, 108, 111}
mockType := new(MockTypeC)

err := DecodeCustom(encoded, mockType)
require.Nil(t, err)
require.Equal(t, expected, mockType)
}

// add Decode func to MockTypeD which will return an error
func (tr *MockTypeD) Decode(in []byte) error {
return errors.New("error decoding")
}

// test decoding for MockTypeD (which has Decode func that returns error)
func TestDecodeCustom_DecodeMockTypeD(t *testing.T) {
encoded := []byte{20, 104, 101, 108, 108, 111}
mockType := new(MockTypeD)

err := DecodeCustom(encoded, mockType)
require.EqualError(t, err, "error decoding")
}
16 changes: 16 additions & 0 deletions codec/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ type Encoder struct {
Writer io.Writer
}

// EncodeCustom check if interface has method Encode, if so use that, otherwise use regular scale encoding
func EncodeCustom(in interface{}) ([]byte, error) {
someType := reflect.TypeOf(in)
_, ok := someType.MethodByName("Encode")
if ok {
res := reflect.ValueOf(in).MethodByName("Encode").Call([]reflect.Value{})
val := res[0].Interface()
err := res[1].Interface()
if err != nil {
return val.([]byte), err.(error)
}
return val.([]byte), nil
}
return Encode(in)
}

// Encode to byte array
func Encode(in interface{}) ([]byte, error) {
buffer := bytes.Buffer{}
Expand Down
81 changes: 81 additions & 0 deletions codec/encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package codec

import (
"bytes"
"errors"
"math/big"
"reflect"
"strings"
Expand Down Expand Up @@ -210,3 +211,83 @@ func TestEncodeAndDecodeStringArrayInStruct(t *testing.T) {
require.Nil(t, err)
require.Equal(t, test, result, "Decoding failed")
}

// test type for encoding
type MockTypeA struct {
A string
}

// Encode func for TypeReal that uses actual Scale Encode
func (tr *MockTypeA) Encode() ([]byte, error) {
return Encode(tr)
}

// test to confirm EncodeCustom is return Scale Encoded result
func TestEncodeCustomMockTypeA(t *testing.T) {
test := &MockTypeA{A: "hello"}

encCust, err := EncodeCustom(test)
require.Nil(t, err)

encScale, err := Encode(test)
require.Nil(t, err)

require.Equal(t, encScale, encCust)
}

// test type for encoding, this type does not have Encode func
type MockTypeB struct {
A string
}

// test to confirm EncodeCustom is return Scale Encoded result
func TestEncodeCustomMockTypeB(t *testing.T) {
test := &MockTypeB{A: "hello"}

encCust, err := EncodeCustom(test)
require.Nil(t, err)

encScale, err := Encode(test)
require.Nil(t, err)

require.Equal(t, encScale, encCust)
}

// test types for encoding
type MockTypeC struct {
A string
}

// Encode func for MockTypeC that return fake byte array [1, 2, 3]
func (tr *MockTypeC) Encode() ([]byte, error) {
return []byte{1, 2, 3}, nil
}

// test to confirm EncodeCustom is using type's Encode function
func TestEncodeCustomMockTypeC(t *testing.T) {
test := &MockTypeC{A: "hello"}
expected := []byte{1, 2, 3}

encCust, err := EncodeCustom(test)
require.Nil(t, err)

require.Equal(t, expected, encCust)
}

// test types for encoding
type MockTypeD struct {
A string
}

// Encode func for MockTypeD that return an error
func (tr *MockTypeD) Encode() ([]byte, error) {
return nil, errors.New("error encoding")
}

// test to confirm EncodeCustom is handling errors
func TestEncodeCustomMockTypeD(t *testing.T) {
test := &MockTypeD{A: "hello"}

_, err := EncodeCustom(test)
require.EqualError(t, err, "error encoding")
}
6 changes: 1 addition & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ require (
github.com/disiqueira/gotree v1.0.0
github.com/ethereum/go-ethereum v1.9.6
github.com/filecoin-project/go-leb128 v0.0.0-20190212224330-8d79a5489543
github.com/golang/protobuf v1.3.2 // indirect
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have raised https://github.com/ChainSafe/gossamer/wiki/GoMOD#pr-597 to track the gomod changes for this PR. Lets try to keep it updated for the next changes.

github.com/golang/snappy v0.0.1
github.com/golangci/golangci-lint v1.23.1 // indirect
github.com/google/go-cmp v0.3.1 // indirect
github.com/gtank/merlin v0.1.1 // indirect
github.com/ipfs/go-datastore v0.3.1
Expand All @@ -24,16 +24,12 @@ require (
github.com/multiformats/go-multiaddr v0.2.0
github.com/naoina/go-stringutil v0.1.0 // indirect
github.com/naoina/toml v0.1.1
github.com/onsi/ginkgo v1.10.1 // indirect
github.com/onsi/gomega v1.7.0 // indirect
github.com/opentracing/opentracing-go v1.1.0 // indirect
github.com/stretchr/testify v1.4.0
github.com/urfave/cli v1.20.0
github.com/wasmerio/go-ext-wasm v0.0.0-20191206132826-225d01fcd22c
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876
golang.org/x/net v0.0.0-20190916140828-c8589233b77d // indirect
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
gopkg.in/yaml.v2 v2.2.7 // indirect
)

go 1.13