Commit 781721f6 authored by Litian's avatar Litian

evm 支持abi代码逻辑基本完成

parent d33e674d
...@@ -294,7 +294,7 @@ func (rc *raftNode) updateValidator() { ...@@ -294,7 +294,7 @@ func (rc *raftNode) updateValidator() {
rlog.Debug(fmt.Sprintf("==============This is %s node!==============", status.RaftState.String())) rlog.Debug(fmt.Sprintf("==============This is %s node!==============", status.RaftState.String()))
continue continue
} else { } else {
// 获取到leader Id,选主成功 // 获取到leader ID,选主成功
if rc.id == int(status.Lead) { if rc.id == int(status.Lead) {
//leader选举出来之后即可添加addReadOnlyPeers //leader选举出来之后即可添加addReadOnlyPeers
if !flag && !isRestart { if !flag && !isRestart {
......
...@@ -236,7 +236,7 @@ func main() { ...@@ -236,7 +236,7 @@ func main() {
} }
////读取当前目录下的文件 ////读取当前目录下的文件
//dir_list, e := ioutil.ReadDir("D:/Repository/src/github.com/33cn/chain33/consensus/drivers/raft/tools/scripts") //dir_list, e := ioutil.ReadDir("ID:/Repository/src/github.com/33cn/chain33/consensus/drivers/raft/tools/scripts")
//if e != nil { //if e != nil {
// fmt.Println("read dir error") // fmt.Println("read dir error")
// return // return
......
...@@ -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
...@@ -70,7 +70,7 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) { ...@@ -70,7 +70,7 @@ func (abi ABI) Pack(name string, args ...interface{}) ([]byte, error) {
return nil, err return nil, err
} }
// Pack up the method ID too if not a constructor and return // Pack up the method ID too if not a constructor and return
return append(method.Id(), arguments...), nil return append(method.ID(), arguments...), nil
} }
// Unpack output in v according to the abi specification // Unpack output in v according to the abi specification
...@@ -134,14 +134,14 @@ func (abi *ABI) UnmarshalJSON(data []byte) error { ...@@ -134,14 +134,14 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
return nil return nil
} }
// MethodById looks up a method by the 4-byte id // MethodByID looks up a method by the 4-byte id
// returns nil if none found // returns nil if none found
func (abi *ABI) MethodById(sigdata []byte) (*Method, error) { func (abi *ABI) MethodByID(sigdata []byte) (*Method, error) {
if len(sigdata) < 4 { if len(sigdata) < 4 {
return nil, fmt.Errorf("data too short (% bytes) for abi method lookup", len(sigdata)) return nil, fmt.Errorf("data too short (% bytes) for abi method lookup", len(sigdata))
} }
for _, method := range abi.Methods { for _, method := range abi.Methods {
if bytes.Equal(method.Id(), sigdata[:4]) { if bytes.Equal(method.ID(), sigdata[:4]) {
return &method, nil return &method, nil
} }
} }
......
This diff is collapsed.
...@@ -3,19 +3,22 @@ package abi ...@@ -3,19 +3,22 @@ package abi
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/golang-collections/collections/stack"
"math/big" "math/big"
"reflect" "reflect"
"strconv" "strconv"
"strings" "strings"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/golang-collections/collections/stack"
"github.com/kataras/iris/core/errors"
) )
// Pack 使用ABI方式调用时,将调用方式转换为EVM底层处理的十六进制编码 // Pack 使用ABI方式调用时,将调用方式转换为EVM底层处理的十六进制编码
// abiData 完整的ABI定义 // abiData 完整的ABI定义
// param 调用方法及参数 // param 调用方法及参数
// readOnly 是否只读,如果调用的方法不为只读,则报错
// 调用方式: foo(param1,param2) // 调用方式: foo(param1,param2)
func Pack(param, abiData string) (methodName string, packData []byte, err error) { func Pack(param, abiData string, readOnly bool) (methodName string, packData []byte, err error) {
// 首先解析参数字符串,分析出方法名以及个参数取值 // 首先解析参数字符串,分析出方法名以及个参数取值
methodName, params, err := procFuncCall(param) methodName, params, err := procFuncCall(param)
if err != nil { if err != nil {
...@@ -35,6 +38,13 @@ func Pack(param, abiData string) (methodName string, packData []byte, err error) ...@@ -35,6 +38,13 @@ func Pack(param, abiData string) (methodName string, packData []byte, err error)
return methodName, packData, err return methodName, packData, err
} }
if readOnly && !method.Const {
return methodName, packData, errors.New("method is not readonly")
}
if len(params) != method.Inputs.LengthNonIndexed() {
err = fmt.Errorf("function params error:%v", params)
return methodName, packData, err
}
// 获取方法参数对象,遍历解析各参数,获得参数的Go取值 // 获取方法参数对象,遍历解析各参数,获得参数的Go取值
paramVals := []interface{}{} paramVals := []interface{}{}
if len(params) != 0 { if len(params) != 0 {
...@@ -62,7 +72,9 @@ func Pack(param, abiData string) (methodName string, packData []byte, err error) ...@@ -62,7 +72,9 @@ func Pack(param, abiData string) (methodName string, packData []byte, err error)
// data 合约方法返回值 // data 合约方法返回值
// abiData 完整的ABI定义 // abiData 完整的ABI定义
func Unpack(data []byte, methodName, abiData string) (output string, err error) { func Unpack(data []byte, methodName, abiData string) (output string, err error) {
if len(data) == 0 {
return output, err
}
// 解析ABI数据结构,获取本次调用的方法对象 // 解析ABI数据结构,获取本次调用的方法对象
abi, err := JSON(strings.NewReader(abiData)) abi, err := JSON(strings.NewReader(abiData))
if err != nil { if err != nil {
...@@ -75,6 +87,10 @@ func Unpack(data []byte, methodName, abiData string) (output string, err error) ...@@ -75,6 +87,10 @@ func Unpack(data []byte, methodName, abiData string) (output string, err error)
return output, fmt.Errorf("function %v not exists", methodName) return output, fmt.Errorf("function %v not exists", methodName)
} }
if method.Outputs.LengthNonIndexed() == 0 {
return output, err
}
values, err := method.Outputs.UnpackValues(data) values, err := method.Outputs.UnpackValues(data)
if err != nil { if err != nil {
return output, err return output, err
...@@ -95,9 +111,13 @@ func Unpack(data []byte, methodName, abiData string) (output string, err error) ...@@ -95,9 +111,13 @@ func Unpack(data []byte, methodName, abiData string) (output string, err error)
return string(jsondata), err return string(jsondata), err
} }
// Param 返回值参数结构定义
type Param struct { type Param struct {
Name string `json:"name"` // Name 参数名称
Type string `json:"type"` Name string `json:"name"`
// Type 参数类型
Type string `json:"type"`
// Value 参数取值
Value interface{} `json:"value"` Value interface{} `json:"value"`
} }
...@@ -143,11 +163,10 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) { ...@@ -143,11 +163,10 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) {
return res, err return res, err
} }
return convertInt(x, typ.Kind), nil return convertInt(x, typ.Kind), nil
} else {
b := new(big.Int)
b.SetString(val, 10)
return b, err
} }
b := new(big.Int)
b.SetString(val, 10)
return b, err
case UintTy: case UintTy:
if typ.Size < 256 { if typ.Size < 256 {
x, err := strconv.ParseUint(val, 10, typ.Size) x, err := strconv.ParseUint(val, 10, typ.Size)
...@@ -155,11 +174,10 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) { ...@@ -155,11 +174,10 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) {
return res, err return res, err
} }
return convertUint(x, typ.Kind), nil return convertUint(x, typ.Kind), nil
} else {
b := new(big.Int)
b.SetString(val, 10)
return b, err
} }
b := new(big.Int)
b.SetString(val, 10)
return b, err
case BoolTy: case BoolTy:
x, err := strconv.ParseBool(val) x, err := strconv.ParseBool(val)
if err != nil { if err != nil {
...@@ -230,7 +248,6 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) { ...@@ -230,7 +248,6 @@ func str2GoValue(typ Type, val string) (res interface{}, err error) {
default: default:
return res, fmt.Errorf("not support type: %v", typ.stringKind) return res, fmt.Errorf("not support type: %v", typ.stringKind)
} }
return res, nil
} }
// 本方法可以将一个表示数组的字符串,经过处理后,返回数组内的字面元素; // 本方法可以将一个表示数组的字符串,经过处理后,返回数组内的字面元素;
......
...@@ -3,10 +3,11 @@ package abi ...@@ -3,10 +3,11 @@ package abi
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/stretchr/testify/assert"
"reflect" "reflect"
"testing" "testing"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/stretchr/testify/assert"
) )
func TestABI_Pack(t *testing.T) { func TestABI_Pack(t *testing.T) {
...@@ -33,7 +34,7 @@ func TestABI_Pack(t *testing.T) { ...@@ -33,7 +34,7 @@ func TestABI_Pack(t *testing.T) {
"0x60fe47b10000000000000000000000000000000000000000000000000000000000000064", "0x60fe47b10000000000000000000000000000000000000000000000000000000000000064",
}, },
} { } {
data, err := Pack(test.input, abiData) _, data, err := Pack(test.input, abiData, false)
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, test.output, common.Bytes2Hex(data)) assert.EqualValues(t, test.output, common.Bytes2Hex(data))
} }
......
...@@ -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
...@@ -31,6 +31,7 @@ type Argument struct { ...@@ -31,6 +31,7 @@ type Argument struct {
Indexed bool // indexed is only used by events Indexed bool // indexed is only used by events
} }
// Arguments Argument slice type
type Arguments []Argument type Arguments []Argument
// UnmarshalJSON implements json.Unmarshaler interface // UnmarshalJSON implements json.Unmarshaler interface
...@@ -86,7 +87,7 @@ func (arguments Arguments) isTuple() bool { ...@@ -86,7 +87,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 +153,10 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa ...@@ -152,10 +153,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 +268,7 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { ...@@ -267,7 +268,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 {
......
...@@ -44,9 +44,9 @@ func (e Event) String() string { ...@@ -44,9 +44,9 @@ func (e Event) String() string {
return fmt.Sprintf("e %v(%v)", e.Name, strings.Join(inputs, ", ")) return fmt.Sprintf("e %v(%v)", e.Name, strings.Join(inputs, ", "))
} }
// Id returns the canonical representation of the event's signature used by the // ID returns the canonical representation of the event's signature used by the
// abi definition to identify event names and types. // abi definition to identify event names and types.
func (e Event) Id() common.Hash { func (e Event) ID() common.Hash {
types := make([]string, len(e.Inputs)) types := make([]string, len(e.Inputs))
i := 0 i := 0
for _, input := range e.Inputs { for _, input := range e.Inputs {
......
...@@ -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)")),
...@@ -104,8 +104,8 @@ func TestEventId(t *testing.T) { ...@@ -104,8 +104,8 @@ func TestEventId(t *testing.T) {
} }
for name, event := range abi.Events { for name, event := range abi.Events {
if event.Id() != test.expectations[name] { if event.ID() != test.expectations[name] {
t.Errorf("expected id to be %x, got %x", test.expectations[name], event.Id()) t.Errorf("expected id to be %x, got %x", test.expectations[name], event.ID())
} }
} }
} }
...@@ -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 {
...@@ -159,7 +159,7 @@ func TestEventTupleUnpack(t *testing.T) { ...@@ -159,7 +159,7 @@ func TestEventTupleUnpack(t *testing.T) {
} }
type EventPledge struct { type EventPledge struct {
Who common.Hash160Address Who common.Hash160Address
Wad *big.Int Wad *big.Int
Currency [3]byte Currency [3]byte
} }
...@@ -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,
...@@ -242,7 +242,7 @@ func TestEventTupleUnpack(t *testing.T) { ...@@ -242,7 +242,7 @@ func TestEventTupleUnpack(t *testing.T) {
"Can unpack Pledge event into structure", "Can unpack Pledge event into structure",
}, { }, {
pledgeData1, pledgeData1,
&[]interface{}{& common.Hash160Address{}, &bigint, &[3]byte{}}, &[]interface{}{&common.Hash160Address{}, &bigint, &[3]byte{}},
&[]interface{}{ &[]interface{}{
&addr, &addr,
&bigintExpected2, &bigintExpected2,
...@@ -252,7 +252,7 @@ func TestEventTupleUnpack(t *testing.T) { ...@@ -252,7 +252,7 @@ func TestEventTupleUnpack(t *testing.T) {
"Can unpack Pledge event into slice", "Can unpack Pledge event into slice",
}, { }, {
pledgeData1, pledgeData1,
&[3]interface{}{& common.Hash160Address{}, &bigint, &[3]byte{}}, &[3]interface{}{&common.Hash160Address{}, &bigint, &[3]byte{}},
&[3]interface{}{ &[3]interface{}{
&addr, &addr,
&bigintExpected2, &bigintExpected2,
...@@ -276,7 +276,7 @@ func TestEventTupleUnpack(t *testing.T) { ...@@ -276,7 +276,7 @@ func TestEventTupleUnpack(t *testing.T) {
"Can not unpack Pledge event into struct with wrong filed types", "Can not unpack Pledge event into struct with wrong filed types",
}, { }, {
pledgeData1, pledgeData1,
&[]interface{}{ common.Hash160Address{}, new(big.Int)}, &[]interface{}{common.Hash160Address{}, new(big.Int)},
&[]interface{}{}, &[]interface{}{},
jsonEventPledge, jsonEventPledge,
"abi: insufficient number of elements in the list/array for unpack, want 3, got 2", "abi: insufficient number of elements in the list/array for unpack, want 3, got 2",
...@@ -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
......
...@@ -72,6 +72,7 @@ func (method Method) String() string { ...@@ -72,6 +72,7 @@ func (method Method) String() string {
return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.Name, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", ")) return fmt.Sprintf("function %v(%v) %sreturns(%v)", method.Name, strings.Join(inputs, ", "), constant, strings.Join(outputs, ", "))
} }
func (method Method) Id() []byte { // ID method name hash
func (method Method) ID() []byte {
return crypto.Keccak256([]byte(method.Sig()))[:4] return crypto.Keccak256([]byte(method.Sig()))[:4]
} }
...@@ -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:
......
...@@ -306,7 +306,7 @@ func TestPack(t *testing.T) { ...@@ -306,7 +306,7 @@ func TestPack(t *testing.T) {
}, },
{ {
"address[]", "address[]",
[] common.Hash160Address{{1}, {2}}, []common.Hash160Address{{1}, {2}},
common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000"), common.Hex2Bytes("000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000"),
}, },
{ {
...@@ -347,7 +347,7 @@ func TestMethodPack(t *testing.T) { ...@@ -347,7 +347,7 @@ func TestMethodPack(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
sig := abi.Methods["slice"].Id() sig := abi.Methods["slice"].ID()
sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
...@@ -360,14 +360,14 @@ func TestMethodPack(t *testing.T) { ...@@ -360,14 +360,14 @@ func TestMethodPack(t *testing.T) {
t.Errorf("expected %x got %x", sig, packed) t.Errorf("expected %x got %x", sig, packed)
} }
var addrA, addrB = common.Hash160Address{1}, common.Hash160Address{2} var addrA, addrB = common.Hash160Address{1}, common.Hash160Address{2}
sig = abi.Methods["sliceAddress"].Id() sig = abi.Methods["sliceAddress"].ID()
sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...) sig = append(sig, common.LeftPadBytes([]byte{32}, 32)...)
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
sig = append(sig, common.LeftPadBytes(addrA[:], 32)...) sig = append(sig, common.LeftPadBytes(addrA[:], 32)...)
sig = append(sig, common.LeftPadBytes(addrB[:], 32)...) sig = append(sig, common.LeftPadBytes(addrB[:], 32)...)
packed, err = abi.Pack("sliceAddress", [] common.Hash160Address{addrA, addrB}) packed, err = abi.Pack("sliceAddress", []common.Hash160Address{addrA, addrB})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -375,8 +375,8 @@ func TestMethodPack(t *testing.T) { ...@@ -375,8 +375,8 @@ func TestMethodPack(t *testing.T) {
t.Errorf("expected %x got %x", sig, packed) t.Errorf("expected %x got %x", sig, packed)
} }
var addrC, addrD = common.Hash160Address{3}, common.Hash160Address{4} var addrC, addrD = common.Hash160Address{3}, common.Hash160Address{4}
sig = abi.Methods["sliceMultiAddress"].Id() sig = abi.Methods["sliceMultiAddress"].ID()
sig = append(sig, common.LeftPadBytes([]byte{64}, 32)...) sig = append(sig, common.LeftPadBytes([]byte{64}, 32)...)
sig = append(sig, common.LeftPadBytes([]byte{160}, 32)...) sig = append(sig, common.LeftPadBytes([]byte{160}, 32)...)
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
...@@ -386,7 +386,7 @@ func TestMethodPack(t *testing.T) { ...@@ -386,7 +386,7 @@ func TestMethodPack(t *testing.T) {
sig = append(sig, common.LeftPadBytes(addrC[:], 32)...) sig = append(sig, common.LeftPadBytes(addrC[:], 32)...)
sig = append(sig, common.LeftPadBytes(addrD[:], 32)...) sig = append(sig, common.LeftPadBytes(addrD[:], 32)...)
packed, err = abi.Pack("sliceMultiAddress", [] common.Hash160Address{addrA, addrB}, [] common.Hash160Address{addrC, addrD}) packed, err = abi.Pack("sliceMultiAddress", []common.Hash160Address{addrA, addrB}, []common.Hash160Address{addrC, addrD})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -394,7 +394,7 @@ func TestMethodPack(t *testing.T) { ...@@ -394,7 +394,7 @@ func TestMethodPack(t *testing.T) {
t.Errorf("expected %x got %x", sig, packed) t.Errorf("expected %x got %x", sig, packed)
} }
sig = abi.Methods["slice256"].Id() sig = abi.Methods["slice256"].ID()
sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...) sig = append(sig, common.LeftPadBytes([]byte{1}, 32)...)
sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...) sig = append(sig, common.LeftPadBytes([]byte{2}, 32)...)
......
...@@ -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
} }
......
...@@ -84,8 +84,8 @@ func TestTypeRegexp(t *testing.T) { ...@@ -84,8 +84,8 @@ func TestTypeRegexp(t *testing.T) {
{"string[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]string{}), Elem: &Type{Kind: reflect.String, Type: reflect.TypeOf(""), T: StringTy, stringKind: "string"}, stringKind: "string[]"}}, {"string[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]string{}), Elem: &Type{Kind: reflect.String, Type: reflect.TypeOf(""), T: StringTy, stringKind: "string"}, stringKind: "string[]"}},
{"string[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]string{}), Elem: &Type{Kind: reflect.String, T: StringTy, Type: reflect.TypeOf(""), stringKind: "string"}, stringKind: "string[2]"}}, {"string[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]string{}), Elem: &Type{Kind: reflect.String, T: StringTy, Type: reflect.TypeOf(""), stringKind: "string"}, stringKind: "string[2]"}},
{"address", Type{Kind: reflect.Array, Type: addressT, Size: 20, T: AddressTy, stringKind: "address"}}, {"address", Type{Kind: reflect.Array, Type: addressT, Size: 20, T: AddressTy, stringKind: "address"}},
{"address[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([] common.Hash160Address{}), Elem: &Type{Kind: reflect.Array, Type: addressT, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[]"}}, {"address[]", Type{T: SliceTy, Kind: reflect.Slice, Type: reflect.TypeOf([]common.Hash160Address{}), Elem: &Type{Kind: reflect.Array, Type: addressT, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[]"}},
{"address[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2] common.Hash160Address{}), Elem: &Type{Kind: reflect.Array, Type: addressT, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[2]"}}, {"address[2]", Type{Kind: reflect.Array, T: ArrayTy, Size: 2, Type: reflect.TypeOf([2]common.Hash160Address{}), Elem: &Type{Kind: reflect.Array, Type: addressT, Size: 20, T: AddressTy, stringKind: "address"}, stringKind: "address[2]"}},
// TODO when fixed types are implemented properly // TODO when fixed types are implemented properly
// {"fixed", Type{}}, // {"fixed", Type{}},
// {"fixed128x128", Type{}}, // {"fixed128x128", Type{}},
...@@ -102,7 +102,7 @@ func TestTypeRegexp(t *testing.T) { ...@@ -102,7 +102,7 @@ func TestTypeRegexp(t *testing.T) {
} }
if !reflect.DeepEqual(typ, tt.kind) { if !reflect.DeepEqual(typ, tt.kind) {
//t.Errorf("type %q: parsed type mismatch:\nGOT %s\nWANT %s ", tt.blob, spew.Sdump(typeWithoutStringer(typ)), spew.Sdump(typeWithoutStringer(tt.kind))) //t.Errorf("type %q: parsed type mismatch:\nGOT %s\nWANT %s ", tt.blob, spew.Sdump(typeWithoutStringer(typ)), spew.Sdump(typeWithoutStringer(tt.kind)))
t.Errorf("type %q: parsed type mismatch:\nGOT %s\nWANT %s ", tt.blob, typeWithoutStringer(typ), typeWithoutStringer(tt.kind)) t.Errorf("type %q: parsed type mismatch:\nGOT %s\nWANT %s ", tt.blob, typ, tt.kind)
} }
} }
} }
...@@ -201,10 +201,10 @@ func TestTypeCheck(t *testing.T) { ...@@ -201,10 +201,10 @@ func TestTypeCheck(t *testing.T) {
{"uint16[3]", [4]uint16{1, 2, 3}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"}, {"uint16[3]", [4]uint16{1, 2, 3}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"},
{"uint16[3]", []uint16{1, 2, 3}, ""}, {"uint16[3]", []uint16{1, 2, 3}, ""},
{"uint16[3]", []uint16{1, 2, 3, 4}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"}, {"uint16[3]", []uint16{1, 2, 3, 4}, "abi: cannot use [4]uint16 as type [3]uint16 as argument"},
{"address[]", [] common.Hash160Address{{1}}, ""}, {"address[]", []common.Hash160Address{{1}}, ""},
{"address[1]", [] common.Hash160Address{{1}}, ""}, {"address[1]", []common.Hash160Address{{1}}, ""},
{"address[1]", [1] common.Hash160Address{{1}}, ""}, {"address[1]", [1]common.Hash160Address{{1}}, ""},
{"address[2]", [1] common.Hash160Address{{1}}, "abi: cannot use [1]array as type [2]array as argument"}, {"address[2]", [1]common.Hash160Address{{1}}, "abi: cannot use [1]array as type [2]array as argument"},
{"bytes32", [32]byte{}, ""}, {"bytes32", [32]byte{}, ""},
{"bytes31", [31]byte{}, ""}, {"bytes31", [31]byte{}, ""},
{"bytes30", [30]byte{}, ""}, {"bytes30", [30]byte{}, ""},
...@@ -249,9 +249,9 @@ func TestTypeCheck(t *testing.T) { ...@@ -249,9 +249,9 @@ func TestTypeCheck(t *testing.T) {
{"string", []byte{}, "abi: cannot use slice as type string as argument"}, {"string", []byte{}, "abi: cannot use slice as type string as argument"},
{"bytes32[]", [][32]byte{{}}, ""}, {"bytes32[]", [][32]byte{{}}, ""},
{"function", [24]byte{}, ""}, {"function", [24]byte{}, ""},
{"bytes20", common.Hash160Address{}, ""}, {"bytes20", common.Hash160Address{}, ""},
{"address", [20]byte{}, ""}, {"address", [20]byte{}, ""},
{"address", common.Hash160Address{}, ""}, {"address", common.Hash160Address{}, ""},
{"bytes32[]]", "", "invalid arg type in abi"}, {"bytes32[]]", "", "invalid arg type in abi"},
{"invalidType", "", "unsupported arg type: invalidType"}, {"invalidType", "", "unsupported arg type: invalidType"},
{"invalidSlice[]", "", "unsupported arg type: invalidSlice"}, {"invalidSlice[]", "", "unsupported arg type: invalidSlice"},
......
...@@ -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) {
......
This diff is collapsed.
...@@ -9,7 +9,6 @@ import ( ...@@ -9,7 +9,6 @@ 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"
...@@ -28,7 +27,12 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt, ...@@ -28,7 +27,12 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
if err != nil { if err != nil {
return nil, err return nil, err
} }
return evm.innerExec(msg, tx.Hash(), index, tx.Fee, false)
}
// 通用的EVM合约执行逻辑封装
// readOnly 是否只读调用,仅执行evm abi查询时为true
func (evm *EVMExecutor) innerExec(msg *common.Message, txHash []byte, index int, txFee int64, readOnly bool) (receipt *types.Receipt, err error) {
// 获取当前区块的上下文信息构造EVM上下文 // 获取当前区块的上下文信息构造EVM上下文
context := evm.NewEVMContext(msg) context := evm.NewEVMContext(msg)
...@@ -42,7 +46,6 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt, ...@@ -42,7 +46,6 @@ 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 abiData string
methodName string methodName string
) )
...@@ -50,38 +53,38 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt, ...@@ -50,38 +53,38 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
// 为了方便计费,即使合约为新生成,也将地址的初始化放到外面操作 // 为了方便计费,即使合约为新生成,也将地址的初始化放到外面操作
if isCreate { if isCreate {
// 使用随机生成的地址作为合约地址(这个可以保证每次创建的合约地址不会重复,不存在冲突的情况) // 使用随机生成的地址作为合约地址(这个可以保证每次创建的合约地址不会重复,不存在冲突的情况)
contractAddr = evm.getNewAddr(tx.Hash()) contractAddr = evm.getNewAddr(txHash)
if !env.StateDB.Empty(contractAddr.String()) { if !env.StateDB.Empty(contractAddr.String()) {
return nil, model.ErrContractAddressCollision return receipt, model.ErrContractAddressCollision
} }
// 只有新创建的合约才能生成合约名称 // 只有新创建的合约才能生成合约名称
execName = fmt.Sprintf("%s%s", types.ExecName(evmtypes.EvmPrefix), common.BytesToHash(tx.Hash()).Hex()) execName = fmt.Sprintf("%s%s", types.ExecName(evmtypes.EvmPrefix), common.BytesToHash(txHash).Hex())
} else { } else {
contractAddr = *msg.To() contractAddr = *msg.To()
} }
// 状态机中设置当前交易状态 // 状态机中设置当前交易状态
evm.mStateDB.Prepare(common.BytesToHash(tx.Hash()), index) evm.mStateDB.Prepare(common.BytesToHash(txHash), index)
if isCreate { if isCreate {
ret, snapshot, leftOverGas, vmerr = env.Create(runtime.AccountRef(msg.From()), contractAddr, msg.Data(), context.GasLimit, execName, msg.Alias()) // 如果携带ABI数据,则对数据合法性进行检查
} else { if len(msg.ABI()) > 0 && types.IsDappFork(evm.GetHeight(), "evm", "ForkEVMABI") {
inData := msg.Data() _, err = abi.JSON(strings.NewReader(abiData))
//TODO 在这里进行ABI和十六进制的调用参数转换
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 { if err != nil {
return nil, err return receipt, err
} }
abiData = string(abiDataBin) }
funcName, packData, err := abi.Pack(string(callData), abiData) ret, snapshot, leftOverGas, vmerr = env.Create(runtime.AccountRef(msg.From()), contractAddr, msg.Data(), context.GasLimit, execName, msg.Alias(), msg.ABI())
} else {
inData := msg.Data()
// 在这里进行ABI和十六进制的调用参数转换
if len(msg.ABI()) > 0 && types.IsDappFork(evm.GetHeight(), "evm", "ForkEVMABI") {
funcName, packData, err := abi.Pack(msg.ABI(), evm.mStateDB.GetAbi(msg.To().String()), readOnly)
if err != nil { if err != nil {
return nil, err return receipt, err
} }
methodName = funcName
inData = packData inData = packData
methodName = funcName
} }
ret, snapshot, leftOverGas, vmerr = env.Call(runtime.AccountRef(msg.From()), *msg.To(), inData, context.GasLimit, msg.Value()) ret, snapshot, leftOverGas, vmerr = env.Call(runtime.AccountRef(msg.From()), *msg.To(), inData, context.GasLimit, msg.Value())
} }
...@@ -98,34 +101,40 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt, ...@@ -98,34 +101,40 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
if vmerr != nil { if vmerr != nil {
log.Error("evm contract exec error", "error info", vmerr) log.Error("evm contract exec error", "error info", vmerr)
return nil, vmerr return receipt, vmerr
} }
// 计算消耗了多少费用(实际消耗的费用) // 计算消耗了多少费用(实际消耗的费用)
usedFee, overflow := common.SafeMul(usedGas, uint64(msg.GasPrice())) usedFee, overflow := common.SafeMul(usedGas, uint64(msg.GasPrice()))
// 费用消耗溢出,执行失败 // 费用消耗溢出,执行失败
if overflow || usedFee > uint64(tx.Fee) { if overflow || usedFee > uint64(txFee) {
// 如果操作没有回滚,则在这里处理 // 如果操作没有回滚,则在这里处理
if curVer != nil && snapshot >= curVer.GetID() && curVer.GetID() > -1 { if curVer != nil && snapshot >= curVer.GetID() && curVer.GetID() > -1 {
evm.mStateDB.RevertToSnapshot(snapshot) evm.mStateDB.RevertToSnapshot(snapshot)
} }
return nil, model.ErrOutOfGas return receipt, model.ErrOutOfGas
} }
// 打印合约中生成的日志 // 打印合约中生成的日志
evm.mStateDB.PrintLogs() evm.mStateDB.PrintLogs()
// 没有任何数据变更
if curVer == nil { if curVer == nil {
return nil, nil return receipt, nil
} }
// 从状态机中获取数据变更和变更日志
data, logs := evm.mStateDB.GetChangedData(curVer.GetID())
// TODO 在这里进行调用结果的转换 // 从状态机中获取数据变更和变更日志
if abiCall { kvSet, logs := evm.mStateDB.GetChangedData(curVer.GetID())
}
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}
// 这里进行ABI调用结果格式化
if len(methodName) > 0 && len(msg.ABI()) > 0 && types.IsDappFork(evm.GetHeight(), "evm", "ForkEVMABI") {
jsonRet, err := abi.Unpack(ret, methodName, evm.mStateDB.GetAbi(msg.To().String()))
if err != nil {
// 这里出错不影响整体执行,只打印错误信息
log.Error("unpack evm return error", "error", err)
}
contractReceipt.JsonRet = jsonRet
}
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())...)
...@@ -133,21 +142,11 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt, ...@@ -133,21 +142,11 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
// 将执行时生成的合约状态数据变更信息也计算哈希并保存 // 将执行时生成的合约状态数据变更信息也计算哈希并保存
hashKV := evm.calcKVHash(contractAddr, logs) hashKV := evm.calcKVHash(contractAddr, logs)
if hashKV != nil { if hashKV != nil {
data = append(data, hashKV) kvSet = append(kvSet, hashKV)
}
}
// 尝试从交易备注中获取ABI数据
if isCreate && types.IsDappFork(evm.GetHeight(), "evm", "ForkEVMABI") {
_, 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())
} }
} }
receipt := &types.Receipt{Ty: types.ExecOk, KV: data, Logs: logs} receipt = &types.Receipt{Ty: types.ExecOk, KV: kvSet, Logs: logs}
// 返回之前,把本次交易在区块中生成的合约日志集中打印出来 // 返回之前,把本次交易在区块中生成的合约日志集中打印出来
if evm.mStateDB != nil { if evm.mStateDB != nil {
...@@ -155,9 +154,10 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt, ...@@ -155,9 +154,10 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
} }
// 替换导致分叉的执行数据信息 // 替换导致分叉的执行数据信息
state.ProcessFork(evm.GetHeight(), tx.Hash(), receipt) state.ProcessFork(evm.GetHeight(), txHash, receipt)
evm.collectEvmTxLog(txHash, contractReceipt, receipt)
evm.collectEvmTxLog(tx, contractReceipt, receipt)
return receipt, nil return receipt, nil
} }
...@@ -173,22 +173,17 @@ func (evm *EVMExecutor) GetMessage(tx *types.Transaction) (msg *common.Message, ...@@ -173,22 +173,17 @@ func (evm *EVMExecutor) GetMessage(tx *types.Transaction) (msg *common.Message,
var action evmtypes.EVMContractAction var action evmtypes.EVMContractAction
err = types.Decode(tx.Payload, &action) err = types.Decode(tx.Payload, &action)
if err != nil { if err != nil {
return nil, err return msg, err
} }
// 此处暂时不考虑消息发送签名的处理,chain33在mempool中对签名做了检查 // 此处暂时不考虑消息发送签名的处理,chain33在mempool中对签名做了检查
from := getCaller(tx) from := getCaller(tx)
to := getReceiver(tx) to := getReceiver(tx)
if to == nil { if to == nil {
return nil, types.ErrInvalidAddress return msg, types.ErrInvalidAddress
} }
// 注意Transaction中的payload内容同时包含转账金额和合约代码
// payload[:8]为转账金额,payload[8:]为合约代码
amount := action.Amount
gasLimit := action.GasLimit gasLimit := action.GasLimit
gasPrice := action.GasPrice gasPrice := action.GasPrice
code := action.Code
if gasLimit == 0 { if gasLimit == 0 {
gasLimit = uint64(tx.Fee) gasLimit = uint64(tx.Fee)
} }
...@@ -197,13 +192,13 @@ func (evm *EVMExecutor) GetMessage(tx *types.Transaction) (msg *common.Message, ...@@ -197,13 +192,13 @@ func (evm *EVMExecutor) GetMessage(tx *types.Transaction) (msg *common.Message,
} }
// 合约的GasLimit即为调用者为本次合约调用准备支付的手续费 // 合约的GasLimit即为调用者为本次合约调用准备支付的手续费
msg = common.NewMessage(from, to, tx.Nonce, amount, gasLimit, gasPrice, code, action.GetAlias(), action.Note) msg = common.NewMessage(from, to, tx.Nonce, action.Amount, gasLimit, gasPrice, action.Code, action.GetAlias(), action.Abi)
return msg, nil return msg, err
} }
func (evm *EVMExecutor) collectEvmTxLog(tx *types.Transaction, cr *evmtypes.ReceiptEVMContract, receipt *types.Receipt) { func (evm *EVMExecutor) collectEvmTxLog(txHash []byte, cr *evmtypes.ReceiptEVMContract, receipt *types.Receipt) {
log.Debug("evm collect begin") log.Debug("evm collect begin")
log.Debug("Tx info", "txHash", common.Bytes2Hex(tx.Hash()), "height", evm.GetHeight()) log.Debug("Tx info", "txHash", common.Bytes2Hex(txHash), "height", evm.GetHeight())
log.Debug("ReceiptEVMContract", "data", fmt.Sprintf("caller=%v, name=%v, addr=%v, usedGas=%v, ret=%v", cr.Caller, cr.ContractName, cr.ContractAddr, cr.UsedGas, common.Bytes2Hex(cr.Ret))) log.Debug("ReceiptEVMContract", "data", fmt.Sprintf("caller=%v, name=%v, addr=%v, usedGas=%v, ret=%v", cr.Caller, cr.ContractName, cr.ContractAddr, cr.UsedGas, common.Bytes2Hex(cr.Ret)))
log.Debug("receipt data", "type", receipt.Ty) log.Debug("receipt data", "type", receipt.Ty)
for _, kv := range receipt.KV { for _, kv := range receipt.KV {
...@@ -232,18 +227,10 @@ func (evm *EVMExecutor) calcKVHash(addr common.Address, logs []*types.ReceiptLog ...@@ -232,18 +227,10 @@ func (evm *EVMExecutor) calcKVHash(addr common.Address, logs []*types.ReceiptLog
return nil return nil
} }
func (evm *EVMExecutor) getABIKV(addr common.Address, data string) (kv *types.KeyValue) {
return &types.KeyValue{Key: getABIKey(addr), Value: []byte(data)}
}
func getDataHashKey(addr common.Address) []byte { func getDataHashKey(addr common.Address) []byte {
return []byte(fmt.Sprintf("mavl-%v-data-hash:%v", evmtypes.ExecutorName, addr)) return []byte(fmt.Sprintf("mavl-%v-data-hash:%v", evmtypes.ExecutorName, addr))
} }
func getABIKey(addr common.Address) []byte {
return []byte(fmt.Sprintf("mavl-%v-data-abi:%v", evmtypes.ExecutorName, addr))
}
// 从交易信息中获取交易发起人地址 // 从交易信息中获取交易发起人地址
func getCaller(tx *types.Transaction) common.Address { func getCaller(tx *types.Transaction) common.Address {
return *common.StringToAddress(tx.From()) return *common.StringToAddress(tx.From())
......
...@@ -12,9 +12,8 @@ import ( ...@@ -12,9 +12,8 @@ import (
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common" "github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/model" "github.com/33cn/plugin/plugin/dapp/evm/executor/vm/model"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/runtime"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/state"
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types" evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
"github.com/kataras/iris/core/errors"
) )
// Query_CheckAddrExists 检查合约地址是否存在,此操作不会改变任何状态,所以可以直接从statedb查询 // Query_CheckAddrExists 检查合约地址是否存在,此操作不会改变任何状态,所以可以直接从statedb查询
...@@ -56,7 +55,6 @@ func (evm *EVMExecutor) Query_EstimateGas(in *evmtypes.EstimateEVMGasReq) (types ...@@ -56,7 +55,6 @@ func (evm *EVMExecutor) Query_EstimateGas(in *evmtypes.EstimateEVMGasReq) (types
evm.CheckInit() evm.CheckInit()
var ( var (
caller common.Address caller common.Address
to *common.Address
) )
// 如果未指定调用地址,则直接使用一个虚拟的地址发起调用 // 如果未指定调用地址,则直接使用一个虚拟的地址发起调用
...@@ -69,35 +67,36 @@ func (evm *EVMExecutor) Query_EstimateGas(in *evmtypes.EstimateEVMGasReq) (types ...@@ -69,35 +67,36 @@ func (evm *EVMExecutor) Query_EstimateGas(in *evmtypes.EstimateEVMGasReq) (types
caller = common.ExecAddress(types.ExecName(evmtypes.ExecutorName)) caller = common.ExecAddress(types.ExecName(evmtypes.ExecutorName))
} }
isCreate := strings.EqualFold(in.To, EvmAddress) msg := common.NewMessage(caller, nil, 0, in.Amount, evmtypes.MaxGasLimit, 1, in.Code, "estimateGas", in.Abi)
txHash := common.BigToHash(big.NewInt(evmtypes.MaxGasLimit)).Bytes()
msg := common.NewMessage(caller, nil, 0, in.Amount, evmtypes.MaxGasLimit, 1, in.Code, "estimateGas","") receipt, err := evm.innerExec(msg, txHash, 1, evmtypes.MaxGasLimit, false)
context := evm.NewEVMContext(msg) if err != nil {
// 创建EVM运行时对象 return nil, err
evm.mStateDB = state.NewMemoryStateDB(evm.GetStateDB(), evm.GetLocalDB(), evm.GetCoinsAccount(), evm.GetHeight()) }
env := runtime.NewEVM(context, evm.mStateDB, *evm.vmCfg)
evm.mStateDB.Prepare(common.BigToHash(big.NewInt(evmtypes.MaxGasLimit)), 0)
var (
vmerr error
leftOverGas uint64
contractAddr common.Address
execName string
)
if isCreate { if receipt.Ty == types.ExecOk {
txHash := common.BigToHash(big.NewInt(evmtypes.MaxGasLimit)).Bytes() callData := getCallReceipt(receipt.GetLogs())
contractAddr = evm.getNewAddr(txHash) if callData != nil {
execName = fmt.Sprintf("%s%s", types.ExecName(evmtypes.EvmPrefix), common.BytesToHash(txHash).Hex()) result := &evmtypes.EstimateEVMGasResp{}
_, _, leftOverGas, vmerr = env.Create(runtime.AccountRef(msg.From()), contractAddr, msg.Data(), context.GasLimit, execName, "estimateGas") result.Gas = callData.UsedGas
} else { return result, nil
to = common.StringToAddress(in.To) }
_, _, leftOverGas, vmerr = env.Call(runtime.AccountRef(msg.From()), *to, msg.Data(), context.GasLimit, msg.Value())
} }
return nil, errors.New("contract call error")
}
result := &evmtypes.EstimateEVMGasResp{} // 从日志中查找调用结果
result.Gas = evmtypes.MaxGasLimit - leftOverGas func getCallReceipt(logs []*types.ReceiptLog) (res *evmtypes.ReceiptEVMContract) {
return result, vmerr if len(logs) == 0 {
return res
}
for _, v := range logs {
if v.Ty == evmtypes.TyLogCallContract {
types.Decode(v.Log, res)
}
}
return res
} }
// Query_EvmDebug 此方法用来估算合约消耗的Gas,不能修改原有执行器的状态数据 // Query_EvmDebug 此方法用来估算合约消耗的Gas,不能修改原有执行器的状态数据
...@@ -113,3 +112,65 @@ func (evm *EVMExecutor) Query_EvmDebug(in *evmtypes.EvmDebugReq) (types.Message, ...@@ -113,3 +112,65 @@ func (evm *EVMExecutor) Query_EvmDebug(in *evmtypes.EvmDebugReq) (types.Message,
ret := &evmtypes.EvmDebugResp{DebugStatus: fmt.Sprintf("%v", evmDebug)} ret := &evmtypes.EvmDebugResp{DebugStatus: fmt.Sprintf("%v", evmDebug)}
return ret, nil return ret, nil
} }
// Query_Query 此方法用来调用合约的只读接口,不修改原有执行器的状态数据
func (evm *EVMExecutor) Query_Query(in *evmtypes.EvmQueryReq) (types.Message, error) {
evm.CheckInit()
ret := &evmtypes.EvmQueryResp{}
ret.Address = in.Address
ret.Input = in.Input
ret.Caller = in.Caller
var (
caller common.Address
)
to := common.StringToAddress(in.Address)
if to == nil {
ret.JsonData = fmt.Sprintf("invalid address:%v", in.Address)
return ret, nil
}
// 如果未指定调用地址,则直接使用一个虚拟的地址发起调用
if len(in.Caller) > 0 {
callAddr := common.StringToAddress(in.Caller)
if callAddr != nil {
caller = *callAddr
}
} else {
caller = common.ExecAddress(types.ExecName(evmtypes.ExecutorName))
}
msg := common.NewMessage(caller, common.StringToAddress(in.Address), 0, 0, evmtypes.MaxGasLimit, 1, nil, "estimateGas", in.Input)
txHash := common.BigToHash(big.NewInt(evmtypes.MaxGasLimit)).Bytes()
receipt, err := evm.innerExec(msg, txHash, 1, evmtypes.MaxGasLimit, true)
if err != nil {
ret.JsonData = fmt.Sprintf("%v", err)
return ret, nil
}
if receipt.Ty == types.ExecOk {
callData := getCallReceipt(receipt.GetLogs())
if callData != nil {
ret.RawData = callData.Ret
ret.JsonData = callData.JsonRet
return ret, nil
}
}
return ret, nil
}
// Query_QueryABI 此方法用来查询合约绑定的ABI数据,不修改原有执行器的状态数据
func (evm *EVMExecutor) Query_QueryABI(in *evmtypes.EvmQueryAbiReq) (types.Message, error) {
evm.CheckInit()
addr := common.StringToAddress(in.GetAddress())
if addr == nil {
return nil, fmt.Errorf("invalid address: %v", in.GetAddress())
}
abiData := evm.mStateDB.GetAbi(addr.String())
return &evmtypes.EvmQueryAbiResp{Address: in.GetAddress(), Abi: abiData}, nil
}
...@@ -137,7 +137,7 @@ func runCase(tt *testing.T, c VMCase, file string) { ...@@ -137,7 +137,7 @@ func runCase(tt *testing.T, c VMCase, file string) {
ret, _, _, err = env.Call(runtime.AccountRef(msg.From()), *common.StringToAddress(c.exec.address), msg.Data(), msg.GasLimit(), msg.Value()) ret, _, _, err = env.Call(runtime.AccountRef(msg.From()), *common.StringToAddress(c.exec.address), msg.Data(), msg.GasLimit(), msg.Value())
} else { } else {
addr := crypto.RandomContractAddress() addr := crypto.RandomContractAddress()
ret, _, _, err = env.Create(runtime.AccountRef(msg.From()), *addr, msg.Data(), msg.GasLimit(), "testExecName", "") ret, _, _, err = env.Create(runtime.AccountRef(msg.From()), *addr, msg.Data(), msg.GasLimit(), "testExecName", "", "")
} }
if err != nil { if err != nil {
...@@ -200,5 +200,5 @@ func buildMsg(c VMCase) *common.Message { ...@@ -200,5 +200,5 @@ func buildMsg(c VMCase) *common.Message {
addr2 := common.StringToAddress(c.exec.address) addr2 := common.StringToAddress(c.exec.address)
gasLimit := uint64(210000000) gasLimit := uint64(210000000)
gasPrice := c.exec.gasPrice gasPrice := c.exec.gasPrice
return common.NewMessage(*addr1, addr2, int64(1), uint64(c.exec.value), gasLimit, uint32(gasPrice), code, "") return common.NewMessage(*addr1, addr2, int64(1), uint64(c.exec.value), gasLimit, uint32(gasPrice), code, "", "")
} }
...@@ -271,7 +271,7 @@ func createContract(mdb *db.GoMemDB, tx types.Transaction, maxCodeSize int) (ret ...@@ -271,7 +271,7 @@ func createContract(mdb *db.GoMemDB, tx types.Transaction, maxCodeSize int) (ret
} }
addr := *crypto2.RandomContractAddress() addr := *crypto2.RandomContractAddress()
ret, _, leftGas, err := env.Create(runtime.AccountRef(msg.From()), addr, msg.Data(), msg.GasLimit(), fmt.Sprintf("%s%s", evmtypes.EvmPrefix, common.BytesToHash(tx.Hash()).Hex()), "") ret, _, leftGas, err := env.Create(runtime.AccountRef(msg.From()), addr, msg.Data(), msg.GasLimit(), fmt.Sprintf("%s%s", evmtypes.EvmPrefix, common.BytesToHash(tx.Hash()).Hex()), "", "")
return ret, addr, leftGas, statedb, err return ret, addr, leftGas, statedb, err
} }
...@@ -7,11 +7,12 @@ package common ...@@ -7,11 +7,12 @@ package common
import ( import (
"math/big" "math/big"
"encoding/hex"
"github.com/33cn/chain33/common/address" "github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/common/crypto/sha3"
"github.com/33cn/chain33/common/log/log15" "github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
"encoding/hex"
"github.com/33cn/chain33/common/crypto/sha3"
) )
// Address 封装地址结构体,并提供各种常用操作封装 // Address 封装地址结构体,并提供各种常用操作封装
...@@ -116,14 +117,6 @@ func BytesToHash160Address(b []byte) Hash160Address { ...@@ -116,14 +117,6 @@ func BytesToHash160Address(b []byte) Hash160Address {
return h return h
} }
// BytesToAddress 字节向地址转换
func Hash160ToAddress(h Hash160Address) Address {
a := new(address.Address)
a.Version = 0
a.Hash160 = copyBytes(h[:])
return Address{addr: a}
}
// StringToAddress 字符串转换为地址 // StringToAddress 字符串转换为地址
func StringToAddress(s string) *Address { func StringToAddress(s string) *Address {
addr, err := address.NewAddrFromString(s) addr, err := address.NewAddrFromString(s)
......
...@@ -69,8 +69,7 @@ func Keccak256(data ...[]byte) []byte { ...@@ -69,8 +69,7 @@ func Keccak256(data ...[]byte) []byte {
return d.Sum(nil) return d.Sum(nil)
} }
// Keccak256Hash calculates and returns the Keccak256 hash of the input data,
// NewKeccak256Hash calculates and returns the Keccak256 hash of the input data,
// converting it to an internal Hash data structure. // converting it to an internal Hash data structure.
func Keccak256Hash(data ...[]byte) (h common.Hash) { func Keccak256Hash(data ...[]byte) (h common.Hash) {
d := sha3.NewLegacyKeccak256() d := sha3.NewLegacyKeccak256()
...@@ -79,4 +78,4 @@ func Keccak256Hash(data ...[]byte) (h common.Hash) { ...@@ -79,4 +78,4 @@ func Keccak256Hash(data ...[]byte) (h common.Hash) {
} }
d.Sum(h[:0]) d.Sum(h[:0])
return h return h
} }
\ No newline at end of file
...@@ -356,7 +356,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte ...@@ -356,7 +356,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
// 使用传入的部署代码创建新的合约; // 使用传入的部署代码创建新的合约;
// 目前chain33为了保证账户安全,不允许合约中涉及到外部账户的转账操作, // 目前chain33为了保证账户安全,不允许合约中涉及到外部账户的转账操作,
// 所以,本步骤不接收转账金额参数 // 所以,本步骤不接收转账金额参数
func (evm *EVM) Create(caller ContractRef, contractAddr common.Address, code []byte, gas uint64, execName, alias string) (ret []byte, snapshot int, leftOverGas uint64, err error) { func (evm *EVM) Create(caller ContractRef, contractAddr common.Address, code []byte, gas uint64, execName, alias, abi string) (ret []byte, snapshot int, leftOverGas uint64, err error) {
pass, err := evm.preCheck(caller, contractAddr, 0) pass, err := evm.preCheck(caller, contractAddr, 0)
if !pass { if !pass {
return nil, -1, gas, err return nil, -1, gas, err
...@@ -386,6 +386,10 @@ func (evm *EVM) Create(caller ContractRef, contractAddr common.Address, code []b ...@@ -386,6 +386,10 @@ func (evm *EVM) Create(caller ContractRef, contractAddr common.Address, code []b
createDataGas := uint64(len(ret)) * params.CreateDataGas createDataGas := uint64(len(ret)) * params.CreateDataGas
if contract.UseGas(createDataGas) { if contract.UseGas(createDataGas) {
evm.StateDB.SetCode(contractAddr.String(), ret) evm.StateDB.SetCode(contractAddr.String(), ret)
// 设置 ABI (如果有的话),这个动作不单独计费
if len(abi) > 0 && types.IsDappFork(evm.StateDB.GetBlockHeight(), "evm", "ForkEVMKVHash") {
evm.StateDB.SetAbi(contractAddr.String(), abi)
}
} else { } else {
// 如果Gas不足,返回这个错误,让外部程序处理 // 如果Gas不足,返回这个错误,让外部程序处理
err = model.ErrCodeStoreOutOfGas err = model.ErrCodeStoreOutOfGas
......
...@@ -717,7 +717,7 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack ...@@ -717,7 +717,7 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *mm.Memory, stack
// 调用合约创建逻辑 // 调用合约创建逻辑
addr := crypto.RandomContractAddress() addr := crypto.RandomContractAddress()
res, _, returnGas, suberr := evm.Create(contract, *addr, inPut, gas, "innerContract", "") res, _, returnGas, suberr := evm.Create(contract, *addr, inPut, gas, "innerContract", "", "")
// 出错时压栈0,否则压栈创建出来的合约对象的地址 // 出错时压栈0,否则压栈创建出来的合约对象的地址
if suberr != nil && suberr != model.ErrCodeStoreOutOfGas { if suberr != nil && suberr != model.ErrCodeStoreOutOfGas {
......
...@@ -165,6 +165,14 @@ func (ca *ContractAccount) LoadContract(db db.KV) { ...@@ -165,6 +165,14 @@ func (ca *ContractAccount) LoadContract(db db.KV) {
return return
} }
ca.resotreState(data) ca.resotreState(data)
// 加载 ABI (如果有的话)
if types.IsDappFork(ca.mdb.GetBlockHeight(), "evm", "ForkEVMABI") {
data, err := db.Get(ca.GetAbiKey())
if err == nil {
ca.Data.Abi = string(data)
}
}
} }
// SetCode 设置合约二进制代码 // SetCode 设置合约二进制代码
...@@ -181,6 +189,18 @@ func (ca *ContractAccount) SetCode(code []byte) { ...@@ -181,6 +189,18 @@ func (ca *ContractAccount) SetCode(code []byte) {
ca.Data.CodeHash = common.ToHash(code).Bytes() ca.Data.CodeHash = common.ToHash(code).Bytes()
} }
// SetAbi 设置合约绑定的ABI数据
func (ca *ContractAccount) SetAbi(abi string) {
if types.IsDappFork(ca.mdb.GetBlockHeight(), "evm", "ForkEVMABI") {
ca.mdb.addChange(abiChange{
baseChange: baseChange{},
account: ca.Addr,
prevabi: ca.Data.Abi,
})
ca.Data.Abi = abi
}
}
// SetCreator 设置创建者 // SetCreator 设置创建者
func (ca *ContractAccount) SetCreator(creator string) { func (ca *ContractAccount) SetCreator(creator string) {
if len(creator) == 0 { if len(creator) == 0 {
...@@ -272,6 +292,11 @@ func (ca *ContractAccount) GetDataKey() []byte { ...@@ -272,6 +292,11 @@ func (ca *ContractAccount) GetDataKey() []byte {
return []byte("mavl-" + evmtypes.ExecutorName + "-data: " + ca.Addr) return []byte("mavl-" + evmtypes.ExecutorName + "-data: " + ca.Addr)
} }
// GetAbiKey 获取Abi数据KEY,ABI数据使用单独的KEY存储
func (ca *ContractAccount) GetAbiKey() []byte {
return []byte("mavl-" + evmtypes.ExecutorName + "-abi: " + ca.Addr)
}
// GetStateKey 获取状态key // GetStateKey 获取状态key
func (ca *ContractAccount) GetStateKey() []byte { func (ca *ContractAccount) GetStateKey() []byte {
return []byte("mavl-" + evmtypes.ExecutorName + "-state: " + ca.Addr) return []byte("mavl-" + evmtypes.ExecutorName + "-state: " + ca.Addr)
......
...@@ -37,6 +37,10 @@ type EVMStateDB interface { ...@@ -37,6 +37,10 @@ type EVMStateDB interface {
SetCode(string, []byte) SetCode(string, []byte)
// GetCodeSize 获取指定地址合约代码大小 // GetCodeSize 获取指定地址合约代码大小
GetCodeSize(string) int GetCodeSize(string) int
// SetAbi 设置ABI内容
SetAbi(addr, abi string)
// GetAbi 获取ABI
GetAbi(addr string) string
// AddRefund 合约Gas奖励回馈 // AddRefund 合约Gas奖励回馈
AddRefund(uint64) AddRefund(uint64)
...@@ -74,4 +78,7 @@ type EVMStateDB interface { ...@@ -74,4 +78,7 @@ type EVMStateDB interface {
CanTransfer(sender, recipient string, amount uint64) bool CanTransfer(sender, recipient string, amount uint64) bool
// Transfer 转账交易 // Transfer 转账交易
Transfer(sender, recipient string, amount uint64) bool Transfer(sender, recipient string, amount uint64) bool
// GetBlockHeight 返回当前区块高度
GetBlockHeight() int64
} }
...@@ -123,6 +123,13 @@ type ( ...@@ -123,6 +123,13 @@ type (
prevcode, prevhash []byte prevcode, prevhash []byte
} }
// 合约ABI变更事件
abiChange struct {
baseChange
account string
prevabi string
}
// 返还金额变更事件 // 返还金额变更事件
refundChange struct { refundChange struct {
baseChange baseChange
...@@ -236,6 +243,22 @@ func (ch codeChange) getData(mdb *MemoryStateDB) (kvset []*types.KeyValue) { ...@@ -236,6 +243,22 @@ func (ch codeChange) getData(mdb *MemoryStateDB) (kvset []*types.KeyValue) {
return nil return nil
} }
func (ch abiChange) revert(mdb *MemoryStateDB) {
acc := mdb.accounts[ch.account]
if acc != nil {
acc.Data.Abi = ch.prevabi
}
}
func (ch abiChange) getData(mdb *MemoryStateDB) (kvset []*types.KeyValue) {
acc := mdb.accounts[ch.account]
if acc != nil {
kvset = append(kvset, acc.GetDataKV()...)
return kvset
}
return nil
}
func (ch storageChange) revert(mdb *MemoryStateDB) { func (ch storageChange) revert(mdb *MemoryStateDB) {
acc := mdb.accounts[ch.account] acc := mdb.accounts[ch.account]
if acc != nil { if acc != nil {
......
...@@ -193,6 +193,24 @@ func (mdb *MemoryStateDB) SetCode(addr string, code []byte) { ...@@ -193,6 +193,24 @@ func (mdb *MemoryStateDB) SetCode(addr string, code []byte) {
} }
} }
// SetAbi 设置ABI内容
func (mdb *MemoryStateDB) SetAbi(addr, abi string) {
acc := mdb.GetAccount(addr)
if acc != nil {
mdb.dataDirty[addr] = true
acc.SetAbi(abi)
}
}
// GetAbi 获取ABI
func (mdb *MemoryStateDB) GetAbi(addr string) string {
acc := mdb.GetAccount(addr)
if acc != nil {
return acc.Data.GetAbi()
}
return ""
}
// GetCodeSize 获取合约代码自身的大小 // GetCodeSize 获取合约代码自身的大小
// 对应 EXTCODESIZE 操作码 // 对应 EXTCODESIZE 操作码
func (mdb *MemoryStateDB) GetCodeSize(addr string) int { func (mdb *MemoryStateDB) GetCodeSize(addr string) int {
...@@ -686,3 +704,8 @@ func (mdb *MemoryStateDB) ResetDatas() { ...@@ -686,3 +704,8 @@ func (mdb *MemoryStateDB) ResetDatas() {
mdb.currentVer = nil mdb.currentVer = nil
mdb.snapshots = mdb.snapshots[:0] mdb.snapshots = mdb.snapshots[:0]
} }
// GetBlockHeight 返回当前区块高度
func (mdb *MemoryStateDB) GetBlockHeight() int64 {
return mdb.blockHeight
}
...@@ -17,6 +17,8 @@ message EVMContractData { ...@@ -17,6 +17,8 @@ message EVMContractData {
string addr = 4; string addr = 4;
bytes code = 5; bytes code = 5;
bytes codeHash = 6; bytes codeHash = 6;
// 绑定ABI数据 ForkEVMABI
string abi = 7;
} }
// 存放合约变化数据 // 存放合约变化数据
...@@ -41,6 +43,8 @@ message EVMContractAction { ...@@ -41,6 +43,8 @@ message EVMContractAction {
string alias = 5; string alias = 5;
// 交易备注 // 交易备注
string note = 6; string note = 6;
// 创建或调用合约时携带的ABI数据 ForkEVMABI
string abi = 7;
} }
// 合约创建/调用日志 // 合约创建/调用日志
...@@ -51,6 +55,8 @@ message ReceiptEVMContract { ...@@ -51,6 +55,8 @@ message ReceiptEVMContract {
uint64 usedGas = 4; uint64 usedGas = 4;
// 创建合约返回的代码 // 创建合约返回的代码
bytes ret = 5; bytes ret = 5;
// json格式化后的返回值
string jsonRet = 6;
} }
// 用于保存EVM只能合约中的状态数据变更 // 用于保存EVM只能合约中的状态数据变更
...@@ -104,6 +110,7 @@ message EstimateEVMGasReq { ...@@ -104,6 +110,7 @@ message EstimateEVMGasReq {
bytes code = 2; bytes code = 2;
string caller = 3; string caller = 3;
uint64 amount = 4; uint64 amount = 4;
string abi = 5;
} }
message EstimateEVMGasResp { message EstimateEVMGasResp {
uint64 gas = 1; uint64 gas = 1;
...@@ -116,4 +123,27 @@ message EvmDebugReq { ...@@ -116,4 +123,27 @@ message EvmDebugReq {
message EvmDebugResp { message EvmDebugResp {
string debugStatus = 1; string debugStatus = 1;
}
message EvmQueryAbiReq {
string address = 1;
}
message EvmQueryAbiResp {
string address = 1;
string abi = 2;
}
message EvmQueryReq {
string address = 1;
string input = 2;
string caller = 3;
}
message EvmQueryResp {
string address = 1;
string input = 2;
string caller = 3;
bytes rawData = 4;
string jsonData = 5;
} }
\ No newline at end of file
...@@ -12,7 +12,6 @@ import ( ...@@ -12,7 +12,6 @@ import (
"github.com/33cn/chain33/common/address" "github.com/33cn/chain33/common/address"
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"
ecommon "github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
) )
var ( var (
...@@ -22,8 +21,6 @@ var ( ...@@ -22,8 +21,6 @@ var (
"EvmCreate": EvmCreateAction, "EvmCreate": EvmCreateAction,
"EvmCall": EvmCallAction, "EvmCall": EvmCallAction,
} }
ABICallPrefix = ecommon.FromHex("0x00000000")
) )
func init() { func init() {
...@@ -102,23 +99,6 @@ func (evm EvmType) CreateTx(action string, message json.RawMessage) (*types.Tran ...@@ -102,23 +99,6 @@ func (evm EvmType) CreateTx(action string, message json.RawMessage) (*types.Tran
} }
return createEvmTx(&param) return createEvmTx(&param)
} }
//else if action == "BindABI" {
// var param BindABI
// err := json.Unmarshal(message, &param)
// if err != nil {
// elog.Error("Create BindABI", "Error", err)
// return nil, types.ErrInvalidParam
// }
// return createBindABITx(&param)
//} else if action == "ABICall" {
// var param ABICall
// err := json.Unmarshal(message, &param)
// if err != nil {
// elog.Error("Create ABICall", "Error", err)
// return nil, types.ErrInvalidParam
// }
// return createABICallTx(&param)
//}
return nil, types.ErrNotSupport return nil, types.ErrNotSupport
} }
...@@ -127,64 +107,6 @@ func (evm *EvmType) GetLogMap() map[int64]*types.LogInfo { ...@@ -127,64 +107,6 @@ func (evm *EvmType) GetLogMap() map[int64]*types.LogInfo {
return logInfo return logInfo
} }
//func createBindABITx(param *BindABI) (*types.Transaction, error) {
// if param == nil {
// elog.Error("createBindABITx", "param", param)
// return nil, types.ErrInvalidParam
// }
//
// code := []byte(param.Data)
// code = append(BindABIPrefix, code...)
//
// action := &EVMContractAction{
// Code: code,
// Note: param.Note,
// }
//
// return createRawTx(action, param.Name)
//}
//
//func createABICallTx(param *ABICall) (*types.Transaction, error) {
// if param == nil {
// elog.Error("createABICallTx", "param", param)
// return nil, types.ErrInvalidParam
// }
//
// code := []byte(param.Data)
// code = append(ABICallPrefix, code...)
//
// action := &EVMContractAction{
// Code: code,
// Amount: param.Amount,
// }
//
// return createRawTx(action, param.Name)
//
// return nil, nil
//}
func createRawTx(action *EVMContractAction, name string) (*types.Transaction, error) {
tx := &types.Transaction{}
if len(name) == 0 {
tx = &types.Transaction{
Execer: []byte(types.ExecName(ExecutorName)),
Payload: types.Encode(action),
To: address.ExecAddress(types.ExecName(ExecutorName)),
}
} else {
tx = &types.Transaction{
Execer: []byte(types.ExecName(name)),
Payload: types.Encode(action),
To: address.ExecAddress(types.ExecName(name)),
}
}
tx, err := types.FormatTx(string(tx.Execer), tx)
if err != nil {
return nil, err
}
return tx, nil
}
func createEvmTx(param *CreateCallTx) (*types.Transaction, error) { func createEvmTx(param *CreateCallTx) (*types.Transaction, error) {
if param == nil { if param == nil {
elog.Error("createEvmTx", "param", param) elog.Error("createEvmTx", "param", param)
...@@ -194,7 +116,6 @@ func createEvmTx(param *CreateCallTx) (*types.Transaction, error) { ...@@ -194,7 +116,6 @@ func createEvmTx(param *CreateCallTx) (*types.Transaction, error) {
// 调用格式判断规则: // 调用格式判断规则:
// 十六进制格式默认使用原方式调用,其它格式,使用ABI方式调用 // 十六进制格式默认使用原方式调用,其它格式,使用ABI方式调用
// 为了方便区分,在ABI格式前加0x00000000 // 为了方便区分,在ABI格式前加0x00000000
bCode, err := common.FromHex(param.Code)
action := &EVMContractAction{ action := &EVMContractAction{
Amount: param.Amount, Amount: param.Amount,
...@@ -203,20 +124,42 @@ func createEvmTx(param *CreateCallTx) (*types.Transaction, error) { ...@@ -203,20 +124,42 @@ func createEvmTx(param *CreateCallTx) (*types.Transaction, error) {
Note: param.Note, Note: param.Note,
Alias: param.Alias, Alias: param.Alias,
} }
// Abi数据和二进制代码必须指定一个,优先判断ABI
if param.IsCreate { if len(param.Abi) > 0 {
action.Abi = strings.TrimSpace(param.Abi)
} else {
bCode, err := common.FromHex(param.Code)
if err != nil { if err != nil {
elog.Error("create evm create Tx", "param.Code", param.Code) elog.Error("create evm Tx error, code is invalid", "param.Code", param.Code)
return nil, err return nil, err
} }
action.Code = bCode action.Code = bCode
}
if param.IsCreate {
return createRawTx(action, "") return createRawTx(action, "")
}
return createRawTx(action, param.Name)
}
func createRawTx(action *EVMContractAction, name string) (*types.Transaction, error) {
tx := &types.Transaction{}
if len(name) == 0 {
tx = &types.Transaction{
Execer: []byte(types.ExecName(ExecutorName)),
Payload: types.Encode(action),
To: address.ExecAddress(types.ExecName(ExecutorName)),
}
} else { } else {
if err != nil { tx = &types.Transaction{
elog.Info("evm call data is invalid hex data, process it as abi data", "param.Code", param.Code) Execer: []byte(types.ExecName(name)),
bCode = []byte(param.Code) Payload: types.Encode(action),
bCode = append(ABICallPrefix, bCode...) To: address.ExecAddress(types.ExecName(name)),
} }
return createRawTx(action, param.Name)
} }
tx, err := types.FormatTx(string(tx.Execer), tx)
if err != nil {
return nil, err
}
return tx, nil
} }
This diff is collapsed.
...@@ -24,4 +24,6 @@ type CreateCallTx struct { ...@@ -24,4 +24,6 @@ type CreateCallTx struct {
Name string `json:"name"` Name string `json:"name"`
// IsCreate 是否创建合约 // IsCreate 是否创建合约
IsCreate bool `json:"isCreate"` IsCreate bool `json:"isCreate"`
// Abi 创建合约或调用合约时附带的ABI数据
Abi string `json:"abi"`
} }
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