Commit d33e674d authored by Litian's avatar Litian

evm abi 解析逻辑初步完成

parent 9cc23096
...@@ -44,7 +44,7 @@ func JSON(reader io.Reader) (ABI, error) { ...@@ -44,7 +44,7 @@ func JSON(reader io.Reader) (ABI, error) {
return abi, nil return abi, nil
} }
// Pack the given method name to conform the ABI. Method call's data // Pack the given method Name to conform the ABI. Method call's data
// will consist of method_id, args0, arg1, ... argN. Method id consists // will consist of method_id, args0, arg1, ... argN. Method id consists
// of 4 bytes and arguments are all 32 bytes. // of 4 bytes and arguments are all 32 bytes.
// Method ids are created from the first 4 bytes of the hash of the // Method ids are created from the first 4 bytes of the hash of the
......
This diff is collapsed.
package abi package abi
import ( import (
"encoding/json"
"fmt" "fmt"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common" "github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/golang-collections/collections/stack" "github.com/golang-collections/collections/stack"
"math/big"
"reflect" "reflect"
"strconv" "strconv"
"strings"
) )
// Pack 使用ABI方式调用时,将调用方式转换为EVM底层处理的十六进制编码 // Pack 使用ABI方式调用时,将调用方式转换为EVM底层处理的十六进制编码
// abiData 完整的ABI定义 // abiData 完整的ABI定义
// param 调用方法及参数 // param 调用方法及参数
func Pack(param, abiData string) ([]byte, error) { // 调用方式: foo(param1,param2)
return nil, nil func Pack(param, abiData string) (methodName string, packData []byte, err error) {
// 首先解析参数字符串,分析出方法名以及个参数取值
methodName, params, err := procFuncCall(param)
if err != nil {
return methodName, packData, err
}
// 解析ABI数据结构,获取本次调用的方法对象
abi, err := JSON(strings.NewReader(abiData))
if err != nil {
return methodName, packData, err
}
var method Method
var ok bool
if method, ok = abi.Methods[methodName]; !ok {
err = fmt.Errorf("function %v not exists", methodName)
return methodName, packData, err
}
// 获取方法参数对象,遍历解析各参数,获得参数的Go取值
paramVals := []interface{}{}
if len(params) != 0 {
// 首先检查参数个数和ABI中定义的是否一致
if method.Inputs.LengthNonIndexed() != len(params) {
err = fmt.Errorf("function Params count error: %v", param)
return methodName, packData, err
}
for i, v := range method.Inputs.NonIndexed() {
paramVal, err := str2GoValue(v.Type, params[i])
if err != nil {
return methodName, packData, err
}
paramVals = append(paramVals, paramVal)
}
}
// 使用Abi对象将方法和参数进行打包
packData, err = abi.Pack(methodName, paramVals...)
return methodName, packData, err
} }
// Unpack 将调用返回结果按照ABI的格式序列化为json // Unpack 将调用返回结果按照ABI的格式序列化为json
// data 合约方法返回值 // data 合约方法返回值
// abiData 完整的ABI定义 // abiData 完整的ABI定义
func Unpack(data []byte, abiData string) (string, error) { func Unpack(data []byte, methodName, abiData string) (output string, err error) {
return "", nil
// 解析ABI数据结构,获取本次调用的方法对象
abi, err := JSON(strings.NewReader(abiData))
if err != nil {
return output, err
}
var method Method
var ok bool
if method, ok = abi.Methods[methodName]; !ok {
return output, fmt.Errorf("function %v not exists", methodName)
}
values, err := method.Outputs.UnpackValues(data)
if err != nil {
return output, err
}
outputs := []*Param{}
for i, v := range values {
arg := method.Outputs[i]
pval := &Param{Name: arg.Name, Type: arg.Type.String(), Value: v}
outputs = append(outputs, pval)
}
jsondata, err := json.Marshal(outputs)
if err != nil {
return output, err
}
return string(jsondata), err
}
type Param struct {
Name string `json:"name"`
Type string `json:"type"`
Value interface{} `json:"value"`
}
func convertUint(val uint64, kind reflect.Kind) interface{} {
switch kind {
case reflect.Uint:
return uint(val)
case reflect.Uint8:
return uint8(val)
case reflect.Uint16:
return uint16(val)
case reflect.Uint32:
return uint32(val)
case reflect.Uint64:
return uint64(val)
}
return val
}
func convertInt(val int64, kind reflect.Kind) interface{} {
switch kind {
case reflect.Int:
return int(val)
case reflect.Int8:
return int8(val)
case reflect.Int16:
return int16(val)
case reflect.Int32:
return int32(val)
case reflect.Int64:
return int64(val)
}
return val
} }
// 从字符串格式的输入参数取值(单个),获取Go类型的 // 从字符串格式的输入参数取值(单个),获取Go类型的
func goValue(typ Type, val string) (res interface{}, err error) { func str2GoValue(typ Type, val string) (res interface{}, err error) {
switch typ.T { switch typ.T {
case IntTy: case IntTy:
bitSize := 0 if typ.Size < 256 {
pos := uint(typ.Kind - reflect.Int) x, err := strconv.ParseInt(val, 10, typ.Size)
if pos > 0 { if err != nil {
bitSize = (2 << pos) * 2 return res, err
} }
x, err := strconv.ParseInt(val, 10, bitSize) return convertInt(x, typ.Kind), nil
if err != nil { } else {
return res, err b := new(big.Int)
b.SetString(val, 10)
return b, err
} }
return x, nil
case UintTy: case UintTy:
bitSize := 0 if typ.Size < 256 {
pos := uint(typ.Kind - reflect.Uint) x, err := strconv.ParseUint(val, 10, typ.Size)
if pos > 0 { if err != nil {
bitSize = (2 << pos) * 2 return res, err
} }
x, err := strconv.ParseUint(val, 10, bitSize) return convertUint(x, typ.Kind), nil
if err != nil { } else {
return res, err b := new(big.Int)
b.SetString(val, 10)
return b, err
} }
return x, nil
case BoolTy: case BoolTy:
x, err := strconv.ParseBool(val) x, err := strconv.ParseBool(val)
if err != nil { if err != nil {
...@@ -55,34 +168,34 @@ func goValue(typ Type, val string) (res interface{}, err error) { ...@@ -55,34 +168,34 @@ func goValue(typ Type, val string) (res interface{}, err error) {
return x, nil return x, nil
case StringTy: case StringTy:
return val, nil return val, nil
//case SliceTy: case SliceTy:
// var data []interface{} subs, err := procArrayItem(val)
// subs, err := getSubArrayStr(val) if err != nil {
// if err != nil { return res, err
// return res, err }
// } rval := reflect.MakeSlice(typ.Type, len(subs), len(subs))
// for idx, sub := range subs { for idx, sub := range subs {
// subVal, er := goValue(*typ.Elem, sub) subVal, er := str2GoValue(*typ.Elem, sub)
// if er != nil { if er != nil {
// return res, er return res, er
// } }
// data[idx] = subVal rval.Index(idx).Set(reflect.ValueOf(subVal))
// } }
// return data, nil return rval.Interface(), nil
//case ArrayTy: case ArrayTy:
// var data [typ.Size]interface{} rval := reflect.New(typ.Type).Elem()
// subs, err := getSubArrayStr(val) subs, err := procArrayItem(val)
// if err != nil { if err != nil {
// return res, err return res, err
// } }
// for idx, sub := range subs { for idx, sub := range subs {
// subVal, er := goValue(*typ.Elem, sub) subVal, er := str2GoValue(*typ.Elem, sub)
// if er != nil { if er != nil {
// return res, er return res, er
// } }
// data[idx] = subVal rval.Index(idx).Set(reflect.ValueOf(subVal))
// } }
// return data, nil return rval.Interface(), nil
case AddressTy: case AddressTy:
addr := common.StringToAddress(val) addr := common.StringToAddress(val)
if addr == nil { if addr == nil {
...@@ -90,25 +203,23 @@ func goValue(typ Type, val string) (res interface{}, err error) { ...@@ -90,25 +203,23 @@ func goValue(typ Type, val string) (res interface{}, err error) {
} }
return addr.ToHash160(), nil return addr.ToHash160(), nil
case FixedBytesTy: case FixedBytesTy:
//rtype := reflect.ArrayOf(typ.Size, reflect.TypeOf(byte(0)))
//value := reflect.New(rtype).Elem()
//value.SetBytes(x)
// 固定长度多字节,输入时以十六进制方式表示,如 0xabcd00ff // 固定长度多字节,输入时以十六进制方式表示,如 0xabcd00ff
//x, err := common.HexToBytes(val) x, err := common.HexToBytes(val)
//if err != nil { if err != nil {
// return res, err return res, err
//} }
//var data [typ.Size]byte rval := reflect.New(typ.Type).Elem()
//copy(data[:], x) for i, b := range x {
//return data, nil rval.Index(i).Set(reflect.ValueOf(b))
}
return rval.Interface(), nil
case BytesTy: case BytesTy:
// 单个字节,输入时以十六进制方式表示,如 0xab // 单个字节,输入时以十六进制方式表示,如 0xab
x, err := common.HexToBytes(val) x, err := common.HexToBytes(val)
if err != nil { if err != nil {
return res, err return res, err
} }
return x[0], nil return x, nil
case HashTy: case HashTy:
// 哈希类型,也是以十六进制为输入,如:0xabcdef // 哈希类型,也是以十六进制为输入,如:0xabcdef
x, err := common.HexToBytes(val) x, err := common.HexToBytes(val)
...@@ -134,13 +245,13 @@ func procArrayItem(val string) (res []string, err error) { ...@@ -134,13 +245,13 @@ func procArrayItem(val string) (res []string, err error) {
switch b { switch b {
case ' ': case ' ':
// 只有字符串元素中间的空格才是有效的 // 只有字符串元素中间的空格才是有效的
if ss.Len() > 0 && stackPeek(ss) == '"' { if ss.Len() > 0 && peekRune(ss) == '"' {
data = append(data, b) data = append(data, b)
} }
case ',': case ',':
// 逗号有可能是多级数组里面的分隔符,我们只处理最外层数组的分隔, // 逗号有可能是多级数组里面的分隔符,我们只处理最外层数组的分隔,
// 因此,需要判断当前栈中是否只有一个'[',否则就当做普通内容对待 // 因此,需要判断当前栈中是否只有一个'[',否则就当做普通内容对待
if ss.Len() == 1 && stackPeek(ss) == '[' { if ss.Len() == 1 && peekRune(ss) == '[' {
// 当前元素结束 // 当前元素结束
res = append(res, string(data)) res = append(res, string(data))
data = []rune{} data = []rune{}
...@@ -166,7 +277,7 @@ func procArrayItem(val string) (res []string, err error) { ...@@ -166,7 +277,7 @@ func procArrayItem(val string) (res []string, err error) {
ss.Push(b) ss.Push(b)
case ']': case ']':
// 只有当栈中只有一个']'时,才会被当做数组结束,否则就当做普通内容对待 // 只有当栈中只有一个']'时,才会被当做数组结束,否则就当做普通内容对待
if ss.Len() == 1 && stackPeek(ss) == '[' { if ss.Len() == 1 && peekRune(ss) == '[' {
// 整个数组结束 // 整个数组结束
res = append(res, string(data)) res = append(res, string(data))
} else { } else {
...@@ -185,6 +296,27 @@ func procArrayItem(val string) (res []string, err error) { ...@@ -185,6 +296,27 @@ func procArrayItem(val string) (res []string, err error) {
return res, err return res, err
} }
func stackPeek(ss *stack.Stack) rune { func peekRune(ss *stack.Stack) rune {
return ss.Peek().(rune) return ss.Peek().(rune)
} }
\ No newline at end of file
// 解析方法调用字符串,返回方法名以及方法参数
// 例如:foo(param1,param2) -> [foo,param1,param2]
func procFuncCall(param string) (funcName string, res []string, err error) {
lidx := strings.Index(param, "(")
ridx := strings.LastIndex(param, ")")
if lidx == -1 || ridx == -1 {
return funcName, res, fmt.Errorf("invalid function signature:%v", param)
}
funcName = strings.TrimSpace(param[:lidx])
params := strings.TrimSpace(param[lidx+1 : ridx])
// 将方法参数转换为数组形式,重用数组内容解析逻辑,获得各个具体的参数
if len(params) > 0 {
res, err = procArrayItem(fmt.Sprintf("[%v]", params))
}
return funcName, res, err
}
This diff is collapsed.
...@@ -23,7 +23,7 @@ import ( ...@@ -23,7 +23,7 @@ import (
"strings" "strings"
) )
// Argument holds the name of the argument and the corresponding type. // Argument holds the Name of the argument and the corresponding type.
// Types are used when packing and testing arguments. // Types are used when packing and testing arguments.
type Argument struct { type Argument struct {
Name string Name string
...@@ -86,7 +86,7 @@ func (arguments Arguments) isTuple() bool { ...@@ -86,7 +86,7 @@ func (arguments Arguments) isTuple() bool {
// Unpack performs the operation hexdata -> Go format // Unpack performs the operation hexdata -> Go format
func (arguments Arguments) Unpack(v interface{}, data []byte) error { func (arguments Arguments) Unpack(v interface{}, data []byte) error {
// make sure the passed value is arguments pointer // make sure the passed Value is arguments pointer
if reflect.Ptr != reflect.ValueOf(v).Kind() { if reflect.Ptr != reflect.ValueOf(v).Kind() {
return fmt.Errorf("abi: Unpack(non-pointer %T)", v) return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
} }
...@@ -152,10 +152,10 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa ...@@ -152,10 +152,10 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa
return nil return nil
} }
// unpackAtomic unpacks ( hexdata -> go ) a single value // unpackAtomic unpacks ( hexdata -> go ) a single Value
func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interface{}) error { func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interface{}) error {
if len(marshalledValues) != 1 { if len(marshalledValues) != 1 {
return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues)) return fmt.Errorf("abi: wrong length, expected single Value, got %d", len(marshalledValues))
} }
elem := reflect.ValueOf(v).Elem() elem := reflect.ValueOf(v).Elem()
...@@ -267,7 +267,7 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { ...@@ -267,7 +267,7 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
// will be appended at the end of the input. // will be appended at the end of the input.
variableInput = append(variableInput, packed...) variableInput = append(variableInput, packed...)
} else { } else {
// append the packed value to the input // append the packed Value to the input
ret = append(ret, packed...) ret = append(ret, packed...)
} }
} }
......
...@@ -23,7 +23,7 @@ import ( ...@@ -23,7 +23,7 @@ import (
) )
var ( var (
errBadBool = errors.New("abi: improperly encoded boolean value") errBadBool = errors.New("abi: improperly encoded boolean Value")
) )
// formatSliceString formats the reflection kind with the given slice size // formatSliceString formats the reflection kind with the given slice size
...@@ -60,7 +60,7 @@ func sliceTypeCheck(t Type, val reflect.Value) error { ...@@ -60,7 +60,7 @@ func sliceTypeCheck(t Type, val reflect.Value) error {
return nil return nil
} }
// typeCheck checks that the given reflection value can be assigned to the reflection // typeCheck checks that the given reflection Value can be assigned to the reflection
// type in t. // type in t.
func typeCheck(t Type, value reflect.Value) error { func typeCheck(t Type, value reflect.Value) error {
if t.T == SliceTy || t.T == ArrayTy { if t.T == SliceTy || t.T == ArrayTy {
......
...@@ -35,39 +35,39 @@ var jsonEventTransfer = []byte(`{ ...@@ -35,39 +35,39 @@ var jsonEventTransfer = []byte(`{
"anonymous": false, "anonymous": false,
"inputs": [ "inputs": [
{ {
"indexed": true, "name": "from", "type": "address" "indexed": true, "Name": "from", "type": "address"
}, { }, {
"indexed": true, "name": "to", "type": "address" "indexed": true, "Name": "to", "type": "address"
}, { }, {
"indexed": false, "name": "value", "type": "uint256" "indexed": false, "Name": "Value", "type": "uint256"
}], }],
"name": "Transfer", "Name": "Transfer",
"type": "event" "type": "event"
}`) }`)
var jsonEventPledge = []byte(`{ var jsonEventPledge = []byte(`{
"anonymous": false, "anonymous": false,
"inputs": [{ "inputs": [{
"indexed": false, "name": "who", "type": "address" "indexed": false, "Name": "who", "type": "address"
}, { }, {
"indexed": false, "name": "wad", "type": "uint128" "indexed": false, "Name": "wad", "type": "uint128"
}, { }, {
"indexed": false, "name": "currency", "type": "bytes3" "indexed": false, "Name": "currency", "type": "bytes3"
}], }],
"name": "Pledge", "Name": "Pledge",
"type": "event" "type": "event"
}`) }`)
var jsonEventMixedCase = []byte(`{ var jsonEventMixedCase = []byte(`{
"anonymous": false, "anonymous": false,
"inputs": [{ "inputs": [{
"indexed": false, "name": "value", "type": "uint256" "indexed": false, "Name": "Value", "type": "uint256"
}, { }, {
"indexed": false, "name": "_value", "type": "uint256" "indexed": false, "Name": "_value", "type": "uint256"
}, { }, {
"indexed": false, "name": "Value", "type": "uint256" "indexed": false, "Name": "Value", "type": "uint256"
}], }],
"name": "MixedCase", "Name": "MixedCase",
"type": "event" "type": "event"
}`) }`)
...@@ -87,8 +87,8 @@ func TestEventId(t *testing.T) { ...@@ -87,8 +87,8 @@ func TestEventId(t *testing.T) {
}{ }{
{ {
definition: `[ definition: `[
{ "type" : "event", "name" : "balance", "inputs": [{ "name" : "in", "type": "uint256" }] }, { "type" : "event", "Name" : "balance", "inputs": [{ "Name" : "in", "type": "uint256" }] },
{ "type" : "event", "name" : "check", "inputs": [{ "name" : "t", "type": "address" }, { "name": "b", "type": "uint256" }] } { "type" : "event", "Name" : "check", "inputs": [{ "Name" : "t", "type": "address" }, { "Name": "b", "type": "uint256" }] }
]`, ]`,
expectations: map[string]common.Hash{ expectations: map[string]common.Hash{
"balance": crypto.Keccak256Hash([]byte("balance(uint256)")), "balance": crypto.Keccak256Hash([]byte("balance(uint256)")),
...@@ -113,7 +113,7 @@ func TestEventId(t *testing.T) { ...@@ -113,7 +113,7 @@ func TestEventId(t *testing.T) {
// TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array. // TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array.
func TestEventMultiValueWithArrayUnpack(t *testing.T) { func TestEventMultiValueWithArrayUnpack(t *testing.T) {
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]` definition := `[{"Name": "test", "type": "event", "inputs": [{"indexed": false, "Name":"value1", "type":"uint8[2]"},{"indexed": false, "Name":"value2", "type":"uint8"}]}]`
type testStruct struct { type testStruct struct {
Value1 [2]uint8 Value1 [2]uint8
Value2 uint8 Value2 uint8
...@@ -138,20 +138,20 @@ func TestEventTupleUnpack(t *testing.T) { ...@@ -138,20 +138,20 @@ func TestEventTupleUnpack(t *testing.T) {
} }
type EventTransferWithTag struct { type EventTransferWithTag struct {
// this is valid because `value` is not exportable, // this is valid because `Value` is not exportable,
// so value is only unmarshalled into `Value1`. // so Value is only unmarshalled into `Value1`.
value *big.Int value *big.Int
Value1 *big.Int `abi:"value"` Value1 *big.Int `abi:"Value"`
} }
type BadEventTransferWithSameFieldAndTag struct { type BadEventTransferWithSameFieldAndTag struct {
Value *big.Int Value *big.Int
Value1 *big.Int `abi:"value"` Value1 *big.Int `abi:"Value"`
} }
type BadEventTransferWithDuplicatedTag struct { type BadEventTransferWithDuplicatedTag struct {
Value1 *big.Int `abi:"value"` Value1 *big.Int `abi:"Value"`
Value2 *big.Int `abi:"value"` Value2 *big.Int `abi:"Value"`
} }
type BadEventTransferWithEmptyTag struct { type BadEventTransferWithEmptyTag struct {
...@@ -171,7 +171,7 @@ func TestEventTupleUnpack(t *testing.T) { ...@@ -171,7 +171,7 @@ func TestEventTupleUnpack(t *testing.T) {
} }
type EventMixedCase struct { type EventMixedCase struct {
Value1 *big.Int `abi:"value"` Value1 *big.Int `abi:"Value"`
Value2 *big.Int `abi:"_value"` Value2 *big.Int `abi:"_value"`
Value3 *big.Int `abi:"Value"` Value3 *big.Int `abi:"Value"`
} }
...@@ -221,7 +221,7 @@ func TestEventTupleUnpack(t *testing.T) { ...@@ -221,7 +221,7 @@ func TestEventTupleUnpack(t *testing.T) {
&BadEventTransferWithSameFieldAndTag{}, &BadEventTransferWithSameFieldAndTag{},
&BadEventTransferWithSameFieldAndTag{}, &BadEventTransferWithSameFieldAndTag{},
jsonEventTransfer, jsonEventTransfer,
"abi: multiple variables maps to the same abi field 'value'", "abi: multiple variables maps to the same abi field 'Value'",
"Can not unpack ERC20 Transfer event with a field and a tag mapping to the same abi variable", "Can not unpack ERC20 Transfer event with a field and a tag mapping to the same abi variable",
}, { }, {
transferData1, transferData1,
...@@ -357,7 +357,7 @@ func (tc testCase) encoded(intType, arrayType Type) []byte { ...@@ -357,7 +357,7 @@ func (tc testCase) encoded(intType, arrayType Type) []byte {
// TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder. // TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder.
func TestEventUnpackIndexed(t *testing.T) { func TestEventUnpackIndexed(t *testing.T) {
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]` definition := `[{"Name": "test", "type": "event", "inputs": [{"indexed": true, "Name":"value1", "type":"uint8"},{"indexed": false, "Name":"value2", "type":"uint8"}]}]`
type testStruct struct { type testStruct struct {
Value1 uint8 Value1 uint8
Value2 uint8 Value2 uint8
...@@ -374,7 +374,7 @@ func TestEventUnpackIndexed(t *testing.T) { ...@@ -374,7 +374,7 @@ func TestEventUnpackIndexed(t *testing.T) {
// TestEventIndexedWithArrayUnpack verifies that decoder will not overlow when static array is indexed input. // TestEventIndexedWithArrayUnpack verifies that decoder will not overlow when static array is indexed input.
func TestEventIndexedWithArrayUnpack(t *testing.T) { func TestEventIndexedWithArrayUnpack(t *testing.T) {
definition := `[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"string"}]}]` definition := `[{"Name": "test", "type": "event", "inputs": [{"indexed": true, "Name":"value1", "type":"uint8[2]"},{"indexed": false, "Name":"value2", "type":"string"}]}]`
type testStruct struct { type testStruct struct {
Value1 [2]uint8 Value1 [2]uint8
Value2 string Value2 string
......
...@@ -30,7 +30,7 @@ func packBytesSlice(bytes []byte, l int) []byte { ...@@ -30,7 +30,7 @@ func packBytesSlice(bytes []byte, l int) []byte {
return append(len, common.RightPadBytes(bytes, (l+31)/32*32)...) return append(len, common.RightPadBytes(bytes, (l+31)/32*32)...)
} }
// packElement packs the given reflect value according to the abi specification in // packElement packs the given reflect Value according to the abi specification in
// t. // t.
func packElement(t Type, reflectValue reflect.Value) []byte { func packElement(t Type, reflectValue reflect.Value) []byte {
switch t.T { switch t.T {
...@@ -64,7 +64,7 @@ func packElement(t Type, reflectValue reflect.Value) []byte { ...@@ -64,7 +64,7 @@ func packElement(t Type, reflectValue reflect.Value) []byte {
} }
} }
// packNum packs the given number (using the reflect value) and will cast it to appropriate number representation // packNum packs the given number (using the reflect Value) and will cast it to appropriate number representation
func packNum(value reflect.Value) []byte { func packNum(value reflect.Value) []byte {
switch kind := value.Kind(); kind { switch kind := value.Kind(); kind {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
......
...@@ -22,7 +22,7 @@ import ( ...@@ -22,7 +22,7 @@ import (
"strings" "strings"
) )
// indirect recursively dereferences the value until it either gets the value // indirect recursively dereferences the Value until it either gets the Value
// or finds a big.Int // or finds a big.Int
func indirect(v reflect.Value) reflect.Value { func indirect(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Ptr && v.Elem().Type() != derefbigT { if v.Kind() == reflect.Ptr && v.Elem().Type() != derefbigT {
...@@ -59,8 +59,8 @@ func reflectIntKindAndType(unsigned bool, size int) (reflect.Kind, reflect.Type) ...@@ -59,8 +59,8 @@ func reflectIntKindAndType(unsigned bool, size int) (reflect.Kind, reflect.Type)
return reflect.Ptr, bigT return reflect.Ptr, bigT
} }
// mustArrayToBytesSlice creates a new byte slice with the exact same size as value // mustArrayToBytesSlice creates a new byte slice with the exact same size as Value
// and copies the bytes in value to the new slice. // and copies the bytes in Value to the new slice.
func mustArrayToByteSlice(value reflect.Value) reflect.Value { func mustArrayToByteSlice(value reflect.Value) reflect.Value {
slice := reflect.MakeSlice(reflect.TypeOf([]byte{}), value.Len(), value.Len()) slice := reflect.MakeSlice(reflect.TypeOf([]byte{}), value.Len(), value.Len())
reflect.Copy(slice, value) reflect.Copy(slice, value)
...@@ -114,7 +114,7 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind, ...@@ -114,7 +114,7 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind,
// mapAbiToStringField maps abi to struct fields. // mapAbiToStringField maps abi to struct fields.
// first round: for each Exportable field that contains a `abi:""` tag // first round: for each Exportable field that contains a `abi:""` tag
// and this field name exists in the arguments, pair them together. // and this field Name exists in the arguments, pair them together.
// second round: for each argument field that has not been already linked, // second round: for each argument field that has not been already linked,
// find what variable is expected to be mapped into, if it exists and has not been // find what variable is expected to be mapped into, if it exists and has not been
// used, pair them. // used, pair them.
...@@ -178,9 +178,9 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin ...@@ -178,9 +178,9 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin
} }
// this abi has already been paired, skip it... unless there exists another, yet unassigned // this abi has already been paired, skip it... unless there exists another, yet unassigned
// struct field with the same field name. If so, raise an error: // struct field with the same field Name. If so, raise an error:
// abi: [ { "name": "value" } ] // abi: [ { "Name": "Value" } ]
// struct { Value *big.Int , Value1 *big.Int `abi:"value"`} // struct { Value *big.Int , Value1 *big.Int `abi:"Value"`}
if abi2struct[abiFieldName] != "" { if abi2struct[abiFieldName] != "" {
if abi2struct[abiFieldName] != structFieldName && if abi2struct[abiFieldName] != structFieldName &&
struct2abi[structFieldName] == "" && struct2abi[structFieldName] == "" &&
...@@ -201,7 +201,7 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin ...@@ -201,7 +201,7 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin
struct2abi[structFieldName] = abiFieldName struct2abi[structFieldName] = abiFieldName
} else { } else {
// not paired, but annotate as used, to detect cases like // not paired, but annotate as used, to detect cases like
// abi : [ { "name": "value" }, { "name": "_value" } ] // abi : [ { "Name": "Value" }, { "Name": "_value" } ]
// struct { Value *big.Int } // struct { Value *big.Int }
struct2abi[structFieldName] = abiFieldName struct2abi[structFieldName] = abiFieldName
} }
......
...@@ -135,7 +135,7 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) ...@@ -135,7 +135,7 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error)
return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size) return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size)
} }
// this value will become our slice or our array, depending on the type // this Value will become our slice or our array, depending on the type
var refSlice reflect.Value var refSlice reflect.Value
if t.T == SliceTy { if t.T == SliceTy {
...@@ -170,7 +170,7 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) ...@@ -170,7 +170,7 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error)
return refSlice.Interface(), nil return refSlice.Interface(), nil
} }
// toGoType parses the output bytes and recursively assigns the value of these bytes // toGoType parses the output bytes and recursively assigns the Value of these bytes
// into a go type with accordance with the ABI spec. // into a go type with accordance with the ABI spec.
func toGoType(index int, t Type, output []byte) (interface{}, error) { func toGoType(index int, t Type, output []byte) (interface{}, error) {
if index+32 > len(output) { if index+32 > len(output) {
......
...@@ -65,13 +65,13 @@ var unpackTests = []unpackTest{ ...@@ -65,13 +65,13 @@ var unpackTests = []unpackTest{
def: `[{ "type": "bool" }]`, def: `[{ "type": "bool" }]`,
enc: "0000000000000000000000000000000000000000000000000001000000000001", enc: "0000000000000000000000000000000000000000000000000001000000000001",
want: false, want: false,
err: "abi: improperly encoded boolean value", err: "abi: improperly encoded boolean Value",
}, },
{ {
def: `[{ "type": "bool" }]`, def: `[{ "type": "bool" }]`,
enc: "0000000000000000000000000000000000000000000000000000000000000003", enc: "0000000000000000000000000000000000000000000000000000000000000003",
want: false, want: false,
err: "abi: improperly encoded boolean value", err: "abi: improperly encoded boolean Value",
}, },
{ {
def: `[{"type": "uint32"}]`, def: `[{"type": "uint32"}]`,
...@@ -288,7 +288,7 @@ var unpackTests = []unpackTest{ ...@@ -288,7 +288,7 @@ var unpackTests = []unpackTest{
}, },
// struct outputs // struct outputs
{ {
def: `[{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}]`, def: `[{"Name":"int1","type":"int256"},{"Name":"int2","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct { want: struct {
Int1 *big.Int Int1 *big.Int
...@@ -296,7 +296,7 @@ var unpackTests = []unpackTest{ ...@@ -296,7 +296,7 @@ var unpackTests = []unpackTest{
}{big.NewInt(1), big.NewInt(2)}, }{big.NewInt(1), big.NewInt(2)},
}, },
{ {
def: `[{"name":"int","type":"int256"},{"name":"Int","type":"int256"}]`, def: `[{"Name":"int","type":"int256"},{"Name":"Int","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct { want: struct {
Int1 *big.Int Int1 *big.Int
...@@ -305,7 +305,7 @@ var unpackTests = []unpackTest{ ...@@ -305,7 +305,7 @@ var unpackTests = []unpackTest{
err: "abi: multiple outputs mapping to the same struct field 'Int'", err: "abi: multiple outputs mapping to the same struct field 'Int'",
}, },
{ {
def: `[{"name":"int","type":"int256"},{"name":"_int","type":"int256"}]`, def: `[{"Name":"int","type":"int256"},{"Name":"_int","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct { want: struct {
Int1 *big.Int Int1 *big.Int
...@@ -314,7 +314,7 @@ var unpackTests = []unpackTest{ ...@@ -314,7 +314,7 @@ var unpackTests = []unpackTest{
err: "abi: multiple outputs mapping to the same struct field 'Int'", err: "abi: multiple outputs mapping to the same struct field 'Int'",
}, },
{ {
def: `[{"name":"Int","type":"int256"},{"name":"_int","type":"int256"}]`, def: `[{"Name":"Int","type":"int256"},{"Name":"_int","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct { want: struct {
Int1 *big.Int Int1 *big.Int
...@@ -323,7 +323,7 @@ var unpackTests = []unpackTest{ ...@@ -323,7 +323,7 @@ var unpackTests = []unpackTest{
err: "abi: multiple outputs mapping to the same struct field 'Int'", err: "abi: multiple outputs mapping to the same struct field 'Int'",
}, },
{ {
def: `[{"name":"Int","type":"int256"},{"name":"_","type":"int256"}]`, def: `[{"Name":"Int","type":"int256"},{"Name":"_","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct { want: struct {
Int1 *big.Int Int1 *big.Int
...@@ -336,7 +336,7 @@ var unpackTests = []unpackTest{ ...@@ -336,7 +336,7 @@ var unpackTests = []unpackTest{
func TestUnpack(t *testing.T) { func TestUnpack(t *testing.T) {
for i, test := range unpackTests { for i, test := range unpackTests {
t.Run(strconv.Itoa(i), func(t *testing.T) { t.Run(strconv.Itoa(i), func(t *testing.T) {
def := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def) def := fmt.Sprintf(`[{ "Name" : "method", "outputs": %s}]`, test.def)
abi, err := JSON(strings.NewReader(def)) abi, err := JSON(strings.NewReader(def))
if err != nil { if err != nil {
t.Fatalf("invalid ABI definition %s: %v", def, err) t.Fatalf("invalid ABI definition %s: %v", def, err)
...@@ -366,7 +366,7 @@ type methodMultiOutput struct { ...@@ -366,7 +366,7 @@ type methodMultiOutput struct {
func methodMultiReturn(require *require.Assertions) (ABI, []byte, methodMultiOutput) { func methodMultiReturn(require *require.Assertions) (ABI, []byte, methodMultiOutput) {
const definition = `[ const definition = `[
{ "name" : "multi", "constant" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]` { "Name" : "multi", "constant" : false, "outputs": [ { "Name": "Int", "type": "uint256" }, { "Name": "String", "type": "string" } ] }]`
var expected = methodMultiOutput{big.NewInt(1), "hello"} var expected = methodMultiOutput{big.NewInt(1), "hello"}
abi, err := JSON(strings.NewReader(definition)) abi, err := JSON(strings.NewReader(definition))
...@@ -440,7 +440,7 @@ func TestMethodMultiReturn(t *testing.T) { ...@@ -440,7 +440,7 @@ func TestMethodMultiReturn(t *testing.T) {
} }
func TestMultiReturnWithArray(t *testing.T) { func TestMultiReturnWithArray(t *testing.T) {
const definition = `[{"name" : "multi", "outputs": [{"type": "uint64[3]"}, {"type": "uint64"}]}]` const definition = `[{"Name" : "multi", "outputs": [{"type": "uint64[3]"}, {"type": "uint64"}]}]`
abi, err := JSON(strings.NewReader(definition)) abi, err := JSON(strings.NewReader(definition))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
...@@ -467,7 +467,7 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) { ...@@ -467,7 +467,7 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
// values of nested static arrays count towards the size as well, and any element following // values of nested static arrays count towards the size as well, and any element following
// after such nested array argument should be read with the correct offset, // after such nested array argument should be read with the correct offset,
// so that it does not read content from the previous array argument. // so that it does not read content from the previous array argument.
const definition = `[{"name" : "multi", "outputs": [{"type": "uint64[3][2][4]"}, {"type": "uint64"}]}]` const definition = `[{"Name" : "multi", "outputs": [{"type": "uint64[3][2][4]"}, {"type": "uint64"}]}]`
abi, err := JSON(strings.NewReader(definition)) abi, err := JSON(strings.NewReader(definition))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
...@@ -504,15 +504,15 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) { ...@@ -504,15 +504,15 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
func TestUnmarshal(t *testing.T) { func TestUnmarshal(t *testing.T) {
const definition = `[ const definition = `[
{ "name" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] }, { "Name" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] },
{ "name" : "bool", "constant" : false, "outputs": [ { "type": "bool" } ] }, { "Name" : "bool", "constant" : false, "outputs": [ { "type": "bool" } ] },
{ "name" : "bytes", "constant" : false, "outputs": [ { "type": "bytes" } ] }, { "Name" : "bytes", "constant" : false, "outputs": [ { "type": "bytes" } ] },
{ "name" : "fixed", "constant" : false, "outputs": [ { "type": "bytes32" } ] }, { "Name" : "fixed", "constant" : false, "outputs": [ { "type": "bytes32" } ] },
{ "name" : "multi", "constant" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] }, { "Name" : "multi", "constant" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] },
{ "name" : "intArraySingle", "constant" : false, "outputs": [ { "type": "uint256[3]" } ] }, { "Name" : "intArraySingle", "constant" : false, "outputs": [ { "type": "uint256[3]" } ] },
{ "name" : "addressSliceSingle", "constant" : false, "outputs": [ { "type": "address[]" } ] }, { "Name" : "addressSliceSingle", "constant" : false, "outputs": [ { "type": "address[]" } ] },
{ "name" : "addressSliceDouble", "constant" : false, "outputs": [ { "name": "a", "type": "address[]" }, { "name": "b", "type": "address[]" } ] }, { "Name" : "addressSliceDouble", "constant" : false, "outputs": [ { "Name": "a", "type": "address[]" }, { "Name": "b", "type": "address[]" } ] },
{ "name" : "mixedBytes", "constant" : true, "outputs": [ { "name": "a", "type": "bytes" }, { "name": "b", "type": "bytes32" } ] }]` { "Name" : "mixedBytes", "constant" : true, "outputs": [ { "Name": "a", "type": "bytes" }, { "Name": "b", "type": "bytes32" } ] }]`
abi, err := JSON(strings.NewReader(definition)) abi, err := JSON(strings.NewReader(definition))
if err != nil { if err != nil {
...@@ -535,11 +535,11 @@ func TestUnmarshal(t *testing.T) { ...@@ -535,11 +535,11 @@ func TestUnmarshal(t *testing.T) {
t.Error(err) t.Error(err)
} else { } else {
if !bytes.Equal(p0, p0Exp) { if !bytes.Equal(p0, p0Exp) {
t.Errorf("unexpected value unpacked: want %x, got %x", p0Exp, p0) t.Errorf("unexpected Value unpacked: want %x, got %x", p0Exp, p0)
} }
if !bytes.Equal(p1[:], p1Exp) { if !bytes.Equal(p1[:], p1Exp) {
t.Errorf("unexpected value unpacked: want %x, got %x", p1Exp, p1) t.Errorf("unexpected Value unpacked: want %x, got %x", p1Exp, p1)
} }
} }
...@@ -805,7 +805,7 @@ func TestOOMMaliciousInput(t *testing.T) { ...@@ -805,7 +805,7 @@ func TestOOMMaliciousInput(t *testing.T) {
}, },
} }
for i, test := range oomTests { for i, test := range oomTests {
def := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def) def := fmt.Sprintf(`[{ "Name" : "method", "outputs": %s}]`, test.def)
abi, err := JSON(strings.NewReader(def)) abi, err := JSON(strings.NewReader(def))
if err != nil { if err != nil {
t.Fatalf("invalid ABI definition %s: %v", def, err) t.Fatalf("invalid ABI definition %s: %v", def, err)
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"strings" "strings"
"bytes"
log "github.com/33cn/chain33/common/log/log15" log "github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
"github.com/33cn/plugin/plugin/dapp/evm/executor/abi" "github.com/33cn/plugin/plugin/dapp/evm/executor/abi"
...@@ -41,6 +42,9 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt, ...@@ -41,6 +42,9 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
contractAddr common.Address contractAddr common.Address
snapshot int snapshot int
execName string execName string
abiCall bool
abiData string
methodName string
) )
// 为了方便计费,即使合约为新生成,也将地址的初始化放到外面操作 // 为了方便计费,即使合约为新生成,也将地址的初始化放到外面操作
...@@ -62,9 +66,24 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt, ...@@ -62,9 +66,24 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
if isCreate { if isCreate {
ret, snapshot, leftOverGas, vmerr = env.Create(runtime.AccountRef(msg.From()), contractAddr, msg.Data(), context.GasLimit, execName, msg.Alias()) ret, snapshot, leftOverGas, vmerr = env.Create(runtime.AccountRef(msg.From()), contractAddr, msg.Data(), context.GasLimit, execName, msg.Alias())
} else { } else {
inData := msg.Data()
//TODO 在这里进行ABI和十六进制的调用参数转换 //TODO 在这里进行ABI和十六进制的调用参数转换
if bytes.HasPrefix(msg.Data(), evmtypes.ABICallPrefix) {
ret, snapshot, leftOverGas, vmerr = env.Call(runtime.AccountRef(msg.From()), *msg.To(), msg.Data(), context.GasLimit, msg.Value()) abiCall = true
callData := msg.Data()[len(evmtypes.ABICallPrefix):]
abiDataBin, err := evm.GetStateDB().Get(getABIKey(*msg.To()))
if err != nil {
return nil, err
}
abiData = string(abiDataBin)
funcName, packData, err := abi.Pack(string(callData), abiData)
if err != nil {
return nil, err
}
methodName = funcName
inData = packData
}
ret, snapshot, leftOverGas, vmerr = env.Call(runtime.AccountRef(msg.From()), *msg.To(), inData, context.GasLimit, msg.Value())
} }
log.Debug("call(create) contract ", "input", common.Bytes2Hex(msg.Data())) log.Debug("call(create) contract ", "input", common.Bytes2Hex(msg.Data()))
...@@ -103,7 +122,9 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt, ...@@ -103,7 +122,9 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
data, logs := evm.mStateDB.GetChangedData(curVer.GetID()) data, logs := evm.mStateDB.GetChangedData(curVer.GetID())
// TODO 在这里进行调用结果的转换 // TODO 在这里进行调用结果的转换
if abiCall {
}
contractReceipt := &evmtypes.ReceiptEVMContract{Caller: msg.From().String(), ContractName: execName, ContractAddr: contractAddr.String(), UsedGas: usedGas, Ret: ret} contractReceipt := &evmtypes.ReceiptEVMContract{Caller: msg.From().String(), ContractName: execName, ContractAddr: contractAddr.String(), UsedGas: usedGas, Ret: ret}
logs = append(logs, &types.ReceiptLog{Ty: evmtypes.TyLogCallContract, Log: types.Encode(contractReceipt)}) logs = append(logs, &types.ReceiptLog{Ty: evmtypes.TyLogCallContract, Log: types.Encode(contractReceipt)})
logs = append(logs, evm.mStateDB.GetReceiptLogs(contractAddr.String())...) logs = append(logs, evm.mStateDB.GetReceiptLogs(contractAddr.String())...)
...@@ -121,6 +142,8 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt, ...@@ -121,6 +142,8 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
_, err = abi.JSON(strings.NewReader(msg.ABI())) _, err = abi.JSON(strings.NewReader(msg.ABI()))
if err == nil { if err == nil {
data = append(data, evm.getABIKV(contractAddr, msg.ABI())) data = append(data, evm.getABIKV(contractAddr, msg.ABI()))
} else {
log.Debug("invalid abi data in transaction note", "note", msg.ABI())
} }
} }
......
...@@ -84,6 +84,11 @@ func (h Hash160Address) Hex() string { ...@@ -84,6 +84,11 @@ func (h Hash160Address) Hex() string {
return "0x" + string(result) return "0x" + string(result)
} }
// ToAddress 返回Chain33格式的地址
func (h Hash160Address) ToAddress() Address {
return BytesToAddress(h[:])
}
// NewAddress xHash生成EVM合约地址 // NewAddress xHash生成EVM合约地址
func NewAddress(txHash []byte) Address { func NewAddress(txHash []byte) Address {
execAddr := address.GetExecAddress(types.ExecName("user.evm.") + BytesToHash(txHash).Hex()) execAddr := address.GetExecAddress(types.ExecName("user.evm.") + BytesToHash(txHash).Hex())
......
...@@ -23,8 +23,7 @@ var ( ...@@ -23,8 +23,7 @@ var (
"EvmCall": EvmCallAction, "EvmCall": EvmCallAction,
} }
BindABIPrefix = ecommon.FromHex("0x00000000") ABICallPrefix = ecommon.FromHex("0x00000000")
ABICallPrefix = ecommon.FromHex("0xffffffff")
) )
func init() { func init() {
...@@ -214,10 +213,10 @@ func createEvmTx(param *CreateCallTx) (*types.Transaction, error) { ...@@ -214,10 +213,10 @@ func createEvmTx(param *CreateCallTx) (*types.Transaction, error) {
return createRawTx(action, "") return createRawTx(action, "")
} else { } else {
if err != nil { if err != nil {
elog.Debug("create evm call Tx as abi", "param.Code", param.Code) elog.Info("evm call data is invalid hex data, process it as abi data", "param.Code", param.Code)
bCode = []byte(param.Code) bCode = []byte(param.Code)
bCode = append(BindABIPrefix, bCode...) bCode = append(ABICallPrefix, bCode...)
} }
return createRawTx(action, param.Name) return createRawTx(action, param.Name)
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment