Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
plugin
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
link33
plugin
Commits
781721f6
Commit
781721f6
authored
Nov 26, 2018
by
Litian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
evm 支持abi代码逻辑基本完成
parent
d33e674d
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
444 additions
and
327 deletions
+444
-327
raft.go
plugin/consensus/raft/raft.go
+1
-1
scp.go
plugin/consensus/raft/tools/scripts/go-scp/scp.go
+1
-1
abi.go
plugin/dapp/evm/executor/abi/abi.go
+5
-5
abi_test.go
plugin/dapp/evm/executor/abi/abi_test.go
+0
-0
api.go
plugin/dapp/evm/executor/abi/api.go
+32
-15
api_test.go
plugin/dapp/evm/executor/abi/api_test.go
+4
-3
argument.go
plugin/dapp/evm/executor/abi/argument.go
+6
-5
error.go
plugin/dapp/evm/executor/abi/error.go
+2
-2
event.go
plugin/dapp/evm/executor/abi/event.go
+2
-2
event_test.go
plugin/dapp/evm/executor/abi/event_test.go
+31
-31
method.go
plugin/dapp/evm/executor/abi/method.go
+2
-1
pack.go
plugin/dapp/evm/executor/abi/pack.go
+2
-2
pack_test.go
plugin/dapp/evm/executor/abi/pack_test.go
+9
-9
reflect.go
plugin/dapp/evm/executor/abi/reflect.go
+8
-8
type_test.go
plugin/dapp/evm/executor/abi/type_test.go
+9
-9
unpack.go
plugin/dapp/evm/executor/abi/unpack.go
+2
-2
unpack_test.go
plugin/dapp/evm/executor/abi/unpack_test.go
+35
-35
exec.go
plugin/dapp/evm/executor/exec.go
+49
-62
query.go
plugin/dapp/evm/executor/query.go
+89
-28
evm_test.go
plugin/dapp/evm/executor/tests/evm_test.go
+2
-2
util_test.go
plugin/dapp/evm/executor/tests/util_test.go
+1
-1
address.go
plugin/dapp/evm/executor/vm/common/address.go
+3
-10
crypto.go
plugin/dapp/evm/executor/vm/common/crypto/crypto.go
+2
-4
evm.go
plugin/dapp/evm/executor/vm/runtime/evm.go
+5
-1
instructions.go
plugin/dapp/evm/executor/vm/runtime/instructions.go
+1
-1
account.go
plugin/dapp/evm/executor/vm/state/account.go
+25
-0
interface.go
plugin/dapp/evm/executor/vm/state/interface.go
+7
-0
snapshot.go
plugin/dapp/evm/executor/vm/state/snapshot.go
+23
-0
statedb.go
plugin/dapp/evm/executor/vm/state/statedb.go
+23
-0
evmcontract.proto
plugin/dapp/evm/proto/evmcontract.proto
+31
-0
evm.go
plugin/dapp/evm/types/evm.go
+30
-87
evmcontract.pb.go
plugin/dapp/evm/types/evmcontract.pb.go
+0
-0
tx.go
plugin/dapp/evm/types/tx.go
+2
-0
No files found.
plugin/consensus/raft/raft.go
View file @
781721f6
...
...
@@ -294,7 +294,7 @@ func (rc *raftNode) updateValidator() {
rlog
.
Debug
(
fmt
.
Sprintf
(
"==============This is %s node!=============="
,
status
.
RaftState
.
String
()))
continue
}
else
{
// 获取到leader I
d
,选主成功
// 获取到leader I
D
,选主成功
if
rc
.
id
==
int
(
status
.
Lead
)
{
//leader选举出来之后即可添加addReadOnlyPeers
if
!
flag
&&
!
isRestart
{
...
...
plugin/consensus/raft/tools/scripts/go-scp/scp.go
View file @
781721f6
...
...
@@ -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("
I
D:/Repository/src/github.com/33cn/chain33/consensus/drivers/raft/tools/scripts")
//if e != nil {
// fmt.Println("read dir error")
// return
...
...
plugin/dapp/evm/executor/abi/abi.go
View file @
781721f6
...
...
@@ -44,7 +44,7 @@ func JSON(reader io.Reader) (ABI, error) {
return
abi
,
nil
}
// Pack the given method
N
ame to conform the ABI. Method call's data
// Pack the given method
n
ame 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
.
I
d
(),
arguments
...
),
nil
return
append
(
method
.
I
D
(),
arguments
...
),
nil
}
// Unpack output in v according to the abi specification
...
...
@@ -134,14 +134,14 @@ func (abi *ABI) UnmarshalJSON(data []byte) error {
return
nil
}
// MethodByI
d
looks up a method by the 4-byte id
// MethodByI
D
looks up a method by the 4-byte id
// returns nil if none found
func
(
abi
*
ABI
)
MethodByI
d
(
sigdata
[]
byte
)
(
*
Method
,
error
)
{
func
(
abi
*
ABI
)
MethodByI
D
(
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
.
I
d
(),
sigdata
[
:
4
])
{
if
bytes
.
Equal
(
method
.
I
D
(),
sigdata
[
:
4
])
{
return
&
method
,
nil
}
}
...
...
plugin/dapp/evm/executor/abi/abi_test.go
View file @
781721f6
This diff is collapsed.
Click to expand it.
plugin/dapp/evm/executor/abi/api.go
View file @
781721f6
...
...
@@ -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
}
// 本方法可以将一个表示数组的字符串,经过处理后,返回数组内的字面元素;
...
...
plugin/dapp/evm/executor/abi/api_test.go
View file @
781721f6
...
...
@@ -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
))
}
...
...
plugin/dapp/evm/executor/abi/argument.go
View file @
781721f6
...
...
@@ -23,7 +23,7 @@ import (
"strings"
)
// Argument holds the
N
ame of the argument and the corresponding type.
// Argument holds the
n
ame 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
V
alue is arguments pointer
// make sure the passed
v
alue 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
V
alue
// unpackAtomic unpacks ( hexdata -> go ) a single
v
alue
func
(
arguments
Arguments
)
unpackAtomic
(
v
interface
{},
marshalledValues
[]
interface
{})
error
{
if
len
(
marshalledValues
)
!=
1
{
return
fmt
.
Errorf
(
"abi: wrong length, expected single
V
alue, got %d"
,
len
(
marshalledValues
))
return
fmt
.
Errorf
(
"abi: wrong length, expected single
v
alue, 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
V
alue to the input
// append the packed
v
alue to the input
ret
=
append
(
ret
,
packed
...
)
}
}
...
...
plugin/dapp/evm/executor/abi/error.go
View file @
781721f6
...
...
@@ -23,7 +23,7 @@ import (
)
var
(
errBadBool
=
errors
.
New
(
"abi: improperly encoded boolean
V
alue"
)
errBadBool
=
errors
.
New
(
"abi: improperly encoded boolean
v
alue"
)
)
// 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
V
alue can be assigned to the reflection
// typeCheck checks that the given reflection
v
alue can be assigned to the reflection
// type in t.
func
typeCheck
(
t
Type
,
value
reflect
.
Value
)
error
{
if
t
.
T
==
SliceTy
||
t
.
T
==
ArrayTy
{
...
...
plugin/dapp/evm/executor/abi/event.go
View file @
781721f6
...
...
@@ -44,9 +44,9 @@ func (e Event) String() string {
return
fmt
.
Sprintf
(
"e %v(%v)"
,
e
.
Name
,
strings
.
Join
(
inputs
,
", "
))
}
// I
d
returns the canonical representation of the event's signature used by the
// I
D
returns the canonical representation of the event's signature used by the
// abi definition to identify event names and types.
func
(
e
Event
)
I
d
()
common
.
Hash
{
func
(
e
Event
)
I
D
()
common
.
Hash
{
types
:=
make
([]
string
,
len
(
e
.
Inputs
))
i
:=
0
for
_
,
input
:=
range
e
.
Inputs
{
...
...
plugin/dapp/evm/executor/abi/event_test.go
View file @
781721f6
...
...
@@ -35,39 +35,39 @@ var jsonEventTransfer = []byte(`{
"anonymous": false,
"inputs": [
{
"indexed": true, "
N
ame": "from", "type": "address"
"indexed": true, "
n
ame": "from", "type": "address"
}, {
"indexed": true, "
N
ame": "to", "type": "address"
"indexed": true, "
n
ame": "to", "type": "address"
}, {
"indexed": false, "
Name": "V
alue", "type": "uint256"
"indexed": false, "
name": "v
alue", "type": "uint256"
}],
"
N
ame": "Transfer",
"
n
ame": "Transfer",
"type": "event"
}`
)
var
jsonEventPledge
=
[]
byte
(
`{
"anonymous": false,
"inputs": [{
"indexed": false, "
N
ame": "who", "type": "address"
"indexed": false, "
n
ame": "who", "type": "address"
}, {
"indexed": false, "
N
ame": "wad", "type": "uint128"
"indexed": false, "
n
ame": "wad", "type": "uint128"
}, {
"indexed": false, "
N
ame": "currency", "type": "bytes3"
"indexed": false, "
n
ame": "currency", "type": "bytes3"
}],
"
N
ame": "Pledge",
"
n
ame": "Pledge",
"type": "event"
}`
)
var
jsonEventMixedCase
=
[]
byte
(
`{
"anonymous": false,
"inputs": [{
"indexed": false, "
Name": "V
alue", "type": "uint256"
"indexed": false, "
name": "v
alue", "type": "uint256"
}, {
"indexed": false, "
N
ame": "_value", "type": "uint256"
"indexed": false, "
n
ame": "_value", "type": "uint256"
}, {
"indexed": false, "
N
ame": "Value", "type": "uint256"
"indexed": false, "
n
ame": "Value", "type": "uint256"
}],
"
N
ame": "MixedCase",
"
n
ame": "MixedCase",
"type": "event"
}`
)
...
...
@@ -87,8 +87,8 @@ func TestEventId(t *testing.T) {
}{
{
definition
:
`[
{ "type" : "event", "
Name" : "balance", "inputs": [{ "N
ame" : "in", "type": "uint256" }] },
{ "type" : "event", "
Name" : "check", "inputs": [{ "Name" : "t", "type": "address" }, { "N
ame": "b", "type": "uint256" }] }
{ "type" : "event", "
name" : "balance", "inputs": [{ "n
ame" : "in", "type": "uint256" }] },
{ "type" : "event", "
name" : "check", "inputs": [{ "name" : "t", "type": "address" }, { "n
ame": "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
.
I
d
()
!=
test
.
expectations
[
name
]
{
t
.
Errorf
(
"expected id to be %x, got %x"
,
test
.
expectations
[
name
],
event
.
I
d
())
if
event
.
I
D
()
!=
test
.
expectations
[
name
]
{
t
.
Errorf
(
"expected id to be %x, got %x"
,
test
.
expectations
[
name
],
event
.
I
D
())
}
}
}
...
...
@@ -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, "N
ame":"value2", "type":"uint8"}]}]`
definition
:=
`[{"
name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "n
ame":"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 `
V
alue` is not exportable,
// so
V
alue is only unmarshalled into `Value1`.
// this is valid because `
v
alue` is not exportable,
// so
v
alue is only unmarshalled into `Value1`.
value
*
big
.
Int
Value1
*
big
.
Int
`abi:"
V
alue"`
Value1
*
big
.
Int
`abi:"
v
alue"`
}
type
BadEventTransferWithSameFieldAndTag
struct
{
Value
*
big
.
Int
Value1
*
big
.
Int
`abi:"
V
alue"`
Value1
*
big
.
Int
`abi:"
v
alue"`
}
type
BadEventTransferWithDuplicatedTag
struct
{
Value1
*
big
.
Int
`abi:"
V
alue"`
Value2
*
big
.
Int
`abi:"
V
alue"`
Value1
*
big
.
Int
`abi:"
v
alue"`
Value2
*
big
.
Int
`abi:"
v
alue"`
}
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:"
V
alue"`
Value1
*
big
.
Int
`abi:"
v
alue"`
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 '
V
alue'"
,
"abi: multiple variables maps to the same abi field '
v
alue'"
,
"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, "N
ame":"value2", "type":"uint8"}]}]`
definition
:=
`[{"
name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "n
ame":"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, "N
ame":"value2", "type":"string"}]}]`
definition
:=
`[{"
name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8[2]"},{"indexed": false, "n
ame":"value2", "type":"string"}]}]`
type
testStruct
struct
{
Value1
[
2
]
uint8
Value2
string
...
...
plugin/dapp/evm/executor/abi/method.go
View file @
781721f6
...
...
@@ -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
]
}
plugin/dapp/evm/executor/abi/pack.go
View file @
781721f6
...
...
@@ -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
V
alue according to the abi specification in
// packElement packs the given reflect
v
alue 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
V
alue) and will cast it to appropriate number representation
// packNum packs the given number (using the reflect
v
alue) 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
:
...
...
plugin/dapp/evm/executor/abi/pack_test.go
View file @
781721f6
...
...
@@ -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"
]
.
I
d
()
sig
:=
abi
.
Methods
[
"slice"
]
.
I
D
()
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"
]
.
I
d
()
var
addrA
,
addrB
=
common
.
Hash160Address
{
1
},
common
.
Hash160Address
{
2
}
sig
=
abi
.
Methods
[
"sliceAddress"
]
.
I
D
()
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"
]
.
I
d
()
var
addrC
,
addrD
=
common
.
Hash160Address
{
3
},
common
.
Hash160Address
{
4
}
sig
=
abi
.
Methods
[
"sliceMultiAddress"
]
.
I
D
()
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"
]
.
I
d
()
sig
=
abi
.
Methods
[
"slice256"
]
.
I
D
()
sig
=
append
(
sig
,
common
.
LeftPadBytes
([]
byte
{
1
},
32
)
...
)
sig
=
append
(
sig
,
common
.
LeftPadBytes
([]
byte
{
2
},
32
)
...
)
...
...
plugin/dapp/evm/executor/abi/reflect.go
View file @
781721f6
...
...
@@ -22,7 +22,7 @@ import (
"strings"
)
// indirect recursively dereferences the
Value until it either gets the V
alue
// indirect recursively dereferences the
value until it either gets the v
alue
// 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
V
alue
// and copies the bytes in
V
alue to the new slice.
// mustArrayToBytesSlice creates a new byte slice with the exact same size as
v
alue
// and copies the bytes in
v
alue 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
N
ame exists in the arguments, pair them together.
// and this field
n
ame 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
N
ame. If so, raise an error:
// abi: [ { "
Name": "V
alue" } ]
// struct { Value *big.Int , Value1 *big.Int `abi:"
V
alue"`}
// struct field with the same field
n
ame. If so, raise an error:
// abi: [ { "
name": "v
alue" } ]
// struct { Value *big.Int , Value1 *big.Int `abi:"
v
alue"`}
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" }, { "N
ame": "_value" } ]
// abi : [ { "
name": "value" }, { "n
ame": "_value" } ]
// struct { Value *big.Int }
struct2abi
[
structFieldName
]
=
abiFieldName
}
...
...
plugin/dapp/evm/executor/abi/type_test.go
View file @
781721f6
...
...
@@ -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:
\n
GOT %s
\n
WANT %s "
,
tt
.
blob
,
typ
eWithoutStringer
(
typ
),
typeWithoutStringer
(
tt
.
kind
)
)
t
.
Errorf
(
"type %q: parsed type mismatch:
\n
GOT %s
\n
WANT %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"
},
...
...
plugin/dapp/evm/executor/abi/unpack.go
View file @
781721f6
...
...
@@ -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
V
alue will become our slice or our array, depending on the type
// this
v
alue 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
V
alue of these bytes
// toGoType parses the output bytes and recursively assigns the
v
alue 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
)
{
...
...
plugin/dapp/evm/executor/abi/unpack_test.go
View file @
781721f6
This diff is collapsed.
Click to expand it.
plugin/dapp/evm/executor/exec.go
View file @
781721f6
...
...
@@ -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
(
tx
Hash
)
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
(
tx
Hash
)
.
Hex
())
}
else
{
contractAddr
=
*
msg
.
To
()
}
// 状态机中设置当前交易状态
evm
.
mStateDB
.
Prepare
(
common
.
BytesToHash
(
tx
.
Hash
()
),
index
)
evm
.
mStateDB
.
Prepare
(
common
.
BytesToHash
(
tx
Hash
),
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
,
a
mount
,
gasLimit
,
gasPrice
,
code
,
action
.
GetAlias
(),
action
.
Note
)
return
msg
,
nil
msg
=
common
.
NewMessage
(
from
,
to
,
tx
.
Nonce
,
a
ction
.
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
(
tx
Hash
[]
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
(
tx
Hash
),
"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
())
...
...
plugin/dapp/evm/executor/query.go
View file @
781721f6
...
...
@@ -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
}
plugin/dapp/evm/executor/tests/evm_test.go
View file @
781721f6
...
...
@@ -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
,
""
,
""
)
}
plugin/dapp/evm/executor/tests/util_test.go
View file @
781721f6
...
...
@@ -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
}
plugin/dapp/evm/executor/vm/common/address.go
View file @
781721f6
...
...
@@ -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
)
...
...
plugin/dapp/evm/executor/vm/common/crypto/crypto.go
View file @
781721f6
...
...
@@ -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
}
plugin/dapp/evm/executor/vm/runtime/evm.go
View file @
781721f6
...
...
@@ -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
...
...
plugin/dapp/evm/executor/vm/runtime/instructions.go
View file @
781721f6
...
...
@@ -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
{
...
...
plugin/dapp/evm/executor/vm/state/account.go
View file @
781721f6
...
...
@@ -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
)
...
...
plugin/dapp/evm/executor/vm/state/interface.go
View file @
781721f6
...
...
@@ -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
}
plugin/dapp/evm/executor/vm/state/snapshot.go
View file @
781721f6
...
...
@@ -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
{
...
...
plugin/dapp/evm/executor/vm/state/statedb.go
View file @
781721f6
...
...
@@ -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
}
plugin/dapp/evm/proto/evmcontract.proto
View file @
781721f6
...
...
@@ -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
plugin/dapp/evm/types/evm.go
View file @
781721f6
...
...
@@ -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, ¶m)
// if err != nil {
// elog.Error("Create BindABI", "Error", err)
// return nil, types.ErrInvalidParam
// }
// return createBindABITx(¶m)
//} else if action == "ABICall" {
// var param ABICall
// err := json.Unmarshal(message, ¶m)
// if err != nil {
// elog.Error("Create ABICall", "Error", err)
// return nil, types.ErrInvalidParam
// }
// return createABICallTx(¶m)
//}
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
}
plugin/dapp/evm/types/evmcontract.pb.go
View file @
781721f6
This diff is collapsed.
Click to expand it.
plugin/dapp/evm/types/tx.go
View file @
781721f6
...
...
@@ -24,4 +24,6 @@ type CreateCallTx struct {
Name
string
`json:"name"`
// IsCreate 是否创建合约
IsCreate
bool
`json:"isCreate"`
// Abi 创建合约或调用合约时附带的ABI数据
Abi
string
`json:"abi"`
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment