From eae14b49deaa48badd1a076ee3acf299af9dff7a Mon Sep 17 00:00:00 2001 From: edwardmack Date: Wed, 5 Feb 2020 17:19:36 -0500 Subject: [PATCH 1/4] checks if type has Encode function --- codec/encode.go | 17 ++++++++++++ codec/encode_test.go | 63 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/codec/encode.go b/codec/encode.go index fc7f9930d4..d89b4d7b6a 100644 --- a/codec/encode.go +++ b/codec/encode.go @@ -32,6 +32,23 @@ type Encoder struct { Writer io.Writer } +// 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 + } else { + return Encode(in) + } +} + // Encode to byte array func Encode(in interface{}) ([]byte, error) { buffer := bytes.Buffer{} diff --git a/codec/encode_test.go b/codec/encode_test.go index f83e0b2753..4aaae22889 100644 --- a/codec/encode_test.go +++ b/codec/encode_test.go @@ -18,6 +18,7 @@ package codec import ( "bytes" + "fmt" "math/big" "reflect" "strings" @@ -210,3 +211,65 @@ func TestEncodeAndDecodeStringArrayInStruct(t *testing.T) { require.Nil(t, err) require.Equal(t, test, result, "Decoding failed") } + +// test type for encoding +type TypeReal struct { + A string +} + +// Encode func for TypeReal that uses actual Scale Encode +func (tr TypeReal) Encode() ([]byte, error) { + return Encode(tr) +} + +// test to confirm EncodeCustom is return Scale Encoded result +func TestEncodeCustomTypeReal(t *testing.T) { + test := &TypeReal{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 TypeFake struct { + A string +} + +// Encode func for TypeFake that return fake byte array [1, 2, 3] +func (tr TypeFake) Encode() ([]byte, error) { + return []byte{1, 2, 3}, nil +} + +// test to confirm EncodeCustom is using type's Encode function +func TestEncodeCustomTypeFake(t *testing.T) { + test := &TypeFake{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 TypeError struct { + A string +} + +// Encode func for TypeError that return an error +func (tr TypeError) Encode() ([]byte, error) { + return nil, fmt.Errorf("error encoding") +} + +// test to confirm EncodeCustom is handling errors +func TestEncodeCustomTypeError(t *testing.T) { + test := &TypeError{A: "hello"} + + _, err := EncodeCustom(test) + require.EqualError(t, err, "error encoding") +} From 75a131ac58fa0c9b0a3e70813a2b026e8cd273f7 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Thu, 6 Feb 2020 16:21:09 -0500 Subject: [PATCH 2/4] Added DecodeCustom to handle calling Decode func DecodeCustom handles calling Decode function for types that have Decode defined, otherwise uses regular Scale Decoding functions Signed-off-by: edwardmack --- codec/decode_ptr.go | 18 +++++++++ codec/decode_ptr_test.go | 79 ++++++++++++++++++++++++++++++++++++++++ codec/encode_test.go | 50 +++++++++++++++++-------- 3 files changed, 131 insertions(+), 16 deletions(-) diff --git a/codec/decode_ptr.go b/codec/decode_ptr.go index a43a7e79af..c47ea50379 100644 --- a/codec/decode_ptr.go +++ b/codec/decode_ptr.go @@ -23,6 +23,24 @@ import ( "reflect" ) +// 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 + } else { + 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) diff --git a/codec/decode_ptr_test.go b/codec/decode_ptr_test.go index 37d2675941..93ef2e1a4e 100644 --- a/codec/decode_ptr_test.go +++ b/codec/decode_ptr_test.go @@ -17,6 +17,10 @@ package codec import ( "bytes" + "errors" + "github.com/ChainSafe/gossamer/consensus/babe/types" + "github.com/ChainSafe/gossamer/crypto/sr25519" + "github.com/stretchr/testify/require" "math/big" "reflect" "testing" @@ -206,3 +210,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") +} \ No newline at end of file diff --git a/codec/encode_test.go b/codec/encode_test.go index 4aaae22889..0943b569a8 100644 --- a/codec/encode_test.go +++ b/codec/encode_test.go @@ -18,7 +18,7 @@ package codec import ( "bytes" - "fmt" + "errors" "math/big" "reflect" "strings" @@ -213,18 +213,36 @@ func TestEncodeAndDecodeStringArrayInStruct(t *testing.T) { } // test type for encoding -type TypeReal struct { +type MockTypeA struct { A string } // Encode func for TypeReal that uses actual Scale Encode -func (tr TypeReal) Encode() ([]byte, error) { +func (tr *MockTypeA) Encode() ([]byte, error) { return Encode(tr) } // test to confirm EncodeCustom is return Scale Encoded result -func TestEncodeCustomTypeReal(t *testing.T) { - test := &TypeReal{A: "hello"} +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) @@ -236,18 +254,18 @@ func TestEncodeCustomTypeReal(t *testing.T) { } // test types for encoding -type TypeFake struct { +type MockTypeC struct { A string } -// Encode func for TypeFake that return fake byte array [1, 2, 3] -func (tr TypeFake) Encode() ([]byte, error) { +// 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 TestEncodeCustomTypeFake(t *testing.T) { - test := &TypeFake{A: "hello"} +func TestEncodeCustomMockTypeC(t *testing.T) { + test := &MockTypeC{A: "hello"} expected := []byte{1, 2, 3} encCust, err := EncodeCustom(test) @@ -257,18 +275,18 @@ func TestEncodeCustomTypeFake(t *testing.T) { } // test types for encoding -type TypeError struct { +type MockTypeD struct { A string } -// Encode func for TypeError that return an error -func (tr TypeError) Encode() ([]byte, error) { - return nil, fmt.Errorf("error encoding") +// 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 TestEncodeCustomTypeError(t *testing.T) { - test := &TypeError{A: "hello"} +func TestEncodeCustomMockTypeD(t *testing.T) { + test := &MockTypeD{A: "hello"} _, err := EncodeCustom(test) require.EqualError(t, err, "error encoding") From 3c86ca2e7700aeed63269ef315087b9031ad02f6 Mon Sep 17 00:00:00 2001 From: edwardmack Date: Thu, 6 Feb 2020 16:27:17 -0500 Subject: [PATCH 3/4] go fmt'ed Signed-off-by: edwardmack --- codec/decode_ptr.go | 2 +- codec/decode_ptr_test.go | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/codec/decode_ptr.go b/codec/decode_ptr.go index c47ea50379..16f127fe45 100644 --- a/codec/decode_ptr.go +++ b/codec/decode_ptr.go @@ -24,7 +24,7 @@ import ( ) // check if interface has method Decode, if so use that, otherwise use regular scale decoding -func DecodeCustom(in []byte, t interface{}) (error) { +func DecodeCustom(in []byte, t interface{}) error { someType := reflect.TypeOf(t) _, ok := someType.MethodByName("Decode") if ok { diff --git a/codec/decode_ptr_test.go b/codec/decode_ptr_test.go index 93ef2e1a4e..1d6ccc91c0 100644 --- a/codec/decode_ptr_test.go +++ b/codec/decode_ptr_test.go @@ -18,12 +18,13 @@ package codec import ( "bytes" "errors" - "github.com/ChainSafe/gossamer/consensus/babe/types" - "github.com/ChainSafe/gossamer/crypto/sr25519" - "github.com/stretchr/testify/require" "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) { @@ -220,7 +221,7 @@ func TestDecodeCustom_DecodeBabeHeader(t *testing.T) { 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} + 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) @@ -236,7 +237,7 @@ func (tr *MockTypeA) Decode(in []byte) error { // 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} + encoded := []byte{20, 104, 101, 108, 108, 111} mockType := new(MockTypeA) err := DecodeCustom(encoded, mockType) @@ -247,7 +248,7 @@ func TestDecodeCustom_DecodeMockTypeA(t *testing.T) { // 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} + encoded := []byte{20, 104, 101, 108, 108, 111} mockType := new(MockTypeB) err := DecodeCustom(encoded, mockType) @@ -264,7 +265,7 @@ func (tr *MockTypeC) Decode(in []byte) error { // 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} + encoded := []byte{20, 104, 101, 108, 108, 111} mockType := new(MockTypeC) err := DecodeCustom(encoded, mockType) @@ -279,9 +280,9 @@ func (tr *MockTypeD) Decode(in []byte) error { // 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} + encoded := []byte{20, 104, 101, 108, 108, 111} mockType := new(MockTypeD) err := DecodeCustom(encoded, mockType) require.EqualError(t, err, "error decoding") -} \ No newline at end of file +} From b6a06deb73a9ea806f9d7851ecedef8ab2603c1e Mon Sep 17 00:00:00 2001 From: edwardmack Date: Fri, 7 Feb 2020 09:57:28 -0500 Subject: [PATCH 4/4] fixed lint rants Signed-off-by: edwardmack --- codec/decode_ptr.go | 5 ++--- codec/encode.go | 5 ++--- go.mod | 6 +----- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/codec/decode_ptr.go b/codec/decode_ptr.go index 16f127fe45..32a66afdbf 100644 --- a/codec/decode_ptr.go +++ b/codec/decode_ptr.go @@ -23,7 +23,7 @@ import ( "reflect" ) -// check if interface has method Decode, if so use that, otherwise use regular scale decoding +// 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") @@ -36,9 +36,8 @@ func DecodeCustom(in []byte, t interface{}) error { return err.(error) } return nil - } else { - return DecodePtr(in, t) } + return DecodePtr(in, t) } // DecodePtr is the high level function wrapping the specific type decoding functions diff --git a/codec/encode.go b/codec/encode.go index d89b4d7b6a..7bc861f591 100644 --- a/codec/encode.go +++ b/codec/encode.go @@ -32,7 +32,7 @@ type Encoder struct { Writer io.Writer } -// check if interface has method Encode, if so use that, otherwise use regular scale encoding +// 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") @@ -44,9 +44,8 @@ func EncodeCustom(in interface{}) ([]byte, error) { return val.([]byte), err.(error) } return val.([]byte), nil - } else { - return Encode(in) } + return Encode(in) } // Encode to byte array diff --git a/go.mod b/go.mod index c44521f440..cc77af72b1 100644 --- a/go.mod +++ b/go.mod @@ -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 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 @@ -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