Commit 781721f6 authored by Litian's avatar Litian

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

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