Commit d33e674d authored by Litian's avatar Litian

evm abi 解析逻辑初步完成

parent 9cc23096
......@@ -44,7 +44,7 @@ func JSON(reader io.Reader) (ABI, error) {
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
// of 4 bytes and arguments are all 32 bytes.
// Method ids are created from the first 4 bytes of the hash of the
......
This diff is collapsed.
package abi
import (
"encoding/json"
"fmt"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/golang-collections/collections/stack"
"math/big"
"reflect"
"strconv"
"strings"
)
// Pack 使用ABI方式调用时,将调用方式转换为EVM底层处理的十六进制编码
// abiData 完整的ABI定义
// param 调用方法及参数
func Pack(param, abiData string) ([]byte, error) {
return nil, nil
// 调用方式: foo(param1,param2)
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
// data 合约方法返回值
// abiData 完整的ABI定义
func Unpack(data []byte, abiData string) (string, error) {
return "", nil
func Unpack(data []byte, methodName, abiData string) (output string, err error) {
// 解析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类型的
func goValue(typ Type, val string) (res interface{}, err error) {
func str2GoValue(typ Type, val string) (res interface{}, err error) {
switch typ.T {
case IntTy:
bitSize := 0
pos := uint(typ.Kind - reflect.Int)
if pos > 0 {
bitSize = (2 << pos) * 2
}
x, err := strconv.ParseInt(val, 10, bitSize)
if err != nil {
return res, err
if typ.Size < 256 {
x, err := strconv.ParseInt(val, 10, typ.Size)
if err != nil {
return res, err
}
return convertInt(x, typ.Kind), nil
} else {
b := new(big.Int)
b.SetString(val, 10)
return b, err
}
return x, nil
case UintTy:
bitSize := 0
pos := uint(typ.Kind - reflect.Uint)
if pos > 0 {
bitSize = (2 << pos) * 2
}
x, err := strconv.ParseUint(val, 10, bitSize)
if err != nil {
return res, err
if typ.Size < 256 {
x, err := strconv.ParseUint(val, 10, typ.Size)
if err != nil {
return res, err
}
return convertUint(x, typ.Kind), nil
} else {
b := new(big.Int)
b.SetString(val, 10)
return b, err
}
return x, nil
case BoolTy:
x, err := strconv.ParseBool(val)
if err != nil {
......@@ -55,34 +168,34 @@ func goValue(typ Type, val string) (res interface{}, err error) {
return x, nil
case StringTy:
return val, nil
//case SliceTy:
// var data []interface{}
// subs, err := getSubArrayStr(val)
// if err != nil {
// return res, err
// }
// for idx, sub := range subs {
// subVal, er := goValue(*typ.Elem, sub)
// if er != nil {
// return res, er
// }
// data[idx] = subVal
// }
// return data, nil
//case ArrayTy:
// var data [typ.Size]interface{}
// subs, err := getSubArrayStr(val)
// if err != nil {
// return res, err
// }
// for idx, sub := range subs {
// subVal, er := goValue(*typ.Elem, sub)
// if er != nil {
// return res, er
// }
// data[idx] = subVal
// }
// return data, nil
case SliceTy:
subs, err := procArrayItem(val)
if err != nil {
return res, err
}
rval := reflect.MakeSlice(typ.Type, len(subs), len(subs))
for idx, sub := range subs {
subVal, er := str2GoValue(*typ.Elem, sub)
if er != nil {
return res, er
}
rval.Index(idx).Set(reflect.ValueOf(subVal))
}
return rval.Interface(), nil
case ArrayTy:
rval := reflect.New(typ.Type).Elem()
subs, err := procArrayItem(val)
if err != nil {
return res, err
}
for idx, sub := range subs {
subVal, er := str2GoValue(*typ.Elem, sub)
if er != nil {
return res, er
}
rval.Index(idx).Set(reflect.ValueOf(subVal))
}
return rval.Interface(), nil
case AddressTy:
addr := common.StringToAddress(val)
if addr == nil {
......@@ -90,25 +203,23 @@ func goValue(typ Type, val string) (res interface{}, err error) {
}
return addr.ToHash160(), nil
case FixedBytesTy:
//rtype := reflect.ArrayOf(typ.Size, reflect.TypeOf(byte(0)))
//value := reflect.New(rtype).Elem()
//value.SetBytes(x)
// 固定长度多字节,输入时以十六进制方式表示,如 0xabcd00ff
//x, err := common.HexToBytes(val)
//if err != nil {
// return res, err
//}
//var data [typ.Size]byte
//copy(data[:], x)
//return data, nil
x, err := common.HexToBytes(val)
if err != nil {
return res, err
}
rval := reflect.New(typ.Type).Elem()
for i, b := range x {
rval.Index(i).Set(reflect.ValueOf(b))
}
return rval.Interface(), nil
case BytesTy:
// 单个字节,输入时以十六进制方式表示,如 0xab
x, err := common.HexToBytes(val)
if err != nil {
return res, err
}
return x[0], nil
return x, nil
case HashTy:
// 哈希类型,也是以十六进制为输入,如:0xabcdef
x, err := common.HexToBytes(val)
......@@ -134,13 +245,13 @@ func procArrayItem(val string) (res []string, err error) {
switch b {
case ' ':
// 只有字符串元素中间的空格才是有效的
if ss.Len() > 0 && stackPeek(ss) == '"' {
if ss.Len() > 0 && peekRune(ss) == '"' {
data = append(data, b)
}
case ',':
// 逗号有可能是多级数组里面的分隔符,我们只处理最外层数组的分隔,
// 因此,需要判断当前栈中是否只有一个'[',否则就当做普通内容对待
if ss.Len() == 1 && stackPeek(ss) == '[' {
if ss.Len() == 1 && peekRune(ss) == '[' {
// 当前元素结束
res = append(res, string(data))
data = []rune{}
......@@ -166,7 +277,7 @@ func procArrayItem(val string) (res []string, err error) {
ss.Push(b)
case ']':
// 只有当栈中只有一个']'时,才会被当做数组结束,否则就当做普通内容对待
if ss.Len() == 1 && stackPeek(ss) == '[' {
if ss.Len() == 1 && peekRune(ss) == '[' {
// 整个数组结束
res = append(res, string(data))
} else {
......@@ -185,6 +296,27 @@ func procArrayItem(val string) (res []string, err error) {
return res, err
}
func stackPeek(ss *stack.Stack) rune {
func peekRune(ss *stack.Stack) 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 (
"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.
type Argument struct {
Name string
......@@ -86,7 +86,7 @@ func (arguments Arguments) isTuple() bool {
// Unpack performs the operation hexdata -> Go format
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() {
return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
}
......@@ -152,10 +152,10 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa
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 {
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()
......@@ -267,7 +267,7 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
// will be appended at the end of the input.
variableInput = append(variableInput, packed...)
} else {
// append the packed value to the input
// append the packed Value to the input
ret = append(ret, packed...)
}
}
......
......@@ -23,7 +23,7 @@ import (
)
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
......@@ -60,7 +60,7 @@ func sliceTypeCheck(t Type, val reflect.Value) error {
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.
func typeCheck(t Type, value reflect.Value) error {
if t.T == SliceTy || t.T == ArrayTy {
......
......@@ -35,39 +35,39 @@ var jsonEventTransfer = []byte(`{
"anonymous": false,
"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"
}`)
var jsonEventPledge = []byte(`{
"anonymous": false,
"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"
}`)
var jsonEventMixedCase = []byte(`{
"anonymous": false,
"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"
}`)
......@@ -87,8 +87,8 @@ func TestEventId(t *testing.T) {
}{
{
definition: `[
{ "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" : "balance", "inputs": [{ "Name" : "in", "type": "uint256" }] },
{ "type" : "event", "Name" : "check", "inputs": [{ "Name" : "t", "type": "address" }, { "Name": "b", "type": "uint256" }] }
]`,
expectations: map[string]common.Hash{
"balance": crypto.Keccak256Hash([]byte("balance(uint256)")),
......@@ -113,7 +113,7 @@ func TestEventId(t *testing.T) {
// TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array.
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 {
Value1 [2]uint8
Value2 uint8
......@@ -138,20 +138,20 @@ func TestEventTupleUnpack(t *testing.T) {
}
type EventTransferWithTag struct {
// this is valid because `value` is not exportable,
// so value is only unmarshalled into `Value1`.
// this is valid because `Value` is not exportable,
// so Value is only unmarshalled into `Value1`.
value *big.Int
Value1 *big.Int `abi:"value"`
Value1 *big.Int `abi:"Value"`
}
type BadEventTransferWithSameFieldAndTag struct {
Value *big.Int
Value1 *big.Int `abi:"value"`
Value1 *big.Int `abi:"Value"`
}
type BadEventTransferWithDuplicatedTag struct {
Value1 *big.Int `abi:"value"`
Value2 *big.Int `abi:"value"`
Value1 *big.Int `abi:"Value"`
Value2 *big.Int `abi:"Value"`
}
type BadEventTransferWithEmptyTag struct {
......@@ -171,7 +171,7 @@ func TestEventTupleUnpack(t *testing.T) {
}
type EventMixedCase struct {
Value1 *big.Int `abi:"value"`
Value1 *big.Int `abi:"Value"`
Value2 *big.Int `abi:"_value"`
Value3 *big.Int `abi:"Value"`
}
......@@ -221,7 +221,7 @@ func TestEventTupleUnpack(t *testing.T) {
&BadEventTransferWithSameFieldAndTag{},
&BadEventTransferWithSameFieldAndTag{},
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",
}, {
transferData1,
......@@ -357,7 +357,7 @@ func (tc testCase) encoded(intType, arrayType Type) []byte {
// TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder.
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 {
Value1 uint8
Value2 uint8
......@@ -374,7 +374,7 @@ func TestEventUnpackIndexed(t *testing.T) {
// TestEventIndexedWithArrayUnpack verifies that decoder will not overlow when static array is indexed input.
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 {
Value1 [2]uint8
Value2 string
......
......@@ -30,7 +30,7 @@ func packBytesSlice(bytes []byte, l int) []byte {
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.
func packElement(t Type, reflectValue reflect.Value) []byte {
switch t.T {
......@@ -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 {
switch kind := value.Kind(); kind {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
......
......@@ -22,7 +22,7 @@ import (
"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
func indirect(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Ptr && v.Elem().Type() != derefbigT {
......@@ -59,8 +59,8 @@ func reflectIntKindAndType(unsigned bool, size int) (reflect.Kind, reflect.Type)
return reflect.Ptr, bigT
}
// mustArrayToBytesSlice creates a new byte slice with the exact same size as value
// and copies the bytes in value to the new slice.
// mustArrayToBytesSlice creates a new byte slice with the exact same size as Value
// and copies the bytes in Value to the new slice.
func mustArrayToByteSlice(value reflect.Value) reflect.Value {
slice := reflect.MakeSlice(reflect.TypeOf([]byte{}), value.Len(), value.Len())
reflect.Copy(slice, value)
......@@ -114,7 +114,7 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind,
// mapAbiToStringField maps abi to struct fields.
// 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,
// find what variable is expected to be mapped into, if it exists and has not been
// used, pair them.
......@@ -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
// struct field with the same field name. If so, raise an error:
// abi: [ { "name": "value" } ]
// struct { Value *big.Int , Value1 *big.Int `abi:"value"`}
// struct field with the same field Name. If so, raise an error:
// abi: [ { "Name": "Value" } ]
// struct { Value *big.Int , Value1 *big.Int `abi:"Value"`}
if abi2struct[abiFieldName] != "" {
if abi2struct[abiFieldName] != structFieldName &&
struct2abi[structFieldName] == "" &&
......@@ -201,7 +201,7 @@ func mapAbiToStructFields(args Arguments, value reflect.Value) (map[string]strin
struct2abi[structFieldName] = abiFieldName
} else {
// not paired, but annotate as used, to detect cases like
// abi : [ { "name": "value" }, { "name": "_value" } ]
// abi : [ { "Name": "Value" }, { "Name": "_value" } ]
// struct { Value *big.Int }
struct2abi[structFieldName] = abiFieldName
}
......
......@@ -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)
}
// 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
if t.T == SliceTy {
......@@ -170,7 +170,7 @@ func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error)
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.
func toGoType(index int, t Type, output []byte) (interface{}, error) {
if index+32 > len(output) {
......
......@@ -65,13 +65,13 @@ var unpackTests = []unpackTest{
def: `[{ "type": "bool" }]`,
enc: "0000000000000000000000000000000000000000000000000001000000000001",
want: false,
err: "abi: improperly encoded boolean value",
err: "abi: improperly encoded boolean Value",
},
{
def: `[{ "type": "bool" }]`,
enc: "0000000000000000000000000000000000000000000000000000000000000003",
want: false,
err: "abi: improperly encoded boolean value",
err: "abi: improperly encoded boolean Value",
},
{
def: `[{"type": "uint32"}]`,
......@@ -288,7 +288,7 @@ var unpackTests = []unpackTest{
},
// struct outputs
{
def: `[{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}]`,
def: `[{"Name":"int1","type":"int256"},{"Name":"int2","type":"int256"}]`,
enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002",
want: struct {
Int1 *big.Int
......@@ -296,7 +296,7 @@ var unpackTests = []unpackTest{
}{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",
want: struct {
Int1 *big.Int
......@@ -305,7 +305,7 @@ var unpackTests = []unpackTest{
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",
want: struct {
Int1 *big.Int
......@@ -314,7 +314,7 @@ var unpackTests = []unpackTest{
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",
want: struct {
Int1 *big.Int
......@@ -323,7 +323,7 @@ var unpackTests = []unpackTest{
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",
want: struct {
Int1 *big.Int
......@@ -336,7 +336,7 @@ var unpackTests = []unpackTest{
func TestUnpack(t *testing.T) {
for i, test := range unpackTests {
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))
if err != nil {
t.Fatalf("invalid ABI definition %s: %v", def, err)
......@@ -366,7 +366,7 @@ type methodMultiOutput struct {
func methodMultiReturn(require *require.Assertions) (ABI, []byte, methodMultiOutput) {
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"}
abi, err := JSON(strings.NewReader(definition))
......@@ -440,7 +440,7 @@ func TestMethodMultiReturn(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))
if err != nil {
t.Fatal(err)
......@@ -467,7 +467,7 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
// 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,
// 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))
if err != nil {
t.Fatal(err)
......@@ -504,15 +504,15 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
func TestUnmarshal(t *testing.T) {
const definition = `[
{ "name" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] },
{ "name" : "bool", "constant" : false, "outputs": [ { "type": "bool" } ] },
{ "name" : "bytes", "constant" : false, "outputs": [ { "type": "bytes" } ] },
{ "name" : "fixed", "constant" : false, "outputs": [ { "type": "bytes32" } ] },
{ "name" : "multi", "constant" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] },
{ "name" : "intArraySingle", "constant" : false, "outputs": [ { "type": "uint256[3]" } ] },
{ "name" : "addressSliceSingle", "constant" : false, "outputs": [ { "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" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] },
{ "Name" : "bool", "constant" : false, "outputs": [ { "type": "bool" } ] },
{ "Name" : "bytes", "constant" : false, "outputs": [ { "type": "bytes" } ] },
{ "Name" : "fixed", "constant" : false, "outputs": [ { "type": "bytes32" } ] },
{ "Name" : "multi", "constant" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] },
{ "Name" : "intArraySingle", "constant" : false, "outputs": [ { "type": "uint256[3]" } ] },
{ "Name" : "addressSliceSingle", "constant" : false, "outputs": [ { "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" } ] }]`
abi, err := JSON(strings.NewReader(definition))
if err != nil {
......@@ -535,11 +535,11 @@ func TestUnmarshal(t *testing.T) {
t.Error(err)
} else {
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) {
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) {
},
}
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))
if err != nil {
t.Fatalf("invalid ABI definition %s: %v", def, err)
......
......@@ -9,6 +9,7 @@ import (
"strings"
"bytes"
log "github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types"
"github.com/33cn/plugin/plugin/dapp/evm/executor/abi"
......@@ -41,6 +42,9 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
contractAddr common.Address
snapshot int
execName string
abiCall bool
abiData string
methodName string
)
// 为了方便计费,即使合约为新生成,也将地址的初始化放到外面操作
......@@ -62,9 +66,24 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
if isCreate {
ret, snapshot, leftOverGas, vmerr = env.Create(runtime.AccountRef(msg.From()), contractAddr, msg.Data(), context.GasLimit, execName, msg.Alias())
} else {
inData := msg.Data()
//TODO 在这里进行ABI和十六进制的调用参数转换
ret, snapshot, leftOverGas, vmerr = env.Call(runtime.AccountRef(msg.From()), *msg.To(), msg.Data(), context.GasLimit, msg.Value())
if bytes.HasPrefix(msg.Data(), evmtypes.ABICallPrefix) {
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()))
......@@ -103,7 +122,9 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
data, logs := evm.mStateDB.GetChangedData(curVer.GetID())
// TODO 在这里进行调用结果的转换
if abiCall {
}
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, evm.mStateDB.GetReceiptLogs(contractAddr.String())...)
......@@ -121,6 +142,8 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
_, err = abi.JSON(strings.NewReader(msg.ABI()))
if err == nil {
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 {
return "0x" + string(result)
}
// ToAddress 返回Chain33格式的地址
func (h Hash160Address) ToAddress() Address {
return BytesToAddress(h[:])
}
// NewAddress xHash生成EVM合约地址
func NewAddress(txHash []byte) Address {
execAddr := address.GetExecAddress(types.ExecName("user.evm.") + BytesToHash(txHash).Hex())
......
......@@ -23,8 +23,7 @@ var (
"EvmCall": EvmCallAction,
}
BindABIPrefix = ecommon.FromHex("0x00000000")
ABICallPrefix = ecommon.FromHex("0xffffffff")
ABICallPrefix = ecommon.FromHex("0x00000000")
)
func init() {
......@@ -214,10 +213,10 @@ func createEvmTx(param *CreateCallTx) (*types.Transaction, error) {
return createRawTx(action, "")
} else {
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 = append(BindABIPrefix, bCode...)
bCode = append(ABICallPrefix, bCode...)
}
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