* fix parseTopics() and add tests * remove printf * add ParseTopicsIntoMap() tests * fix FixedBytesTy * fix int and fixed bytes * golint topics_test.go
This commit is contained in:
parent
49cf000df7
commit
6ae9dc15cc
@ -178,6 +178,13 @@ func parseTopics(out interface{}, fields abi.Arguments, topics []common.Hash) er
|
|||||||
|
|
||||||
case reflectBigInt:
|
case reflectBigInt:
|
||||||
num := new(big.Int).SetBytes(topics[0][:])
|
num := new(big.Int).SetBytes(topics[0][:])
|
||||||
|
if arg.Type.T == abi.IntTy {
|
||||||
|
if num.Cmp(abi.MaxInt256) > 0 {
|
||||||
|
num.Add(abi.MaxUint256, big.NewInt(0).Neg(num))
|
||||||
|
num.Add(num, big.NewInt(1))
|
||||||
|
num.Neg(num)
|
||||||
|
}
|
||||||
|
}
|
||||||
field.Set(reflect.ValueOf(num))
|
field.Set(reflect.ValueOf(num))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -212,8 +219,7 @@ func parseTopicsIntoMap(out map[string]interface{}, fields abi.Arguments, topics
|
|||||||
case abi.BoolTy:
|
case abi.BoolTy:
|
||||||
out[arg.Name] = topics[0][common.HashLength-1] == 1
|
out[arg.Name] = topics[0][common.HashLength-1] == 1
|
||||||
case abi.IntTy, abi.UintTy:
|
case abi.IntTy, abi.UintTy:
|
||||||
num := new(big.Int).SetBytes(topics[0][:])
|
out[arg.Name] = abi.ReadInteger(arg.Type.T, arg.Type.Kind, topics[0].Bytes())
|
||||||
out[arg.Name] = num
|
|
||||||
case abi.AddressTy:
|
case abi.AddressTy:
|
||||||
var addr common.Address
|
var addr common.Address
|
||||||
copy(addr[:], topics[0][common.HashLength-common.AddressLength:])
|
copy(addr[:], topics[0][common.HashLength-common.AddressLength:])
|
||||||
@ -221,7 +227,11 @@ func parseTopicsIntoMap(out map[string]interface{}, fields abi.Arguments, topics
|
|||||||
case abi.HashTy:
|
case abi.HashTy:
|
||||||
out[arg.Name] = topics[0]
|
out[arg.Name] = topics[0]
|
||||||
case abi.FixedBytesTy:
|
case abi.FixedBytesTy:
|
||||||
out[arg.Name] = topics[0][:]
|
array, err := abi.ReadFixedBytes(arg.Type, topics[0].Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
out[arg.Name] = array
|
||||||
case abi.StringTy, abi.BytesTy, abi.SliceTy, abi.ArrayTy:
|
case abi.StringTy, abi.BytesTy, abi.SliceTy, abi.ArrayTy:
|
||||||
// Array types (including strings and bytes) have their keccak256 hashes stored in the topic- not a hash
|
// Array types (including strings and bytes) have their keccak256 hashes stored in the topic- not a hash
|
||||||
// whose bytes can be decoded to the actual value- so the best we can do is retrieve that hash
|
// whose bytes can be decoded to the actual value- so the best we can do is retrieve that hash
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package bind
|
package bind
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -55,27 +56,44 @@ func TestMakeTopics(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseTopics(t *testing.T) {
|
type args struct {
|
||||||
type bytesStruct struct {
|
createObj func() interface{}
|
||||||
StaticBytes [5]byte
|
resultObj func() interface{}
|
||||||
}
|
resultMap func() map[string]interface{}
|
||||||
|
fields abi.Arguments
|
||||||
|
topics []common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
type bytesStruct struct {
|
||||||
|
StaticBytes [5]byte
|
||||||
|
}
|
||||||
|
type int8Struct struct {
|
||||||
|
Int8Value int8
|
||||||
|
}
|
||||||
|
type int256Struct struct {
|
||||||
|
Int256Value *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
type topicTest struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
wantErr bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupTopicsTests() []topicTest {
|
||||||
bytesType, _ := abi.NewType("bytes5", "", nil)
|
bytesType, _ := abi.NewType("bytes5", "", nil)
|
||||||
type args struct {
|
int8Type, _ := abi.NewType("int8", "", nil)
|
||||||
createObj func() interface{}
|
int256Type, _ := abi.NewType("int256", "", nil)
|
||||||
resultObj func() interface{}
|
|
||||||
fields abi.Arguments
|
tests := []topicTest{
|
||||||
topics []common.Hash
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
wantErr bool
|
|
||||||
}{
|
|
||||||
{
|
{
|
||||||
name: "support fixed byte types, right padded to 32 bytes",
|
name: "support fixed byte types, right padded to 32 bytes",
|
||||||
args: args{
|
args: args{
|
||||||
createObj: func() interface{} { return &bytesStruct{} },
|
createObj: func() interface{} { return &bytesStruct{} },
|
||||||
resultObj: func() interface{} { return &bytesStruct{StaticBytes: [5]byte{1, 2, 3, 4, 5}} },
|
resultObj: func() interface{} { return &bytesStruct{StaticBytes: [5]byte{1, 2, 3, 4, 5}} },
|
||||||
|
resultMap: func() map[string]interface{} {
|
||||||
|
return map[string]interface{}{"staticBytes": [5]byte{1, 2, 3, 4, 5}}
|
||||||
|
},
|
||||||
fields: abi.Arguments{abi.Argument{
|
fields: abi.Arguments{abi.Argument{
|
||||||
Name: "staticBytes",
|
Name: "staticBytes",
|
||||||
Type: bytesType,
|
Type: bytesType,
|
||||||
@ -87,7 +105,54 @@ func TestParseTopics(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "int8 with negative value",
|
||||||
|
args: args{
|
||||||
|
createObj: func() interface{} { return &int8Struct{} },
|
||||||
|
resultObj: func() interface{} { return &int8Struct{Int8Value: -1} },
|
||||||
|
resultMap: func() map[string]interface{} {
|
||||||
|
return map[string]interface{}{"int8Value": int8(-1)}
|
||||||
|
},
|
||||||
|
fields: abi.Arguments{abi.Argument{
|
||||||
|
Name: "int8Value",
|
||||||
|
Type: int8Type,
|
||||||
|
Indexed: true,
|
||||||
|
}},
|
||||||
|
topics: []common.Hash{
|
||||||
|
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "int256 with negative value",
|
||||||
|
args: args{
|
||||||
|
createObj: func() interface{} { return &int256Struct{} },
|
||||||
|
resultObj: func() interface{} { return &int256Struct{Int256Value: big.NewInt(-1)} },
|
||||||
|
resultMap: func() map[string]interface{} {
|
||||||
|
return map[string]interface{}{"int256Value": big.NewInt(-1)}
|
||||||
|
},
|
||||||
|
fields: abi.Arguments{abi.Argument{
|
||||||
|
Name: "int256Value",
|
||||||
|
Type: int256Type,
|
||||||
|
Indexed: true,
|
||||||
|
}},
|
||||||
|
topics: []common.Hash{
|
||||||
|
{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return tests
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseTopics(t *testing.T) {
|
||||||
|
tests := setupTopicsTests()
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
createObj := tt.args.createObj()
|
createObj := tt.args.createObj()
|
||||||
@ -101,3 +166,20 @@ func TestParseTopics(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParseTopicsIntoMap(t *testing.T) {
|
||||||
|
tests := setupTopicsTests()
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
outMap := make(map[string]interface{})
|
||||||
|
if err := parseTopicsIntoMap(outMap, tt.args.fields, tt.args.topics); (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("parseTopicsIntoMap() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
}
|
||||||
|
resultMap := tt.args.resultMap()
|
||||||
|
if !reflect.DeepEqual(outMap, resultMap) {
|
||||||
|
t.Errorf("parseTopicsIntoMap() = %v, want %v", outMap, resultMap)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -26,16 +26,18 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
maxUint256 = big.NewInt(0).Add(
|
// MaxUint256 is the maximum value that can be represented by a uint256
|
||||||
|
MaxUint256 = big.NewInt(0).Add(
|
||||||
big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil),
|
big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil),
|
||||||
big.NewInt(-1))
|
big.NewInt(-1))
|
||||||
maxInt256 = big.NewInt(0).Add(
|
// MaxInt256 is the maximum value that can be represented by a int256
|
||||||
|
MaxInt256 = big.NewInt(0).Add(
|
||||||
big.NewInt(0).Exp(big.NewInt(2), big.NewInt(255), nil),
|
big.NewInt(0).Exp(big.NewInt(2), big.NewInt(255), nil),
|
||||||
big.NewInt(-1))
|
big.NewInt(-1))
|
||||||
)
|
)
|
||||||
|
|
||||||
// reads the integer based on its kind
|
// ReadInteger reads the integer based on its kind and returns the appropriate value
|
||||||
func readInteger(typ byte, kind reflect.Kind, b []byte) interface{} {
|
func ReadInteger(typ byte, kind reflect.Kind, b []byte) interface{} {
|
||||||
switch kind {
|
switch kind {
|
||||||
case reflect.Uint8:
|
case reflect.Uint8:
|
||||||
return b[len(b)-1]
|
return b[len(b)-1]
|
||||||
@ -62,8 +64,8 @@ func readInteger(typ byte, kind reflect.Kind, b []byte) interface{} {
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
if ret.Cmp(maxInt256) > 0 {
|
if ret.Cmp(MaxInt256) > 0 {
|
||||||
ret.Add(maxUint256, big.NewInt(0).Neg(ret))
|
ret.Add(MaxUint256, big.NewInt(0).Neg(ret))
|
||||||
ret.Add(ret, big.NewInt(1))
|
ret.Add(ret, big.NewInt(1))
|
||||||
ret.Neg(ret)
|
ret.Neg(ret)
|
||||||
}
|
}
|
||||||
@ -102,8 +104,8 @@ func readFunctionType(t Type, word []byte) (funcTy [24]byte, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// through reflection, creates a fixed array to be read from
|
// ReadFixedBytes uses reflection to create a fixed array to be read from
|
||||||
func readFixedBytes(t Type, word []byte) (interface{}, error) {
|
func ReadFixedBytes(t Type, word []byte) (interface{}, error) {
|
||||||
if t.T != FixedBytesTy {
|
if t.T != FixedBytesTy {
|
||||||
return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array")
|
return nil, fmt.Errorf("abi: invalid type in call to make fixed byte array")
|
||||||
}
|
}
|
||||||
@ -230,7 +232,7 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
|
|||||||
case StringTy: // variable arrays are written at the end of the return bytes
|
case StringTy: // variable arrays are written at the end of the return bytes
|
||||||
return string(output[begin : begin+length]), nil
|
return string(output[begin : begin+length]), nil
|
||||||
case IntTy, UintTy:
|
case IntTy, UintTy:
|
||||||
return readInteger(t.T, t.Kind, returnOutput), nil
|
return ReadInteger(t.T, t.Kind, returnOutput), nil
|
||||||
case BoolTy:
|
case BoolTy:
|
||||||
return readBool(returnOutput)
|
return readBool(returnOutput)
|
||||||
case AddressTy:
|
case AddressTy:
|
||||||
@ -240,7 +242,7 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
|
|||||||
case BytesTy:
|
case BytesTy:
|
||||||
return output[begin : begin+length], nil
|
return output[begin : begin+length], nil
|
||||||
case FixedBytesTy:
|
case FixedBytesTy:
|
||||||
return readFixedBytes(t, returnOutput)
|
return ReadFixedBytes(t, returnOutput)
|
||||||
case FunctionTy:
|
case FunctionTy:
|
||||||
return readFunctionType(t, returnOutput)
|
return readFunctionType(t, returnOutput)
|
||||||
default:
|
default:
|
||||||
|
Loading…
Reference in New Issue
Block a user