Parse stack params (#119)

* small fixes

* gofmt

* bytearray parsing

* tests

* removed unnecessary files

* added more types for bytearray

* iter

* made TryParseArray parameter variadic

* fixes after review

* fix after review

* misprints

* updated array reverse

* imports/fmt

* naming
This commit is contained in:
Anastasia Prasolova 2019-02-05 15:22:10 +03:00 committed by fabwa
parent 7c1147f04f
commit a058598ecc
5 changed files with 210 additions and 4 deletions

1
go.mod
View file

@ -19,4 +19,5 @@ require (
golang.org/x/tools v0.0.0-20180318012157-96caea41033d
gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect
gopkg.in/h2non/gock.v1 v1.0.12 // indirect
)

View file

@ -1,6 +1,7 @@
package rpc
import (
"encoding/binary"
"encoding/hex"
"encoding/json"
"strconv"
@ -97,7 +98,7 @@ func (t *StackParamType) UnmarshalJSON(data []byte) (err error) {
return
}
// StackParam respresent a stack parameter.
// StackParam represent a stack parameter.
type StackParam struct {
Type StackParamType `json:"type"`
Value interface{} `json:"value"`
@ -172,3 +173,89 @@ func (p *StackParam) UnmarshalJSON(data []byte) (err error) {
}
return
}
type StackParams []StackParam
func (p StackParams) TryParseArray(vals ...interface{}) error {
var (
err error
i int
par StackParam
)
if len(p) != len(vals) {
return errors.New("receiver array doesn't fit the StackParams length")
}
for i, par = range p {
if err = par.TryParse(vals[i]); err != nil {
return err
}
}
return nil
}
func (p StackParam) TryParse(dest interface{}) error {
var (
err error
ok bool
data []byte
)
switch p.Type {
case ByteArray:
if data, ok = p.Value.([]byte); !ok {
return errors.Errorf("failed to cast %s to []byte", p.Value)
}
switch dest := dest.(type) {
case *util.Uint160:
if *dest, err = util.Uint160DecodeBytes(data); err != nil {
return err
}
return nil
case *[]byte:
*dest = data
return nil
case *util.Uint256:
if *dest, err = util.Uint256DecodeBytes(data); err != nil {
return err
}
return nil
case *int64, *int32, *int16, *int8, *int, *uint64, *uint32, *uint16, *uint8, *uint:
i := bytesToUint64(data)
switch dest := dest.(type) {
case *int64:
*dest = int64(i)
case *int32:
*dest = int32(i)
case *int16:
*dest = int16(i)
case *int8:
*dest = int8(i)
case *int:
*dest = int(i)
case *uint64:
*dest = i
case *uint32:
*dest = uint32(i)
case *uint16:
*dest = uint16(i)
case *uint8:
*dest = uint8(i)
case *uint:
*dest = uint(i)
}
case *string:
*dest = string(data)
return nil
default:
return errors.Errorf("cannot cast stackparam of type %s to type %s", p.Type, dest)
}
default:
return errors.New("cannot define stackparam type")
}
return nil
}
func bytesToUint64(b []byte) uint64 {
data := make([]byte, 8)
copy(data[8-len(b):], util.ArrayReverse(b))
return binary.BigEndian.Uint64(data)
}

View file

@ -1,6 +1,7 @@
package rpc
import (
"encoding/hex"
"encoding/json"
"reflect"
"testing"
@ -103,3 +104,120 @@ func TestStackParam_UnmarshalJSON(t *testing.T) {
}
}
}
const (
hash160 = "0bcd2978634d961c24f5aea0802297ff128724d6"
hash256 = "7fe610b7c8259ae949accacb091a1bc53219c51a1cb8752fbc6457674c13ec0b"
testString = "myteststring"
)
func TestStackParam_TryParse(t *testing.T) {
// ByteArray to util.Uint160 conversion
data, err := hex.DecodeString(hash160)
var (
outputUint160, expectedUint160 util.Uint160
input = StackParam{
Type: ByteArray,
Value: data,
}
)
expectedUint160, err = util.Uint160DecodeString(hash160)
if err = input.TryParse(&outputUint160); err != nil {
t.Errorf("failed to parse stackparam to Uint160: %v", err)
}
if !reflect.DeepEqual(outputUint160, expectedUint160) {
t.Errorf("got (%v), expected (%v)", outputUint160, expectedUint160)
}
// ByteArray to util.Uint256 conversion
data, err = hex.DecodeString(hash256)
var (
outputUint256, expectedUint256 util.Uint256
uint256input = StackParam{
Type: ByteArray,
Value: data,
}
)
expectedUint256, err = util.Uint256DecodeString(hash256)
if err = uint256input.TryParse(&outputUint256); err != nil {
t.Errorf("failed to parse stackparam to []byte: %v", err)
}
if !reflect.DeepEqual(outputUint256, expectedUint256) {
t.Errorf("got (%v), expected (%v)", outputUint256, expectedUint256)
}
// ByteArray to []byte conversion
var (
outputBytes []byte
expectedBytes = expectedUint160.Bytes()
)
if err = input.TryParse(&outputBytes); err != nil {
t.Errorf("failed to parse stackparam to []byte: %v", err)
}
if !reflect.DeepEqual(outputBytes, expectedBytes) {
t.Errorf("got (%v), expected (%v)", outputBytes, expectedBytes)
}
// ByteArray to int64 conversion
data, err = hex.DecodeString("637829cd0b")
var (
outputInt, expectedInt int64
intinput = StackParam{
Type: ByteArray,
Value: data,
}
)
expectedInt = 50686687331
if err = intinput.TryParse(&outputInt); err != nil {
t.Errorf("failed to parse stackparam to []byte: %v", err)
}
if !reflect.DeepEqual(outputInt, expectedInt) {
t.Errorf("got (%v), expected (%v)", outputInt, expectedInt)
}
// ByteArray to string conversion
data = []byte(testString)
var (
outputStr, expectedStr string
strinput = StackParam{
Type: ByteArray,
Value: data,
}
)
expectedStr = testString
if err = strinput.TryParse(&outputStr); err != nil {
t.Errorf("failed to parse stackparam to []byte: %v", err)
}
if !reflect.DeepEqual(outputStr, expectedStr) {
t.Errorf("got (%v), expected (%v)", outputStr, expectedStr)
}
// StackParams to []util.Uint160
data, err = hex.DecodeString(hash160)
expUint160, err := util.Uint160DecodeString(hash160)
var (
params = StackParams{
StackParam{
Type: ByteArray,
Value: data,
},
StackParam{
Type: ByteArray,
Value: data,
},
}
expectedArray = []util.Uint160{
expUint160,
expUint160,
}
out1, out2 = &util.Uint160{}, &util.Uint160{}
)
if err = params.TryParseArray(out1, out2); err != nil {
t.Errorf("failed to parse stackparam to []byte: %v", err)
}
outArray := []util.Uint160{*out1, *out2}
if !reflect.DeepEqual(outArray, expectedArray) {
t.Errorf("got (%v), expected (%v)", outArray, expectedArray)
}
}

View file

@ -7,7 +7,7 @@ func ArrayReverse(b []byte) []byte {
return b
}
dest := make([]byte, len(b))
for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
for i, j := 0, len(b)-1; i <= j; i, j = i+1, j-1 {
dest[i], dest[j] = b[j], b[i]
}
return dest

View file

@ -6,9 +6,9 @@ import (
)
func TestArrayReverse(t *testing.T) {
arr := []byte{0x01, 0x02, 0x03, 0x04}
arr := []byte{0x01, 0x02, 0x03, 0x04, 0x05}
have := ArrayReverse(arr)
want := []byte{0x04, 0x03, 0x02, 0x01}
want := []byte{0x05, 0x04, 0x03, 0x02, 0x01}
if bytes.Compare(have, want) != 0 {
t.Fatalf("expected %v got %v", want, have)
}