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
d33e674d
Commit
d33e674d
authored
Nov 23, 2018
by
Litian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
evm abi 解析逻辑初步完成
parent
9cc23096
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
303 additions
and
146 deletions
+303
-146
abi.go
plugin/dapp/evm/executor/abi/abi.go
+1
-1
abi_test.go
plugin/dapp/evm/executor/abi/abi_test.go
+0
-0
api.go
plugin/dapp/evm/executor/abi/api.go
+200
-69
api_test.go
plugin/dapp/evm/executor/abi/api_test.go
+0
-0
argument.go
plugin/dapp/evm/executor/abi/argument.go
+5
-5
error.go
plugin/dapp/evm/executor/abi/error.go
+2
-2
event_test.go
plugin/dapp/evm/executor/abi/event_test.go
+25
-25
pack.go
plugin/dapp/evm/executor/abi/pack.go
+2
-2
reflect.go
plugin/dapp/evm/executor/abi/reflect.go
+8
-8
unpack.go
plugin/dapp/evm/executor/abi/unpack.go
+2
-2
unpack_test.go
plugin/dapp/evm/executor/abi/unpack_test.go
+23
-23
exec.go
plugin/dapp/evm/executor/exec.go
+26
-3
address.go
plugin/dapp/evm/executor/vm/common/address.go
+5
-0
evm.go
plugin/dapp/evm/types/evm.go
+4
-6
No files found.
plugin/dapp/evm/executor/abi/abi.go
View file @
d33e674d
...
...
@@ -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
...
...
plugin/dapp/evm/executor/abi/abi_test.go
View file @
d33e674d
This diff is collapsed.
Click to expand it.
plugin/dapp/evm/executor/abi/api.go
View file @
d33e674d
package
abi
import
(
"encoding/json"
"fmt"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/golang-collections/collections/stack"
"math/big"
"reflect"
"strconv"
"strings"
)
// Pack 使用ABI方式调用时,将调用方式转换为EVM底层处理的十六进制编码
// abiData 完整的ABI定义
// param 调用方法及参数
func
Pack
(
param
,
abiData
string
)
([]
byte
,
error
)
{
return
nil
,
nil
// 调用方式: foo(param1,param2)
func
Pack
(
param
,
abiData
string
)
(
methodName
string
,
packData
[]
byte
,
err
error
)
{
// 首先解析参数字符串,分析出方法名以及个参数取值
methodName
,
params
,
err
:=
procFuncCall
(
param
)
if
err
!=
nil
{
return
methodName
,
packData
,
err
}
// 解析ABI数据结构,获取本次调用的方法对象
abi
,
err
:=
JSON
(
strings
.
NewReader
(
abiData
))
if
err
!=
nil
{
return
methodName
,
packData
,
err
}
var
method
Method
var
ok
bool
if
method
,
ok
=
abi
.
Methods
[
methodName
];
!
ok
{
err
=
fmt
.
Errorf
(
"function %v not exists"
,
methodName
)
return
methodName
,
packData
,
err
}
// 获取方法参数对象,遍历解析各参数,获得参数的Go取值
paramVals
:=
[]
interface
{}{}
if
len
(
params
)
!=
0
{
// 首先检查参数个数和ABI中定义的是否一致
if
method
.
Inputs
.
LengthNonIndexed
()
!=
len
(
params
)
{
err
=
fmt
.
Errorf
(
"function Params count error: %v"
,
param
)
return
methodName
,
packData
,
err
}
for
i
,
v
:=
range
method
.
Inputs
.
NonIndexed
()
{
paramVal
,
err
:=
str2GoValue
(
v
.
Type
,
params
[
i
])
if
err
!=
nil
{
return
methodName
,
packData
,
err
}
paramVals
=
append
(
paramVals
,
paramVal
)
}
}
// 使用Abi对象将方法和参数进行打包
packData
,
err
=
abi
.
Pack
(
methodName
,
paramVals
...
)
return
methodName
,
packData
,
err
}
// Unpack 将调用返回结果按照ABI的格式序列化为json
// data 合约方法返回值
// abiData 完整的ABI定义
func
Unpack
(
data
[]
byte
,
abiData
string
)
(
string
,
error
)
{
return
""
,
nil
func
Unpack
(
data
[]
byte
,
methodName
,
abiData
string
)
(
output
string
,
err
error
)
{
// 解析ABI数据结构,获取本次调用的方法对象
abi
,
err
:=
JSON
(
strings
.
NewReader
(
abiData
))
if
err
!=
nil
{
return
output
,
err
}
var
method
Method
var
ok
bool
if
method
,
ok
=
abi
.
Methods
[
methodName
];
!
ok
{
return
output
,
fmt
.
Errorf
(
"function %v not exists"
,
methodName
)
}
values
,
err
:=
method
.
Outputs
.
UnpackValues
(
data
)
if
err
!=
nil
{
return
output
,
err
}
outputs
:=
[]
*
Param
{}
for
i
,
v
:=
range
values
{
arg
:=
method
.
Outputs
[
i
]
pval
:=
&
Param
{
Name
:
arg
.
Name
,
Type
:
arg
.
Type
.
String
(),
Value
:
v
}
outputs
=
append
(
outputs
,
pval
)
}
jsondata
,
err
:=
json
.
Marshal
(
outputs
)
if
err
!=
nil
{
return
output
,
err
}
return
string
(
jsondata
),
err
}
type
Param
struct
{
Name
string
`json:"name"`
Type
string
`json:"type"`
Value
interface
{}
`json:"value"`
}
func
convertUint
(
val
uint64
,
kind
reflect
.
Kind
)
interface
{}
{
switch
kind
{
case
reflect
.
Uint
:
return
uint
(
val
)
case
reflect
.
Uint8
:
return
uint8
(
val
)
case
reflect
.
Uint16
:
return
uint16
(
val
)
case
reflect
.
Uint32
:
return
uint32
(
val
)
case
reflect
.
Uint64
:
return
uint64
(
val
)
}
return
val
}
func
convertInt
(
val
int64
,
kind
reflect
.
Kind
)
interface
{}
{
switch
kind
{
case
reflect
.
Int
:
return
int
(
val
)
case
reflect
.
Int8
:
return
int8
(
val
)
case
reflect
.
Int16
:
return
int16
(
val
)
case
reflect
.
Int32
:
return
int32
(
val
)
case
reflect
.
Int64
:
return
int64
(
val
)
}
return
val
}
// 从字符串格式的输入参数取值(单个),获取Go类型的
func
g
oValue
(
typ
Type
,
val
string
)
(
res
interface
{},
err
error
)
{
func
str2G
oValue
(
typ
Type
,
val
string
)
(
res
interface
{},
err
error
)
{
switch
typ
.
T
{
case
IntTy
:
bitSize
:=
0
pos
:=
uint
(
typ
.
Kind
-
reflect
.
Int
)
if
pos
>
0
{
bitSize
=
(
2
<<
pos
)
*
2
}
x
,
err
:=
strconv
.
ParseInt
(
val
,
10
,
bitSize
)
if
err
!=
nil
{
return
res
,
err
if
typ
.
Size
<
256
{
x
,
err
:=
strconv
.
ParseInt
(
val
,
10
,
typ
.
Size
)
if
err
!=
nil
{
return
res
,
err
}
return
convertInt
(
x
,
typ
.
Kind
),
nil
}
else
{
b
:=
new
(
big
.
Int
)
b
.
SetString
(
val
,
10
)
return
b
,
err
}
return
x
,
nil
case
UintTy
:
bitSize
:=
0
pos
:=
uint
(
typ
.
Kind
-
reflect
.
Uint
)
if
pos
>
0
{
bitSize
=
(
2
<<
pos
)
*
2
}
x
,
err
:=
strconv
.
ParseUint
(
val
,
10
,
bitSize
)
if
err
!=
nil
{
return
res
,
err
if
typ
.
Size
<
256
{
x
,
err
:=
strconv
.
ParseUint
(
val
,
10
,
typ
.
Size
)
if
err
!=
nil
{
return
res
,
err
}
return
convertUint
(
x
,
typ
.
Kind
),
nil
}
else
{
b
:=
new
(
big
.
Int
)
b
.
SetString
(
val
,
10
)
return
b
,
err
}
return
x
,
nil
case
BoolTy
:
x
,
err
:=
strconv
.
ParseBool
(
val
)
if
err
!=
nil
{
...
...
@@ -55,34 +168,34 @@ func goValue(typ Type, val string) (res interface{}, err error) {
return
x
,
nil
case
StringTy
:
return
val
,
nil
//
case SliceTy:
// var data []interface{}
// subs, err := getSubArrayStr(val)
// if err != nil {
// return res, err
// }
//
for idx, sub := range subs {
// subVal, er := g
oValue(*typ.Elem, sub)
//
if er != nil {
//
return res, er
//
}
// data[idx] = subVal
//
}
// return data
, nil
//
case ArrayTy:
// var data [typ.Size]interface{}
// subs, err := getSubArrayStr
(val)
//
if err != nil {
//
return res, err
//
}
//
for idx, sub := range subs {
// subVal, er := g
oValue(*typ.Elem, sub)
//
if er != nil {
//
return res, er
//
}
// data[idx] = subVal
//
}
// return data
, nil
case
SliceTy
:
subs
,
err
:=
procArrayItem
(
val
)
if
err
!=
nil
{
return
res
,
err
}
rval
:=
reflect
.
MakeSlice
(
typ
.
Type
,
len
(
subs
),
len
(
subs
))
for
idx
,
sub
:=
range
subs
{
subVal
,
er
:=
str2G
oValue
(
*
typ
.
Elem
,
sub
)
if
er
!=
nil
{
return
res
,
er
}
rval
.
Index
(
idx
)
.
Set
(
reflect
.
ValueOf
(
subVal
))
}
return
rval
.
Interface
()
,
nil
case
ArrayTy
:
rval
:=
reflect
.
New
(
typ
.
Type
)
.
Elem
()
subs
,
err
:=
procArrayItem
(
val
)
if
err
!=
nil
{
return
res
,
err
}
for
idx
,
sub
:=
range
subs
{
subVal
,
er
:=
str2G
oValue
(
*
typ
.
Elem
,
sub
)
if
er
!=
nil
{
return
res
,
er
}
rval
.
Index
(
idx
)
.
Set
(
reflect
.
ValueOf
(
subVal
))
}
return
rval
.
Interface
()
,
nil
case
AddressTy
:
addr
:=
common
.
StringToAddress
(
val
)
if
addr
==
nil
{
...
...
@@ -90,25 +203,23 @@ func goValue(typ Type, val string) (res interface{}, err error) {
}
return
addr
.
ToHash160
(),
nil
case
FixedBytesTy
:
//rtype := reflect.ArrayOf(typ.Size, reflect.TypeOf(byte(0)))
//value := reflect.New(rtype).Elem()
//value.SetBytes(x)
// 固定长度多字节,输入时以十六进制方式表示,如 0xabcd00ff
//x, err := common.HexToBytes(val)
//if err != nil {
// return res, err
//}
//var data [typ.Size]byte
//copy(data[:], x)
//return data, nil
x
,
err
:=
common
.
HexToBytes
(
val
)
if
err
!=
nil
{
return
res
,
err
}
rval
:=
reflect
.
New
(
typ
.
Type
)
.
Elem
()
for
i
,
b
:=
range
x
{
rval
.
Index
(
i
)
.
Set
(
reflect
.
ValueOf
(
b
))
}
return
rval
.
Interface
(),
nil
case
BytesTy
:
// 单个字节,输入时以十六进制方式表示,如 0xab
x
,
err
:=
common
.
HexToBytes
(
val
)
if
err
!=
nil
{
return
res
,
err
}
return
x
[
0
]
,
nil
return
x
,
nil
case
HashTy
:
// 哈希类型,也是以十六进制为输入,如:0xabcdef
x
,
err
:=
common
.
HexToBytes
(
val
)
...
...
@@ -134,13 +245,13 @@ func procArrayItem(val string) (res []string, err error) {
switch
b
{
case
' '
:
// 只有字符串元素中间的空格才是有效的
if
ss
.
Len
()
>
0
&&
stackPeek
(
ss
)
==
'"'
{
if
ss
.
Len
()
>
0
&&
peekRune
(
ss
)
==
'"'
{
data
=
append
(
data
,
b
)
}
case
','
:
// 逗号有可能是多级数组里面的分隔符,我们只处理最外层数组的分隔,
// 因此,需要判断当前栈中是否只有一个'[',否则就当做普通内容对待
if
ss
.
Len
()
==
1
&&
stackPeek
(
ss
)
==
'['
{
if
ss
.
Len
()
==
1
&&
peekRune
(
ss
)
==
'['
{
// 当前元素结束
res
=
append
(
res
,
string
(
data
))
data
=
[]
rune
{}
...
...
@@ -166,7 +277,7 @@ func procArrayItem(val string) (res []string, err error) {
ss
.
Push
(
b
)
case
']'
:
// 只有当栈中只有一个']'时,才会被当做数组结束,否则就当做普通内容对待
if
ss
.
Len
()
==
1
&&
stackPeek
(
ss
)
==
'['
{
if
ss
.
Len
()
==
1
&&
peekRune
(
ss
)
==
'['
{
// 整个数组结束
res
=
append
(
res
,
string
(
data
))
}
else
{
...
...
@@ -185,6 +296,27 @@ func procArrayItem(val string) (res []string, err error) {
return
res
,
err
}
func
stackPeek
(
ss
*
stack
.
Stack
)
rune
{
func
peekRune
(
ss
*
stack
.
Stack
)
rune
{
return
ss
.
Peek
()
.
(
rune
)
}
\ No newline at end of file
}
// 解析方法调用字符串,返回方法名以及方法参数
// 例如:foo(param1,param2) -> [foo,param1,param2]
func
procFuncCall
(
param
string
)
(
funcName
string
,
res
[]
string
,
err
error
)
{
lidx
:=
strings
.
Index
(
param
,
"("
)
ridx
:=
strings
.
LastIndex
(
param
,
")"
)
if
lidx
==
-
1
||
ridx
==
-
1
{
return
funcName
,
res
,
fmt
.
Errorf
(
"invalid function signature:%v"
,
param
)
}
funcName
=
strings
.
TrimSpace
(
param
[
:
lidx
])
params
:=
strings
.
TrimSpace
(
param
[
lidx
+
1
:
ridx
])
// 将方法参数转换为数组形式,重用数组内容解析逻辑,获得各个具体的参数
if
len
(
params
)
>
0
{
res
,
err
=
procArrayItem
(
fmt
.
Sprintf
(
"[%v]"
,
params
))
}
return
funcName
,
res
,
err
}
plugin/dapp/evm/executor/abi/api_test.go
View file @
d33e674d
This diff is collapsed.
Click to expand it.
plugin/dapp/evm/executor/abi/argument.go
View file @
d33e674d
...
...
@@ -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
...
...
@@ -86,7 +86,7 @@ func (arguments Arguments) isTuple() bool {
// Unpack performs the operation hexdata -> Go format
func
(
arguments
Arguments
)
Unpack
(
v
interface
{},
data
[]
byte
)
error
{
// make sure the passed
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 +152,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 +267,7 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
// will be appended at the end of the input.
variableInput
=
append
(
variableInput
,
packed
...
)
}
else
{
// append the packed
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 @
d33e674d
...
...
@@ -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_test.go
View file @
d33e674d
...
...
@@ -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)"
)),
...
...
@@ -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
{
...
...
@@ -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
,
...
...
@@ -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/pack.go
View file @
d33e674d
...
...
@@ -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/reflect.go
View file @
d33e674d
...
...
@@ -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/unpack.go
View file @
d33e674d
...
...
@@ -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 @
d33e674d
...
...
@@ -65,13 +65,13 @@ var unpackTests = []unpackTest{
def
:
`[{ "type": "bool" }]`
,
enc
:
"0000000000000000000000000000000000000000000000000001000000000001"
,
want
:
false
,
err
:
"abi: improperly encoded boolean
v
alue"
,
err
:
"abi: improperly encoded boolean
V
alue"
,
},
{
def
:
`[{ "type": "bool" }]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000003"
,
want
:
false
,
err
:
"abi: improperly encoded boolean
v
alue"
,
err
:
"abi: improperly encoded boolean
V
alue"
,
},
{
def
:
`[{"type": "uint32"}]`
,
...
...
@@ -288,7 +288,7 @@ var unpackTests = []unpackTest{
},
// struct outputs
{
def
:
`[{"
name":"int1","type":"int256"},{"n
ame":"int2","type":"int256"}]`
,
def
:
`[{"
Name":"int1","type":"int256"},{"N
ame":"int2","type":"int256"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
struct
{
Int1
*
big
.
Int
...
...
@@ -296,7 +296,7 @@ var unpackTests = []unpackTest{
}{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
)},
},
{
def
:
`[{"
name":"int","type":"int256"},{"n
ame":"Int","type":"int256"}]`
,
def
:
`[{"
Name":"int","type":"int256"},{"N
ame":"Int","type":"int256"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
struct
{
Int1
*
big
.
Int
...
...
@@ -305,7 +305,7 @@ var unpackTests = []unpackTest{
err
:
"abi: multiple outputs mapping to the same struct field 'Int'"
,
},
{
def
:
`[{"
name":"int","type":"int256"},{"n
ame":"_int","type":"int256"}]`
,
def
:
`[{"
Name":"int","type":"int256"},{"N
ame":"_int","type":"int256"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
struct
{
Int1
*
big
.
Int
...
...
@@ -314,7 +314,7 @@ var unpackTests = []unpackTest{
err
:
"abi: multiple outputs mapping to the same struct field 'Int'"
,
},
{
def
:
`[{"
name":"Int","type":"int256"},{"n
ame":"_int","type":"int256"}]`
,
def
:
`[{"
Name":"Int","type":"int256"},{"N
ame":"_int","type":"int256"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
struct
{
Int1
*
big
.
Int
...
...
@@ -323,7 +323,7 @@ var unpackTests = []unpackTest{
err
:
"abi: multiple outputs mapping to the same struct field 'Int'"
,
},
{
def
:
`[{"
name":"Int","type":"int256"},{"n
ame":"_","type":"int256"}]`
,
def
:
`[{"
Name":"Int","type":"int256"},{"N
ame":"_","type":"int256"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
struct
{
Int1
*
big
.
Int
...
...
@@ -336,7 +336,7 @@ var unpackTests = []unpackTest{
func
TestUnpack
(
t
*
testing
.
T
)
{
for
i
,
test
:=
range
unpackTests
{
t
.
Run
(
strconv
.
Itoa
(
i
),
func
(
t
*
testing
.
T
)
{
def
:=
fmt
.
Sprintf
(
`[{ "
n
ame" : "method", "outputs": %s}]`
,
test
.
def
)
def
:=
fmt
.
Sprintf
(
`[{ "
N
ame" : "method", "outputs": %s}]`
,
test
.
def
)
abi
,
err
:=
JSON
(
strings
.
NewReader
(
def
))
if
err
!=
nil
{
t
.
Fatalf
(
"invalid ABI definition %s: %v"
,
def
,
err
)
...
...
@@ -366,7 +366,7 @@ type methodMultiOutput struct {
func
methodMultiReturn
(
require
*
require
.
Assertions
)
(
ABI
,
[]
byte
,
methodMultiOutput
)
{
const
definition
=
`[
{ "
name" : "multi", "constant" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "n
ame": "String", "type": "string" } ] }]`
{ "
Name" : "multi", "constant" : false, "outputs": [ { "Name": "Int", "type": "uint256" }, { "N
ame": "String", "type": "string" } ] }]`
var
expected
=
methodMultiOutput
{
big
.
NewInt
(
1
),
"hello"
}
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
...
...
@@ -440,7 +440,7 @@ func TestMethodMultiReturn(t *testing.T) {
}
func
TestMultiReturnWithArray
(
t
*
testing
.
T
)
{
const
definition
=
`[{"
n
ame" : "multi", "outputs": [{"type": "uint64[3]"}, {"type": "uint64"}]}]`
const
definition
=
`[{"
N
ame" : "multi", "outputs": [{"type": "uint64[3]"}, {"type": "uint64"}]}]`
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
...
...
@@ -467,7 +467,7 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
// values of nested static arrays count towards the size as well, and any element following
// after such nested array argument should be read with the correct offset,
// so that it does not read content from the previous array argument.
const
definition
=
`[{"
n
ame" : "multi", "outputs": [{"type": "uint64[3][2][4]"}, {"type": "uint64"}]}]`
const
definition
=
`[{"
N
ame" : "multi", "outputs": [{"type": "uint64[3][2][4]"}, {"type": "uint64"}]}]`
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
...
...
@@ -504,15 +504,15 @@ func TestMultiReturnWithDeeplyNestedArray(t *testing.T) {
func
TestUnmarshal
(
t
*
testing
.
T
)
{
const
definition
=
`[
{ "
n
ame" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] },
{ "
n
ame" : "bool", "constant" : false, "outputs": [ { "type": "bool" } ] },
{ "
n
ame" : "bytes", "constant" : false, "outputs": [ { "type": "bytes" } ] },
{ "
n
ame" : "fixed", "constant" : false, "outputs": [ { "type": "bytes32" } ] },
{ "
n
ame" : "multi", "constant" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] },
{ "
n
ame" : "intArraySingle", "constant" : false, "outputs": [ { "type": "uint256[3]" } ] },
{ "
n
ame" : "addressSliceSingle", "constant" : false, "outputs": [ { "type": "address[]" } ] },
{ "
name" : "addressSliceDouble", "constant" : false, "outputs": [ { "name": "a", "type": "address[]" }, { "n
ame": "b", "type": "address[]" } ] },
{ "
name" : "mixedBytes", "constant" : true, "outputs": [ { "name": "a", "type": "bytes" }, { "n
ame": "b", "type": "bytes32" } ] }]`
{ "
N
ame" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] },
{ "
N
ame" : "bool", "constant" : false, "outputs": [ { "type": "bool" } ] },
{ "
N
ame" : "bytes", "constant" : false, "outputs": [ { "type": "bytes" } ] },
{ "
N
ame" : "fixed", "constant" : false, "outputs": [ { "type": "bytes32" } ] },
{ "
N
ame" : "multi", "constant" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] },
{ "
N
ame" : "intArraySingle", "constant" : false, "outputs": [ { "type": "uint256[3]" } ] },
{ "
N
ame" : "addressSliceSingle", "constant" : false, "outputs": [ { "type": "address[]" } ] },
{ "
Name" : "addressSliceDouble", "constant" : false, "outputs": [ { "Name": "a", "type": "address[]" }, { "N
ame": "b", "type": "address[]" } ] },
{ "
Name" : "mixedBytes", "constant" : true, "outputs": [ { "Name": "a", "type": "bytes" }, { "N
ame": "b", "type": "bytes32" } ] }]`
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
if
err
!=
nil
{
...
...
@@ -535,11 +535,11 @@ func TestUnmarshal(t *testing.T) {
t
.
Error
(
err
)
}
else
{
if
!
bytes
.
Equal
(
p0
,
p0Exp
)
{
t
.
Errorf
(
"unexpected
v
alue unpacked: want %x, got %x"
,
p0Exp
,
p0
)
t
.
Errorf
(
"unexpected
V
alue unpacked: want %x, got %x"
,
p0Exp
,
p0
)
}
if
!
bytes
.
Equal
(
p1
[
:
],
p1Exp
)
{
t
.
Errorf
(
"unexpected
v
alue unpacked: want %x, got %x"
,
p1Exp
,
p1
)
t
.
Errorf
(
"unexpected
V
alue unpacked: want %x, got %x"
,
p1Exp
,
p1
)
}
}
...
...
@@ -805,7 +805,7 @@ func TestOOMMaliciousInput(t *testing.T) {
},
}
for
i
,
test
:=
range
oomTests
{
def
:=
fmt
.
Sprintf
(
`[{ "
n
ame" : "method", "outputs": %s}]`
,
test
.
def
)
def
:=
fmt
.
Sprintf
(
`[{ "
N
ame" : "method", "outputs": %s}]`
,
test
.
def
)
abi
,
err
:=
JSON
(
strings
.
NewReader
(
def
))
if
err
!=
nil
{
t
.
Fatalf
(
"invalid ABI definition %s: %v"
,
def
,
err
)
...
...
plugin/dapp/evm/executor/exec.go
View file @
d33e674d
...
...
@@ -9,6 +9,7 @@ import (
"strings"
"bytes"
log
"github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types"
"github.com/33cn/plugin/plugin/dapp/evm/executor/abi"
...
...
@@ -41,6 +42,9 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
contractAddr
common
.
Address
snapshot
int
execName
string
abiCall
bool
abiData
string
methodName
string
)
// 为了方便计费,即使合约为新生成,也将地址的初始化放到外面操作
...
...
@@ -62,9 +66,24 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
if
isCreate
{
ret
,
snapshot
,
leftOverGas
,
vmerr
=
env
.
Create
(
runtime
.
AccountRef
(
msg
.
From
()),
contractAddr
,
msg
.
Data
(),
context
.
GasLimit
,
execName
,
msg
.
Alias
())
}
else
{
inData
:=
msg
.
Data
()
//TODO 在这里进行ABI和十六进制的调用参数转换
ret
,
snapshot
,
leftOverGas
,
vmerr
=
env
.
Call
(
runtime
.
AccountRef
(
msg
.
From
()),
*
msg
.
To
(),
msg
.
Data
(),
context
.
GasLimit
,
msg
.
Value
())
if
bytes
.
HasPrefix
(
msg
.
Data
(),
evmtypes
.
ABICallPrefix
)
{
abiCall
=
true
callData
:=
msg
.
Data
()[
len
(
evmtypes
.
ABICallPrefix
)
:
]
abiDataBin
,
err
:=
evm
.
GetStateDB
()
.
Get
(
getABIKey
(
*
msg
.
To
()))
if
err
!=
nil
{
return
nil
,
err
}
abiData
=
string
(
abiDataBin
)
funcName
,
packData
,
err
:=
abi
.
Pack
(
string
(
callData
),
abiData
)
if
err
!=
nil
{
return
nil
,
err
}
methodName
=
funcName
inData
=
packData
}
ret
,
snapshot
,
leftOverGas
,
vmerr
=
env
.
Call
(
runtime
.
AccountRef
(
msg
.
From
()),
*
msg
.
To
(),
inData
,
context
.
GasLimit
,
msg
.
Value
())
}
log
.
Debug
(
"call(create) contract "
,
"input"
,
common
.
Bytes2Hex
(
msg
.
Data
()))
...
...
@@ -103,7 +122,9 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
data
,
logs
:=
evm
.
mStateDB
.
GetChangedData
(
curVer
.
GetID
())
// TODO 在这里进行调用结果的转换
if
abiCall
{
}
contractReceipt
:=
&
evmtypes
.
ReceiptEVMContract
{
Caller
:
msg
.
From
()
.
String
(),
ContractName
:
execName
,
ContractAddr
:
contractAddr
.
String
(),
UsedGas
:
usedGas
,
Ret
:
ret
}
logs
=
append
(
logs
,
&
types
.
ReceiptLog
{
Ty
:
evmtypes
.
TyLogCallContract
,
Log
:
types
.
Encode
(
contractReceipt
)})
logs
=
append
(
logs
,
evm
.
mStateDB
.
GetReceiptLogs
(
contractAddr
.
String
())
...
)
...
...
@@ -121,6 +142,8 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
_
,
err
=
abi
.
JSON
(
strings
.
NewReader
(
msg
.
ABI
()))
if
err
==
nil
{
data
=
append
(
data
,
evm
.
getABIKV
(
contractAddr
,
msg
.
ABI
()))
}
else
{
log
.
Debug
(
"invalid abi data in transaction note"
,
"note"
,
msg
.
ABI
())
}
}
...
...
plugin/dapp/evm/executor/vm/common/address.go
View file @
d33e674d
...
...
@@ -84,6 +84,11 @@ func (h Hash160Address) Hex() string {
return
"0x"
+
string
(
result
)
}
// ToAddress 返回Chain33格式的地址
func
(
h
Hash160Address
)
ToAddress
()
Address
{
return
BytesToAddress
(
h
[
:
])
}
// NewAddress xHash生成EVM合约地址
func
NewAddress
(
txHash
[]
byte
)
Address
{
execAddr
:=
address
.
GetExecAddress
(
types
.
ExecName
(
"user.evm."
)
+
BytesToHash
(
txHash
)
.
Hex
())
...
...
plugin/dapp/evm/types/evm.go
View file @
d33e674d
...
...
@@ -23,8 +23,7 @@ var (
"EvmCall"
:
EvmCallAction
,
}
BindABIPrefix
=
ecommon
.
FromHex
(
"0x00000000"
)
ABICallPrefix
=
ecommon
.
FromHex
(
"0xffffffff"
)
ABICallPrefix
=
ecommon
.
FromHex
(
"0x00000000"
)
)
func
init
()
{
...
...
@@ -214,10 +213,10 @@ func createEvmTx(param *CreateCallTx) (*types.Transaction, error) {
return
createRawTx
(
action
,
""
)
}
else
{
if
err
!=
nil
{
elog
.
Debug
(
"create evm call Tx as abi
"
,
"param.Code"
,
param
.
Code
)
elog
.
Info
(
"evm call data is invalid hex data, process it as abi data
"
,
"param.Code"
,
param
.
Code
)
bCode
=
[]
byte
(
param
.
Code
)
bCode
=
append
(
BindABI
Prefix
,
bCode
...
)
bCode
=
append
(
ABICall
Prefix
,
bCode
...
)
}
return
createRawTx
(
action
,
param
.
Name
)
}
}
\ No newline at end of file
}
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