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
b2ebdcd4
Unverified
Commit
b2ebdcd4
authored
Nov 28, 2018
by
33cn
Committed by
GitHub
Nov 28, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #89 from litian33/evm_abi
Evm abi
parents
bbd3a1b6
80b3761f
Show whitespace changes
Inline
Side-by-side
Showing
48 changed files
with
5905 additions
and
155 deletions
+5905
-155
raft.go
plugin/consensus/raft/raft.go
+1
-1
scp.go
plugin/consensus/raft/tools/scripts/go-scp/scp.go
+1
-1
evm.go
plugin/dapp/evm/commands/evm.go
+101
-9
evm_test.go
plugin/dapp/evm/commands/evm_test.go
+53
-0
abi.go
plugin/dapp/evm/executor/abi/abi.go
+149
-0
abi_test.go
plugin/dapp/evm/executor/abi/abi_test.go
+724
-0
api.go
plugin/dapp/evm/executor/abi/api.go
+340
-0
api_test.go
plugin/dapp/evm/executor/abi/api_test.go
+461
-0
argument.go
plugin/dapp/evm/executor/abi/argument.go
+291
-0
error.go
plugin/dapp/evm/executor/abi/error.go
+84
-0
event.go
plugin/dapp/evm/executor/abi/event.go
+57
-0
event_test.go
plugin/dapp/evm/executor/abi/event_test.go
+372
-0
method.go
plugin/dapp/evm/executor/abi/method.go
+78
-0
numbers.go
plugin/dapp/evm/executor/abi/numbers.go
+43
-0
numbers_test.go
plugin/dapp/evm/executor/abi/numbers_test.go
+33
-0
pack.go
plugin/dapp/evm/executor/abi/pack.go
+80
-0
pack_test.go
plugin/dapp/evm/executor/abi/pack_test.go
+443
-0
reflect.go
plugin/dapp/evm/executor/abi/reflect.go
+212
-0
type.go
plugin/dapp/evm/executor/abi/type.go
+209
-0
type_test.go
plugin/dapp/evm/executor/abi/type_test.go
+283
-0
unpack.go
plugin/dapp/evm/executor/abi/unpack.go
+252
-0
unpack_test.go
plugin/dapp/evm/executor/abi/unpack_test.go
+822
-0
evm.go
plugin/dapp/evm/executor/evm.go
+1
-1
exec.go
plugin/dapp/evm/executor/exec.go
+58
-28
exec_del_local.go
plugin/dapp/evm/executor/exec_del_local.go
+1
-1
exec_local.go
plugin/dapp/evm/executor/exec_local.go
+1
-1
query.go
plugin/dapp/evm/executor/query.go
+96
-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
+69
-5
bytes.go
plugin/dapp/evm/executor/vm/common/bytes.go
+21
-0
crypto.go
plugin/dapp/evm/executor/vm/common/crypto/crypto.go
+11
-0
hash.go
plugin/dapp/evm/executor/vm/common/hash.go
+3
-0
message.go
plugin/dapp/evm/executor/vm/common/message.go
+6
-1
evm.go
plugin/dapp/evm/executor/vm/runtime/evm.go
+7
-2
instructions.go
plugin/dapp/evm/executor/vm/runtime/instructions.go
+1
-1
account.go
plugin/dapp/evm/executor/vm/state/account.go
+15
-3
interface.go
plugin/dapp/evm/executor/vm/state/interface.go
+7
-0
snapshot.go
plugin/dapp/evm/executor/vm/state/snapshot.go
+24
-1
statedb.go
plugin/dapp/evm/executor/vm/state/statedb.go
+25
-1
evmcontract.proto
plugin/dapp/evm/proto/evmcontract.proto
+31
-0
evm.go
plugin/dapp/evm/types/evm.go
+46
-22
evmcontract.pb.go
plugin/dapp/evm/types/evmcontract.pb.go
+305
-46
tx.go
plugin/dapp/evm/types/tx.go
+2
-0
types.go
plugin/dapp/evm/types/types.go
+11
-0
LICENSE
vendor/github.com/golang-collections/collections/LICENSE
+21
-0
stack.go
.../github.com/golang-collections/collections/stack/stack.go
+45
-0
vendor.json
vendor/vendor.json
+6
-0
No files found.
plugin/consensus/raft/raft.go
View file @
b2ebdcd4
...
...
@@ -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 @
b2ebdcd4
...
...
@@ -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/commands/evm.go
View file @
b2ebdcd4
...
...
@@ -15,6 +15,8 @@ import (
"strconv"
"encoding/json"
"github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/common/crypto/sha3"
...
...
@@ -39,6 +41,7 @@ func EvmCmd() *cobra.Command {
cmd
.
AddCommand
(
createContractCmd
(),
callContractCmd
(),
abiCmd
(),
estimateContractCmd
(),
checkContractAddrCmd
(),
evmDebugCmd
(),
...
...
@@ -200,8 +203,10 @@ func createContractCmd() *cobra.Command {
func
addCreateContractFlags
(
cmd
*
cobra
.
Command
)
{
addCommonFlags
(
cmd
)
cmd
.
MarkFlagRequired
(
"input"
)
cmd
.
Flags
()
.
StringP
(
"alias"
,
"s"
,
""
,
"human readable contract alias name"
)
cmd
.
Flags
()
.
StringP
(
"abi"
,
"b"
,
""
,
"bind the abi data"
)
}
func
createContract
(
cmd
*
cobra
.
Command
,
args
[]
string
)
{
...
...
@@ -213,6 +218,7 @@ func createContract(cmd *cobra.Command, args []string) {
fee
,
_
:=
cmd
.
Flags
()
.
GetFloat64
(
"fee"
)
rpcLaddr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"rpc_laddr"
)
paraName
,
_
:=
cmd
.
Flags
()
.
GetString
(
"paraName"
)
abi
,
_
:=
cmd
.
Flags
()
.
GetString
(
"abi"
)
feeInt64
:=
uint64
(
fee
*
1e4
)
*
1e4
...
...
@@ -221,7 +227,7 @@ func createContract(cmd *cobra.Command, args []string) {
fmt
.
Fprintln
(
os
.
Stderr
,
"parse evm code error"
,
err
)
return
}
action
:=
evmtypes
.
EVMContractAction
{
Amount
:
0
,
Code
:
bCode
,
GasLimit
:
0
,
GasPrice
:
0
,
Note
:
note
,
Alias
:
alias
}
action
:=
evmtypes
.
EVMContractAction
{
Amount
:
0
,
Code
:
bCode
,
GasLimit
:
0
,
GasPrice
:
0
,
Note
:
note
,
Alias
:
alias
,
Abi
:
abi
}
data
,
err
:=
createEvmTx
(
&
action
,
types
.
ExecName
(
paraName
+
"evm"
),
caller
,
address
.
ExecAddress
(
types
.
ExecName
(
paraName
+
"evm"
)),
expire
,
rpcLaddr
,
feeInt64
)
...
...
@@ -343,6 +349,7 @@ func callContract(cmd *cobra.Command, args []string) {
amount
,
_
:=
cmd
.
Flags
()
.
GetFloat64
(
"amount"
)
fee
,
_
:=
cmd
.
Flags
()
.
GetFloat64
(
"fee"
)
name
,
_
:=
cmd
.
Flags
()
.
GetString
(
"exec"
)
abi
,
_
:=
cmd
.
Flags
()
.
GetString
(
"abi"
)
rpcLaddr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"rpc_laddr"
)
amountInt64
:=
uint64
(
amount
*
1e4
)
*
1e4
...
...
@@ -355,7 +362,7 @@ func callContract(cmd *cobra.Command, args []string) {
return
}
action
:=
evmtypes
.
EVMContractAction
{
Amount
:
amountInt64
,
Code
:
bCode
,
GasLimit
:
0
,
GasPrice
:
0
,
Note
:
note
}
action
:=
evmtypes
.
EVMContractAction
{
Amount
:
amountInt64
,
Code
:
bCode
,
GasLimit
:
0
,
GasPrice
:
0
,
Note
:
note
,
Abi
:
abi
}
//name表示发给哪个执行器
data
,
err
:=
createEvmTx
(
&
action
,
name
,
caller
,
toAddr
,
expire
,
rpcLaddr
,
feeInt64
)
...
...
@@ -379,11 +386,12 @@ func addCallContractFlags(cmd *cobra.Command) {
cmd
.
MarkFlagRequired
(
"exec"
)
cmd
.
Flags
()
.
Float64P
(
"amount"
,
"a"
,
0
,
"the amount transfer to the contract (optional)"
)
cmd
.
Flags
()
.
StringP
(
"abi"
,
"b"
,
""
,
"call with abi"
)
}
func
addCommonFlags
(
cmd
*
cobra
.
Command
)
{
cmd
.
Flags
()
.
StringP
(
"input"
,
"i"
,
""
,
"input contract binary code"
)
cmd
.
MarkFlagRequired
(
"input"
)
cmd
.
Flags
()
.
StringP
(
"caller"
,
"c"
,
""
,
"the caller address"
)
cmd
.
MarkFlagRequired
(
"caller"
)
...
...
@@ -395,6 +403,85 @@ func addCommonFlags(cmd *cobra.Command) {
cmd
.
Flags
()
.
Float64P
(
"fee"
,
"f"
,
0
,
"contract gas fee (optional)"
)
}
// abi命令
func
abiCmd
()
*
cobra
.
Command
{
cmd
:=
&
cobra
.
Command
{
Use
:
"abi"
,
Short
:
"EVM ABI commands"
,
Args
:
cobra
.
MinimumNArgs
(
1
),
}
cmd
.
AddCommand
(
getAbiCmd
(),
callAbiCmd
(),
)
return
cmd
}
func
getAbiCmd
()
*
cobra
.
Command
{
cmd
:=
&
cobra
.
Command
{
Use
:
"get"
,
Short
:
"get abi data of evm contract"
,
Run
:
getAbi
,
}
cmd
.
Flags
()
.
StringP
(
"address"
,
"a"
,
""
,
"evm contract address"
)
cmd
.
MarkFlagRequired
(
"address"
)
return
cmd
}
func
getAbi
(
cmd
*
cobra
.
Command
,
args
[]
string
)
{
addr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"address"
)
var
req
=
evmtypes
.
EvmQueryAbiReq
{
Address
:
addr
}
var
resp
evmtypes
.
EvmQueryAbiResp
rpcLaddr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"rpc_laddr"
)
query
:=
sendQuery
(
rpcLaddr
,
"QueryABI"
,
&
req
,
&
resp
)
if
query
{
fmt
.
Fprintln
(
os
.
Stdout
,
resp
.
Abi
)
}
}
func
callAbiCmd
()
*
cobra
.
Command
{
cmd
:=
&
cobra
.
Command
{
Use
:
"call"
,
Short
:
"send query call by abi format"
,
Run
:
callAbi
,
}
cmd
.
Flags
()
.
StringP
(
"address"
,
"a"
,
""
,
"evm contract address"
)
cmd
.
MarkFlagRequired
(
"address"
)
cmd
.
Flags
()
.
StringP
(
"input"
,
"b"
,
""
,
"call params (abi format) like foobar(param1,param2)"
)
cmd
.
MarkFlagRequired
(
"input"
)
cmd
.
Flags
()
.
StringP
(
"caller"
,
"c"
,
""
,
"the caller address"
)
return
cmd
}
func
callAbi
(
cmd
*
cobra
.
Command
,
args
[]
string
)
{
addr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"address"
)
input
,
_
:=
cmd
.
Flags
()
.
GetString
(
"input"
)
caller
,
_
:=
cmd
.
Flags
()
.
GetString
(
"caller"
)
var
req
=
evmtypes
.
EvmQueryReq
{
Address
:
addr
,
Input
:
input
,
Caller
:
caller
}
var
resp
evmtypes
.
EvmQueryResp
rpcLaddr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"rpc_laddr"
)
query
:=
sendQuery
(
rpcLaddr
,
"Query"
,
&
req
,
&
resp
)
if
query
{
data
,
err
:=
json
.
MarshalIndent
(
&
resp
,
""
,
" "
)
if
err
!=
nil
{
fmt
.
Println
(
resp
.
String
())
}
else
{
fmt
.
Println
(
string
(
data
))
}
}
}
func
estimateContract
(
cmd
*
cobra
.
Command
,
args
[]
string
)
{
code
,
_
:=
cmd
.
Flags
()
.
GetString
(
"input"
)
name
,
_
:=
cmd
.
Flags
()
.
GetString
(
"exec"
)
...
...
@@ -416,7 +503,7 @@ func estimateContract(cmd *cobra.Command, args []string) {
var
estGasReq
=
evmtypes
.
EstimateEVMGasReq
{
To
:
toAddr
,
Code
:
bCode
,
Caller
:
caller
,
Amount
:
amountInt64
}
var
estGasResp
evmtypes
.
EstimateEVMGasResp
rpcLaddr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"rpc_laddr"
)
query
:=
sendQuery
(
rpcLaddr
,
"EstimateGas"
,
estGasReq
,
&
estGasResp
)
query
:=
sendQuery
(
rpcLaddr
,
"EstimateGas"
,
&
estGasReq
,
&
estGasResp
)
if
query
{
fmt
.
Fprintf
(
os
.
Stdout
,
"gas cost estimate %v
\n
"
,
estGasResp
.
Gas
)
...
...
@@ -481,7 +568,7 @@ func checkContractAddr(cmd *cobra.Command, args []string) {
var
checkAddrReq
=
evmtypes
.
CheckEVMAddrReq
{
Addr
:
toAddr
}
var
checkAddrResp
evmtypes
.
CheckEVMAddrResp
rpcLaddr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"rpc_laddr"
)
query
:=
sendQuery
(
rpcLaddr
,
"CheckAddrExists"
,
checkAddrReq
,
&
checkAddrResp
)
query
:=
sendQuery
(
rpcLaddr
,
"CheckAddrExists"
,
&
checkAddrReq
,
&
checkAddrResp
)
if
query
&&
checkAddrResp
.
Contract
{
proto
.
MarshalText
(
os
.
Stdout
,
&
checkAddrResp
)
...
...
@@ -541,7 +628,7 @@ func evmDebugRPC(cmd *cobra.Command, flag int32) {
var
debugReq
=
evmtypes
.
EvmDebugReq
{
Optype
:
flag
}
var
debugResp
evmtypes
.
EvmDebugResp
rpcLaddr
,
_
:=
cmd
.
Flags
()
.
GetString
(
"rpc_laddr"
)
query
:=
sendQuery
(
rpcLaddr
,
"EvmDebug"
,
debugReq
,
&
debugResp
)
query
:=
sendQuery
(
rpcLaddr
,
"EvmDebug"
,
&
debugReq
,
&
debugResp
)
if
query
{
proto
.
MarshalText
(
os
.
Stdout
,
&
debugResp
)
...
...
@@ -646,11 +733,16 @@ func evmWithdraw(cmd *cobra.Command, args []string) {
ctx
.
RunWithoutMarshal
()
}
func
sendQuery
(
rpcAddr
,
funcName
string
,
request
interface
{},
result
proto
.
Message
)
bool
{
params
:=
types
.
Query4Cli
{
func
sendQuery
(
rpcAddr
,
funcName
string
,
request
,
result
proto
.
Message
)
bool
{
js
,
err
:=
types
.
PBToJSON
(
request
)
if
err
!=
nil
{
fmt
.
Fprintln
(
os
.
Stderr
,
err
)
return
false
}
params
:=
rpctypes
.
Query4Jrpc
{
Execer
:
"evm"
,
FuncName
:
funcName
,
Payload
:
request
,
Payload
:
js
,
}
jsonrpc
,
err
:=
jsonclient
.
NewJSONClient
(
rpcAddr
)
...
...
plugin/dapp/evm/commands/evm_test.go
0 → 100644
View file @
b2ebdcd4
package
commands
import
(
"testing"
"github.com/33cn/chain33/rpc/jsonclient"
rpctypes
"github.com/33cn/chain33/rpc/types"
"github.com/33cn/chain33/types"
"github.com/33cn/chain33/util/testnode"
"github.com/stretchr/testify/assert"
// 因为测试程序在外层,而合约类型的初始化在里面,所以需要显示引用,否则不会加载合约插件
_
"github.com/33cn/plugin/plugin/dapp/evm/executor"
evmtypes
"github.com/33cn/plugin/plugin/dapp/evm/types"
// 需要显示引用系统插件,以加载系统内置合约
"github.com/33cn/chain33/client/mocks"
_
"github.com/33cn/chain33/system"
)
// TestQueryDebug 测试命令行调用rpc接口
func
TestQueryDebug
(
t
*
testing
.
T
)
{
var
debugReq
=
evmtypes
.
EvmDebugReq
{
Optype
:
1
}
js
,
err
:=
types
.
PBToJSON
(
&
debugReq
)
assert
.
Nil
(
t
,
err
)
in
:=
&
rpctypes
.
Query4Jrpc
{
Execer
:
"evm"
,
FuncName
:
"EvmDebug"
,
Payload
:
js
,
}
var
mockResp
=
evmtypes
.
EvmDebugResp
{
DebugStatus
:
"on"
}
mockapi
:=
&
mocks
.
QueueProtocolAPI
{}
// 这里对需要mock的方法打桩,Close是必须的,其它方法根据需要
mockapi
.
On
(
"Close"
)
.
Return
()
mockapi
.
On
(
"Query"
,
"evm"
,
"EvmDebug"
,
&
debugReq
)
.
Return
(
&
mockResp
,
nil
)
mock33
:=
testnode
.
New
(
""
,
mockapi
)
defer
mock33
.
Close
()
rpcCfg
:=
mock33
.
GetCfg
()
.
RPC
// 这里必须设置监听端口,默认的是无效值
rpcCfg
.
JrpcBindAddr
=
"127.0.0.1:8899"
mock33
.
GetRPC
()
.
Listen
()
jsonClient
,
err
:=
jsonclient
.
NewJSONClient
(
"http://"
+
rpcCfg
.
JrpcBindAddr
+
"/"
)
assert
.
Nil
(
t
,
err
)
assert
.
NotNil
(
t
,
jsonClient
)
var
debugResp
evmtypes
.
EvmDebugResp
err
=
jsonClient
.
Call
(
"Chain33.Query"
,
in
,
&
debugResp
)
assert
.
Nil
(
t
,
err
)
assert
.
Equal
(
t
,
"on"
,
debugResp
.
DebugStatus
)
}
plugin/dapp/evm/executor/abi/abi.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"bytes"
"encoding/json"
"fmt"
"io"
)
// The ABI holds information about a contract's context and available
// invokable methods. It will allow you to type check function calls and
// packs data accordingly.
type
ABI
struct
{
Constructor
Method
Methods
map
[
string
]
Method
Events
map
[
string
]
Event
}
// JSON returns a parsed ABI interface and error if it failed.
func
JSON
(
reader
io
.
Reader
)
(
ABI
,
error
)
{
dec
:=
json
.
NewDecoder
(
reader
)
var
abi
ABI
if
err
:=
dec
.
Decode
(
&
abi
);
err
!=
nil
{
return
ABI
{},
err
}
return
abi
,
nil
}
// Pack the given method name to conform the ABI. Method call's data
// will consist of method_id, args0, arg1, ... argN. Method id consists
// of 4 bytes and arguments are all 32 bytes.
// Method ids are created from the first 4 bytes of the hash of the
// methods string signature. (signature = baz(uint32,string32))
func
(
abi
ABI
)
Pack
(
name
string
,
args
...
interface
{})
([]
byte
,
error
)
{
// Fetch the ABI of the requested method
if
name
==
""
{
// constructor
arguments
,
err
:=
abi
.
Constructor
.
Inputs
.
Pack
(
args
...
)
if
err
!=
nil
{
return
nil
,
err
}
return
arguments
,
nil
}
method
,
exist
:=
abi
.
Methods
[
name
]
if
!
exist
{
return
nil
,
fmt
.
Errorf
(
"method '%s' not found"
,
name
)
}
arguments
,
err
:=
method
.
Inputs
.
Pack
(
args
...
)
if
err
!=
nil
{
return
nil
,
err
}
// Pack up the method ID too if not a constructor and return
return
append
(
method
.
ID
(),
arguments
...
),
nil
}
// Unpack output in v according to the abi specification
func
(
abi
ABI
)
Unpack
(
v
interface
{},
name
string
,
output
[]
byte
)
(
err
error
)
{
if
len
(
output
)
==
0
{
return
fmt
.
Errorf
(
"abi: unmarshalling empty output"
)
}
// since there can't be naming collisions with contracts and events,
// we need to decide whether we're calling a method or an event
if
method
,
ok
:=
abi
.
Methods
[
name
];
ok
{
if
len
(
output
)
%
32
!=
0
{
return
fmt
.
Errorf
(
"abi: improperly formatted output"
)
}
return
method
.
Outputs
.
Unpack
(
v
,
output
)
}
else
if
event
,
ok
:=
abi
.
Events
[
name
];
ok
{
return
event
.
Inputs
.
Unpack
(
v
,
output
)
}
return
fmt
.
Errorf
(
"abi: could not locate named method or event"
)
}
// UnmarshalJSON implements json.Unmarshaler interface
func
(
abi
*
ABI
)
UnmarshalJSON
(
data
[]
byte
)
error
{
var
fields
[]
struct
{
Type
string
Name
string
Constant
bool
Anonymous
bool
Inputs
[]
Argument
Outputs
[]
Argument
}
if
err
:=
json
.
Unmarshal
(
data
,
&
fields
);
err
!=
nil
{
return
err
}
abi
.
Methods
=
make
(
map
[
string
]
Method
)
abi
.
Events
=
make
(
map
[
string
]
Event
)
for
_
,
field
:=
range
fields
{
switch
field
.
Type
{
case
"constructor"
:
abi
.
Constructor
=
Method
{
Inputs
:
field
.
Inputs
,
}
// empty defaults to function according to the abi spec
case
"function"
,
""
:
abi
.
Methods
[
field
.
Name
]
=
Method
{
Name
:
field
.
Name
,
Const
:
field
.
Constant
,
Inputs
:
field
.
Inputs
,
Outputs
:
field
.
Outputs
,
}
case
"event"
:
abi
.
Events
[
field
.
Name
]
=
Event
{
Name
:
field
.
Name
,
Anonymous
:
field
.
Anonymous
,
Inputs
:
field
.
Inputs
,
}
}
}
return
nil
}
// MethodByID looks up a method by the 4-byte id
// returns nil if none found
func
(
abi
*
ABI
)
MethodByID
(
sigdata
[]
byte
)
(
*
Method
,
error
)
{
if
len
(
sigdata
)
<
4
{
return
nil
,
fmt
.
Errorf
(
"data too short (% bytes) for abi method lookup"
,
len
(
sigdata
))
}
for
_
,
method
:=
range
abi
.
Methods
{
if
bytes
.
Equal
(
method
.
ID
(),
sigdata
[
:
4
])
{
return
&
method
,
nil
}
}
return
nil
,
fmt
.
Errorf
(
"no method with id: %#x"
,
sigdata
[
:
4
])
}
plugin/dapp/evm/executor/abi/abi_test.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"bytes"
"encoding/hex"
"fmt"
"log"
"math/big"
"strings"
"testing"
"reflect"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common/crypto"
)
const
jsondata
=
`
[
{ "type" : "function", "name" : "balance", "constant" : true },
{ "type" : "function", "name" : "send", "constant" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] }
]`
const
jsondata2
=
`
[
{ "type" : "function", "name" : "balance", "constant" : true },
{ "type" : "function", "name" : "send", "constant" : false, "inputs" : [ { "name" : "amount", "type" : "uint256" } ] },
{ "type" : "function", "name" : "test", "constant" : false, "inputs" : [ { "name" : "number", "type" : "uint32" } ] },
{ "type" : "function", "name" : "string", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "string" } ] },
{ "type" : "function", "name" : "bool", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "bool" } ] },
{ "type" : "function", "name" : "address", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "address" } ] },
{ "type" : "function", "name" : "uint64[2]", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint64[2]" } ] },
{ "type" : "function", "name" : "uint64[]", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint64[]" } ] },
{ "type" : "function", "name" : "foo", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" } ] },
{ "type" : "function", "name" : "bar", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32" }, { "name" : "string", "type" : "uint16" } ] },
{ "type" : "function", "name" : "slice", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint32[2]" } ] },
{ "type" : "function", "name" : "slice256", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "uint256[2]" } ] },
{ "type" : "function", "name" : "sliceAddress", "constant" : false, "inputs" : [ { "name" : "inputs", "type" : "address[]" } ] },
{ "type" : "function", "name" : "sliceMultiAddress", "constant" : false, "inputs" : [ { "name" : "a", "type" : "address[]" }, { "name" : "b", "type" : "address[]" } ] }
]`
func
TestReader
(
t
*
testing
.
T
)
{
Uint256
,
_
:=
NewType
(
"uint256"
)
exp
:=
ABI
{
Methods
:
map
[
string
]
Method
{
"balance"
:
{
"balance"
,
true
,
nil
,
nil
,
},
"send"
:
{
"send"
,
false
,
[]
Argument
{
{
"amount"
,
Uint256
,
false
},
},
nil
,
},
},
}
abi
,
err
:=
JSON
(
strings
.
NewReader
(
jsondata
))
if
err
!=
nil
{
t
.
Error
(
err
)
}
// deep equal fails for some reason
for
name
,
expM
:=
range
exp
.
Methods
{
gotM
,
exist
:=
abi
.
Methods
[
name
]
if
!
exist
{
t
.
Errorf
(
"Missing expected method %v"
,
name
)
}
if
!
reflect
.
DeepEqual
(
gotM
,
expM
)
{
t
.
Errorf
(
"
\n
Got abi method:
\n
%v
\n
does not match expected method
\n
%v"
,
gotM
,
expM
)
}
}
for
name
,
gotM
:=
range
abi
.
Methods
{
expM
,
exist
:=
exp
.
Methods
[
name
]
if
!
exist
{
t
.
Errorf
(
"Found extra method %v"
,
name
)
}
if
!
reflect
.
DeepEqual
(
gotM
,
expM
)
{
t
.
Errorf
(
"
\n
Got abi method:
\n
%v
\n
does not match expected method
\n
%v"
,
gotM
,
expM
)
}
}
}
func
TestTestNumbers
(
t
*
testing
.
T
)
{
abi
,
err
:=
JSON
(
strings
.
NewReader
(
jsondata2
))
if
err
!=
nil
{
t
.
Error
(
err
)
t
.
FailNow
()
}
if
_
,
err
:=
abi
.
Pack
(
"balance"
);
err
!=
nil
{
t
.
Error
(
err
)
}
if
_
,
err
:=
abi
.
Pack
(
"balance"
,
1
);
err
==
nil
{
t
.
Error
(
"expected error for balance(1)"
)
}
if
_
,
err
:=
abi
.
Pack
(
"doesntexist"
,
nil
);
err
==
nil
{
t
.
Errorf
(
"doesntexist shouldn't exist"
)
}
if
_
,
err
:=
abi
.
Pack
(
"doesntexist"
,
1
);
err
==
nil
{
t
.
Errorf
(
"doesntexist(1) shouldn't exist"
)
}
if
_
,
err
:=
abi
.
Pack
(
"send"
,
big
.
NewInt
(
1000
));
err
!=
nil
{
t
.
Error
(
err
)
}
i
:=
new
(
int
)
*
i
=
1000
if
_
,
err
:=
abi
.
Pack
(
"send"
,
i
);
err
==
nil
{
t
.
Errorf
(
"expected send( ptr ) to throw, requires *big.Int instead of *int"
)
}
if
_
,
err
:=
abi
.
Pack
(
"test"
,
uint32
(
1000
));
err
!=
nil
{
t
.
Error
(
err
)
}
}
func
TestTestString
(
t
*
testing
.
T
)
{
abi
,
err
:=
JSON
(
strings
.
NewReader
(
jsondata2
))
if
err
!=
nil
{
t
.
Error
(
err
)
t
.
FailNow
()
}
if
_
,
err
:=
abi
.
Pack
(
"string"
,
"hello world"
);
err
!=
nil
{
t
.
Error
(
err
)
}
}
func
TestTestBool
(
t
*
testing
.
T
)
{
abi
,
err
:=
JSON
(
strings
.
NewReader
(
jsondata2
))
if
err
!=
nil
{
t
.
Error
(
err
)
t
.
FailNow
()
}
if
_
,
err
:=
abi
.
Pack
(
"bool"
,
true
);
err
!=
nil
{
t
.
Error
(
err
)
}
}
func
TestTestSlice
(
t
*
testing
.
T
)
{
abi
,
err
:=
JSON
(
strings
.
NewReader
(
jsondata2
))
if
err
!=
nil
{
t
.
Error
(
err
)
t
.
FailNow
()
}
slice
:=
make
([]
uint64
,
2
)
if
_
,
err
:=
abi
.
Pack
(
"uint64[2]"
,
slice
);
err
!=
nil
{
t
.
Error
(
err
)
}
if
_
,
err
:=
abi
.
Pack
(
"uint64[]"
,
slice
);
err
!=
nil
{
t
.
Error
(
err
)
}
}
func
TestMethodSignature
(
t
*
testing
.
T
)
{
String
,
_
:=
NewType
(
"string"
)
m
:=
Method
{
"foo"
,
false
,
[]
Argument
{{
"bar"
,
String
,
false
},
{
"baz"
,
String
,
false
}},
nil
}
exp
:=
"foo(string,string)"
if
m
.
Sig
()
!=
exp
{
t
.
Error
(
"signature mismatch"
,
exp
,
"!="
,
m
.
Sig
())
}
idexp
:=
crypto
.
Keccak256
([]
byte
(
exp
))[
:
4
]
if
!
bytes
.
Equal
(
m
.
ID
(),
idexp
)
{
t
.
Errorf
(
"expected ids to match %x != %x"
,
m
.
ID
(),
idexp
)
}
uintt
,
_
:=
NewType
(
"uint256"
)
m
=
Method
{
"foo"
,
false
,
[]
Argument
{{
"bar"
,
uintt
,
false
}},
nil
}
exp
=
"foo(uint256)"
if
m
.
Sig
()
!=
exp
{
t
.
Error
(
"signature mismatch"
,
exp
,
"!="
,
m
.
Sig
())
}
}
func
TestMultiPack
(
t
*
testing
.
T
)
{
abi
,
err
:=
JSON
(
strings
.
NewReader
(
jsondata2
))
if
err
!=
nil
{
t
.
Error
(
err
)
t
.
FailNow
()
}
sig
:=
crypto
.
Keccak256
([]
byte
(
"bar(uint32,uint16)"
))[
:
4
]
sig
=
append
(
sig
,
make
([]
byte
,
64
)
...
)
sig
[
35
]
=
10
sig
[
67
]
=
11
packed
,
err
:=
abi
.
Pack
(
"bar"
,
uint32
(
10
),
uint16
(
11
))
if
err
!=
nil
{
t
.
Error
(
err
)
t
.
FailNow
()
}
if
!
bytes
.
Equal
(
packed
,
sig
)
{
t
.
Errorf
(
"expected %x got %x"
,
sig
,
packed
)
}
}
func
ExampleJSON
()
{
const
definition
=
`[{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"isBar","outputs":[{"name":"","type":"bool"}],"type":"function"}]`
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
if
err
!=
nil
{
log
.
Fatalln
(
err
)
}
out
,
err
:=
abi
.
Pack
(
"isBar"
,
common
.
HexToAddress
(
"01"
))
if
err
!=
nil
{
log
.
Fatalln
(
err
)
}
fmt
.
Printf
(
"%x
\n
"
,
out
)
// Output:
// 1f2c40920000000000000000000000000000000000000000000000000000000000000001
}
func
TestInputVariableInputLength
(
t
*
testing
.
T
)
{
const
definition
=
`[
{ "type" : "function", "name" : "strOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" } ] },
{ "type" : "function", "name" : "bytesOne", "constant" : true, "inputs" : [ { "name" : "str", "type" : "bytes" } ] },
{ "type" : "function", "name" : "strTwo", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "str1", "type" : "string" } ] }
]`
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// test one string
strin
:=
"hello world"
strpack
,
err
:=
abi
.
Pack
(
"strOne"
,
strin
)
if
err
!=
nil
{
t
.
Error
(
err
)
}
offset
:=
make
([]
byte
,
32
)
offset
[
31
]
=
32
length
:=
make
([]
byte
,
32
)
length
[
31
]
=
byte
(
len
(
strin
))
value
:=
common
.
RightPadBytes
([]
byte
(
strin
),
32
)
exp
:=
append
(
offset
,
append
(
length
,
value
...
)
...
)
// ignore first 4 bytes of the output. This is the function identifier
strpack
=
strpack
[
4
:
]
if
!
bytes
.
Equal
(
strpack
,
exp
)
{
t
.
Errorf
(
"expected %x, got %x
\n
"
,
exp
,
strpack
)
}
// test one bytes
btspack
,
err
:=
abi
.
Pack
(
"bytesOne"
,
[]
byte
(
strin
))
if
err
!=
nil
{
t
.
Error
(
err
)
}
// ignore first 4 bytes of the output. This is the function identifier
btspack
=
btspack
[
4
:
]
if
!
bytes
.
Equal
(
btspack
,
exp
)
{
t
.
Errorf
(
"expected %x, got %x
\n
"
,
exp
,
btspack
)
}
// test two strings
str1
:=
"hello"
str2
:=
"world"
str2pack
,
err
:=
abi
.
Pack
(
"strTwo"
,
str1
,
str2
)
if
err
!=
nil
{
t
.
Error
(
err
)
}
offset1
:=
make
([]
byte
,
32
)
offset1
[
31
]
=
64
length1
:=
make
([]
byte
,
32
)
length1
[
31
]
=
byte
(
len
(
str1
))
value1
:=
common
.
RightPadBytes
([]
byte
(
str1
),
32
)
offset2
:=
make
([]
byte
,
32
)
offset2
[
31
]
=
128
length2
:=
make
([]
byte
,
32
)
length2
[
31
]
=
byte
(
len
(
str2
))
value2
:=
common
.
RightPadBytes
([]
byte
(
str2
),
32
)
exp2
:=
append
(
offset1
,
offset2
...
)
exp2
=
append
(
exp2
,
append
(
length1
,
value1
...
)
...
)
exp2
=
append
(
exp2
,
append
(
length2
,
value2
...
)
...
)
// ignore first 4 bytes of the output. This is the function identifier
str2pack
=
str2pack
[
4
:
]
if
!
bytes
.
Equal
(
str2pack
,
exp2
)
{
t
.
Errorf
(
"expected %x, got %x
\n
"
,
exp
,
str2pack
)
}
// test two strings, first > 32, second < 32
str1
=
strings
.
Repeat
(
"a"
,
33
)
str2pack
,
err
=
abi
.
Pack
(
"strTwo"
,
str1
,
str2
)
if
err
!=
nil
{
t
.
Error
(
err
)
}
offset1
=
make
([]
byte
,
32
)
offset1
[
31
]
=
64
length1
=
make
([]
byte
,
32
)
length1
[
31
]
=
byte
(
len
(
str1
))
value1
=
common
.
RightPadBytes
([]
byte
(
str1
),
64
)
offset2
[
31
]
=
160
exp2
=
append
(
offset1
,
offset2
...
)
exp2
=
append
(
exp2
,
append
(
length1
,
value1
...
)
...
)
exp2
=
append
(
exp2
,
append
(
length2
,
value2
...
)
...
)
// ignore first 4 bytes of the output. This is the function identifier
str2pack
=
str2pack
[
4
:
]
if
!
bytes
.
Equal
(
str2pack
,
exp2
)
{
t
.
Errorf
(
"expected %x, got %x
\n
"
,
exp
,
str2pack
)
}
// test two strings, first > 32, second >32
str1
=
strings
.
Repeat
(
"a"
,
33
)
str2
=
strings
.
Repeat
(
"a"
,
33
)
str2pack
,
err
=
abi
.
Pack
(
"strTwo"
,
str1
,
str2
)
if
err
!=
nil
{
t
.
Error
(
err
)
}
offset1
=
make
([]
byte
,
32
)
offset1
[
31
]
=
64
length1
=
make
([]
byte
,
32
)
length1
[
31
]
=
byte
(
len
(
str1
))
value1
=
common
.
RightPadBytes
([]
byte
(
str1
),
64
)
offset2
=
make
([]
byte
,
32
)
offset2
[
31
]
=
160
length2
=
make
([]
byte
,
32
)
length2
[
31
]
=
byte
(
len
(
str2
))
value2
=
common
.
RightPadBytes
([]
byte
(
str2
),
64
)
exp2
=
append
(
offset1
,
offset2
...
)
exp2
=
append
(
exp2
,
append
(
length1
,
value1
...
)
...
)
exp2
=
append
(
exp2
,
append
(
length2
,
value2
...
)
...
)
// ignore first 4 bytes of the output. This is the function identifier
str2pack
=
str2pack
[
4
:
]
if
!
bytes
.
Equal
(
str2pack
,
exp2
)
{
t
.
Errorf
(
"expected %x, got %x
\n
"
,
exp
,
str2pack
)
}
}
func
TestInputFixedArrayAndVariableInputLength
(
t
*
testing
.
T
)
{
const
definition
=
`[
{ "type" : "function", "name" : "fixedArrStr", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr", "type" : "uint256[2]" } ] },
{ "type" : "function", "name" : "fixedArrBytes", "constant" : true, "inputs" : [ { "name" : "str", "type" : "bytes" }, { "name" : "fixedArr", "type" : "uint256[2]" } ] },
{ "type" : "function", "name" : "mixedArrStr", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr", "type": "uint256[2]" }, { "name" : "dynArr", "type": "uint256[]" } ] },
{ "type" : "function", "name" : "doubleFixedArrStr", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr1", "type": "uint256[2]" }, { "name" : "fixedArr2", "type": "uint256[3]" } ] },
{ "type" : "function", "name" : "multipleMixedArrStr", "constant" : true, "inputs" : [ { "name" : "str", "type" : "string" }, { "name" : "fixedArr1", "type": "uint256[2]" }, { "name" : "dynArr", "type" : "uint256[]" }, { "name" : "fixedArr2", "type" : "uint256[3]" } ] }
]`
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
if
err
!=
nil
{
t
.
Error
(
err
)
}
// test string, fixed array uint256[2]
strin
:=
"hello world"
arrin
:=
[
2
]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
)}
fixedArrStrPack
,
err
:=
abi
.
Pack
(
"fixedArrStr"
,
strin
,
arrin
)
if
err
!=
nil
{
t
.
Error
(
err
)
}
// generate expected output
offset
:=
make
([]
byte
,
32
)
offset
[
31
]
=
96
length
:=
make
([]
byte
,
32
)
length
[
31
]
=
byte
(
len
(
strin
))
strvalue
:=
common
.
RightPadBytes
([]
byte
(
strin
),
32
)
arrinvalue1
:=
common
.
LeftPadBytes
(
arrin
[
0
]
.
Bytes
(),
32
)
arrinvalue2
:=
common
.
LeftPadBytes
(
arrin
[
1
]
.
Bytes
(),
32
)
exp
:=
append
(
offset
,
arrinvalue1
...
)
exp
=
append
(
exp
,
arrinvalue2
...
)
exp
=
append
(
exp
,
append
(
length
,
strvalue
...
)
...
)
// ignore first 4 bytes of the output. This is the function identifier
fixedArrStrPack
=
fixedArrStrPack
[
4
:
]
if
!
bytes
.
Equal
(
fixedArrStrPack
,
exp
)
{
t
.
Errorf
(
"expected %x, got %x
\n
"
,
exp
,
fixedArrStrPack
)
}
// test byte array, fixed array uint256[2]
bytesin
:=
[]
byte
(
strin
)
arrin
=
[
2
]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
)}
fixedArrBytesPack
,
err
:=
abi
.
Pack
(
"fixedArrBytes"
,
bytesin
,
arrin
)
if
err
!=
nil
{
t
.
Error
(
err
)
}
// generate expected output
offset
=
make
([]
byte
,
32
)
offset
[
31
]
=
96
length
=
make
([]
byte
,
32
)
length
[
31
]
=
byte
(
len
(
strin
))
strvalue
=
common
.
RightPadBytes
([]
byte
(
strin
),
32
)
arrinvalue1
=
common
.
LeftPadBytes
(
arrin
[
0
]
.
Bytes
(),
32
)
arrinvalue2
=
common
.
LeftPadBytes
(
arrin
[
1
]
.
Bytes
(),
32
)
exp
=
append
(
offset
,
arrinvalue1
...
)
exp
=
append
(
exp
,
arrinvalue2
...
)
exp
=
append
(
exp
,
append
(
length
,
strvalue
...
)
...
)
// ignore first 4 bytes of the output. This is the function identifier
fixedArrBytesPack
=
fixedArrBytesPack
[
4
:
]
if
!
bytes
.
Equal
(
fixedArrBytesPack
,
exp
)
{
t
.
Errorf
(
"expected %x, got %x
\n
"
,
exp
,
fixedArrBytesPack
)
}
// test string, fixed array uint256[2], dynamic array uint256[]
strin
=
"hello world"
fixedarrin
:=
[
2
]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
)}
dynarrin
:=
[]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
),
big
.
NewInt
(
3
)}
mixedArrStrPack
,
err
:=
abi
.
Pack
(
"mixedArrStr"
,
strin
,
fixedarrin
,
dynarrin
)
if
err
!=
nil
{
t
.
Error
(
err
)
}
// generate expected output
stroffset
:=
make
([]
byte
,
32
)
stroffset
[
31
]
=
128
strlength
:=
make
([]
byte
,
32
)
strlength
[
31
]
=
byte
(
len
(
strin
))
strvalue
=
common
.
RightPadBytes
([]
byte
(
strin
),
32
)
fixedarrinvalue1
:=
common
.
LeftPadBytes
(
fixedarrin
[
0
]
.
Bytes
(),
32
)
fixedarrinvalue2
:=
common
.
LeftPadBytes
(
fixedarrin
[
1
]
.
Bytes
(),
32
)
dynarroffset
:=
make
([]
byte
,
32
)
dynarroffset
[
31
]
=
byte
(
160
+
((
len
(
strin
)
/
32
)
+
1
)
*
32
)
dynarrlength
:=
make
([]
byte
,
32
)
dynarrlength
[
31
]
=
byte
(
len
(
dynarrin
))
dynarrinvalue1
:=
common
.
LeftPadBytes
(
dynarrin
[
0
]
.
Bytes
(),
32
)
dynarrinvalue2
:=
common
.
LeftPadBytes
(
dynarrin
[
1
]
.
Bytes
(),
32
)
dynarrinvalue3
:=
common
.
LeftPadBytes
(
dynarrin
[
2
]
.
Bytes
(),
32
)
exp
=
append
(
stroffset
,
fixedarrinvalue1
...
)
exp
=
append
(
exp
,
fixedarrinvalue2
...
)
exp
=
append
(
exp
,
dynarroffset
...
)
exp
=
append
(
exp
,
append
(
strlength
,
strvalue
...
)
...
)
dynarrarg
:=
append
(
dynarrlength
,
dynarrinvalue1
...
)
dynarrarg
=
append
(
dynarrarg
,
dynarrinvalue2
...
)
dynarrarg
=
append
(
dynarrarg
,
dynarrinvalue3
...
)
exp
=
append
(
exp
,
dynarrarg
...
)
// ignore first 4 bytes of the output. This is the function identifier
mixedArrStrPack
=
mixedArrStrPack
[
4
:
]
if
!
bytes
.
Equal
(
mixedArrStrPack
,
exp
)
{
t
.
Errorf
(
"expected %x, got %x
\n
"
,
exp
,
mixedArrStrPack
)
}
// test string, fixed array uint256[2], fixed array uint256[3]
strin
=
"hello world"
fixedarrin1
:=
[
2
]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
)}
fixedarrin2
:=
[
3
]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
),
big
.
NewInt
(
3
)}
doubleFixedArrStrPack
,
err
:=
abi
.
Pack
(
"doubleFixedArrStr"
,
strin
,
fixedarrin1
,
fixedarrin2
)
if
err
!=
nil
{
t
.
Error
(
err
)
}
// generate expected output
stroffset
=
make
([]
byte
,
32
)
stroffset
[
31
]
=
192
strlength
=
make
([]
byte
,
32
)
strlength
[
31
]
=
byte
(
len
(
strin
))
strvalue
=
common
.
RightPadBytes
([]
byte
(
strin
),
32
)
fixedarrin1value1
:=
common
.
LeftPadBytes
(
fixedarrin1
[
0
]
.
Bytes
(),
32
)
fixedarrin1value2
:=
common
.
LeftPadBytes
(
fixedarrin1
[
1
]
.
Bytes
(),
32
)
fixedarrin2value1
:=
common
.
LeftPadBytes
(
fixedarrin2
[
0
]
.
Bytes
(),
32
)
fixedarrin2value2
:=
common
.
LeftPadBytes
(
fixedarrin2
[
1
]
.
Bytes
(),
32
)
fixedarrin2value3
:=
common
.
LeftPadBytes
(
fixedarrin2
[
2
]
.
Bytes
(),
32
)
exp
=
append
(
stroffset
,
fixedarrin1value1
...
)
exp
=
append
(
exp
,
fixedarrin1value2
...
)
exp
=
append
(
exp
,
fixedarrin2value1
...
)
exp
=
append
(
exp
,
fixedarrin2value2
...
)
exp
=
append
(
exp
,
fixedarrin2value3
...
)
exp
=
append
(
exp
,
append
(
strlength
,
strvalue
...
)
...
)
// ignore first 4 bytes of the output. This is the function identifier
doubleFixedArrStrPack
=
doubleFixedArrStrPack
[
4
:
]
if
!
bytes
.
Equal
(
doubleFixedArrStrPack
,
exp
)
{
t
.
Errorf
(
"expected %x, got %x
\n
"
,
exp
,
doubleFixedArrStrPack
)
}
// test string, fixed array uint256[2], dynamic array uint256[], fixed array uint256[3]
strin
=
"hello world"
fixedarrin1
=
[
2
]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
)}
dynarrin
=
[]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
)}
fixedarrin2
=
[
3
]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
),
big
.
NewInt
(
3
)}
multipleMixedArrStrPack
,
err
:=
abi
.
Pack
(
"multipleMixedArrStr"
,
strin
,
fixedarrin1
,
dynarrin
,
fixedarrin2
)
if
err
!=
nil
{
t
.
Error
(
err
)
}
// generate expected output
stroffset
=
make
([]
byte
,
32
)
stroffset
[
31
]
=
224
strlength
=
make
([]
byte
,
32
)
strlength
[
31
]
=
byte
(
len
(
strin
))
strvalue
=
common
.
RightPadBytes
([]
byte
(
strin
),
32
)
fixedarrin1value1
=
common
.
LeftPadBytes
(
fixedarrin1
[
0
]
.
Bytes
(),
32
)
fixedarrin1value2
=
common
.
LeftPadBytes
(
fixedarrin1
[
1
]
.
Bytes
(),
32
)
dynarroffset
=
U256
(
big
.
NewInt
(
int64
(
256
+
((
len
(
strin
)
/
32
)
+
1
)
*
32
)))
dynarrlength
=
make
([]
byte
,
32
)
dynarrlength
[
31
]
=
byte
(
len
(
dynarrin
))
dynarrinvalue1
=
common
.
LeftPadBytes
(
dynarrin
[
0
]
.
Bytes
(),
32
)
dynarrinvalue2
=
common
.
LeftPadBytes
(
dynarrin
[
1
]
.
Bytes
(),
32
)
fixedarrin2value1
=
common
.
LeftPadBytes
(
fixedarrin2
[
0
]
.
Bytes
(),
32
)
fixedarrin2value2
=
common
.
LeftPadBytes
(
fixedarrin2
[
1
]
.
Bytes
(),
32
)
fixedarrin2value3
=
common
.
LeftPadBytes
(
fixedarrin2
[
2
]
.
Bytes
(),
32
)
exp
=
append
(
stroffset
,
fixedarrin1value1
...
)
exp
=
append
(
exp
,
fixedarrin1value2
...
)
exp
=
append
(
exp
,
dynarroffset
...
)
exp
=
append
(
exp
,
fixedarrin2value1
...
)
exp
=
append
(
exp
,
fixedarrin2value2
...
)
exp
=
append
(
exp
,
fixedarrin2value3
...
)
exp
=
append
(
exp
,
append
(
strlength
,
strvalue
...
)
...
)
dynarrarg
=
append
(
dynarrlength
,
dynarrinvalue1
...
)
dynarrarg
=
append
(
dynarrarg
,
dynarrinvalue2
...
)
exp
=
append
(
exp
,
dynarrarg
...
)
// ignore first 4 bytes of the output. This is the function identifier
multipleMixedArrStrPack
=
multipleMixedArrStrPack
[
4
:
]
if
!
bytes
.
Equal
(
multipleMixedArrStrPack
,
exp
)
{
t
.
Errorf
(
"expected %x, got %x
\n
"
,
exp
,
multipleMixedArrStrPack
)
}
}
func
TestDefaultFunctionParsing
(
t
*
testing
.
T
)
{
const
definition
=
`[{ "name" : "balance" }]`
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
_
,
ok
:=
abi
.
Methods
[
"balance"
];
!
ok
{
t
.
Error
(
"expected 'balance' to be present"
)
}
}
func
TestBareEvents
(
t
*
testing
.
T
)
{
const
definition
=
`[
{ "type" : "event", "name" : "balance" },
{ "type" : "event", "name" : "anon", "anonymous" : true},
{ "type" : "event", "name" : "args", "inputs" : [{ "indexed":false, "name":"arg0", "type":"uint256" }, { "indexed":true, "name":"arg1", "type":"address" }] }
]`
arg0
,
_
:=
NewType
(
"uint256"
)
arg1
,
_
:=
NewType
(
"address"
)
expectedEvents
:=
map
[
string
]
struct
{
Anonymous
bool
Args
[]
Argument
}{
"balance"
:
{
false
,
nil
},
"anon"
:
{
true
,
nil
},
"args"
:
{
false
,
[]
Argument
{
{
Name
:
"arg0"
,
Type
:
arg0
,
Indexed
:
false
},
{
Name
:
"arg1"
,
Type
:
arg1
,
Indexed
:
true
},
}},
}
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
len
(
abi
.
Events
)
!=
len
(
expectedEvents
)
{
t
.
Fatalf
(
"invalid number of events after parsing, want %d, got %d"
,
len
(
expectedEvents
),
len
(
abi
.
Events
))
}
for
name
,
exp
:=
range
expectedEvents
{
got
,
ok
:=
abi
.
Events
[
name
]
if
!
ok
{
t
.
Errorf
(
"could not found event %s"
,
name
)
continue
}
if
got
.
Anonymous
!=
exp
.
Anonymous
{
t
.
Errorf
(
"invalid anonymous indication for event %s, want %v, got %v"
,
name
,
exp
.
Anonymous
,
got
.
Anonymous
)
}
if
len
(
got
.
Inputs
)
!=
len
(
exp
.
Args
)
{
t
.
Errorf
(
"invalid number of args, want %d, got %d"
,
len
(
exp
.
Args
),
len
(
got
.
Inputs
))
continue
}
for
i
,
arg
:=
range
exp
.
Args
{
if
arg
.
Name
!=
got
.
Inputs
[
i
]
.
Name
{
t
.
Errorf
(
"events[%s].Input[%d] has an invalid name, want %s, got %s"
,
name
,
i
,
arg
.
Name
,
got
.
Inputs
[
i
]
.
Name
)
}
if
arg
.
Indexed
!=
got
.
Inputs
[
i
]
.
Indexed
{
t
.
Errorf
(
"events[%s].Input[%d] has an invalid indexed indication, want %v, got %v"
,
name
,
i
,
arg
.
Indexed
,
got
.
Inputs
[
i
]
.
Indexed
)
}
if
arg
.
Type
.
T
!=
got
.
Inputs
[
i
]
.
Type
.
T
{
t
.
Errorf
(
"events[%s].Input[%d] has an invalid type, want %x, got %x"
,
name
,
i
,
arg
.
Type
.
T
,
got
.
Inputs
[
i
]
.
Type
.
T
)
}
}
}
}
// TestUnpackEvent is based on this contract:
// contract T {
// event received(address sender, uint amount, bytes memo);
// event receivedAddr(address sender);
// function receive(bytes memo) external payable {
// received(msg.sender, msg.value, memo);
// receivedAddr(msg.sender);
// }
// }
// When receive("X") is called with sender 0x00... and value 1, it produces this tx receipt:
// receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
func
TestUnpackEvent
(
t
*
testing
.
T
)
{
const
abiJSON
=
`[{"constant":false,"inputs":[{"name":"memo","type":"bytes"}],"name":"receive","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}],"name":"received","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"}],"name":"receivedAddr","type":"event"}]`
abi
,
err
:=
JSON
(
strings
.
NewReader
(
abiJSON
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
const
hexdata
=
`000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158`
data
,
err
:=
hex
.
DecodeString
(
hexdata
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
len
(
data
)
%
32
==
0
{
t
.
Errorf
(
"len(data) is %d, want a non-multiple of 32"
,
len
(
data
))
}
type
ReceivedEvent
struct
{
Address
common
.
Hash160Address
Amount
*
big
.
Int
Memo
[]
byte
}
var
ev
ReceivedEvent
err
=
abi
.
Unpack
(
&
ev
,
"received"
,
data
)
if
err
!=
nil
{
t
.
Error
(
err
)
}
else
{
t
.
Logf
(
"len(data): %d; received event: %+v"
,
len
(
data
),
ev
)
}
type
ReceivedAddrEvent
struct
{
Address
common
.
Hash160Address
}
var
receivedAddrEv
ReceivedAddrEvent
err
=
abi
.
Unpack
(
&
receivedAddrEv
,
"receivedAddr"
,
data
)
if
err
!=
nil
{
t
.
Error
(
err
)
}
else
{
t
.
Logf
(
"len(data): %d; received event: %+v"
,
len
(
data
),
receivedAddrEv
)
}
}
func
TestABI_MethodById
(
t
*
testing
.
T
)
{
const
abiJSON
=
`[
{"type":"function","name":"receive","constant":false,"inputs":[{"name":"memo","type":"bytes"}],"outputs":[],"payable":true,"stateMutability":"payable"},
{"type":"event","name":"received","anonymous":false,"inputs":[{"indexed":false,"name":"sender","type":"address"},{"indexed":false,"name":"amount","type":"uint256"},{"indexed":false,"name":"memo","type":"bytes"}]},
{"type":"function","name":"fixedArrStr","constant":true,"inputs":[{"name":"str","type":"string"},{"name":"fixedArr","type":"uint256[2]"}]},
{"type":"function","name":"fixedArrBytes","constant":true,"inputs":[{"name":"str","type":"bytes"},{"name":"fixedArr","type":"uint256[2]"}]},
{"type":"function","name":"mixedArrStr","constant":true,"inputs":[{"name":"str","type":"string"},{"name":"fixedArr","type":"uint256[2]"},{"name":"dynArr","type":"uint256[]"}]},
{"type":"function","name":"doubleFixedArrStr","constant":true,"inputs":[{"name":"str","type":"string"},{"name":"fixedArr1","type":"uint256[2]"},{"name":"fixedArr2","type":"uint256[3]"}]},
{"type":"function","name":"multipleMixedArrStr","constant":true,"inputs":[{"name":"str","type":"string"},{"name":"fixedArr1","type":"uint256[2]"},{"name":"dynArr","type":"uint256[]"},{"name":"fixedArr2","type":"uint256[3]"}]},
{"type":"function","name":"balance","constant":true},
{"type":"function","name":"send","constant":false,"inputs":[{"name":"amount","type":"uint256"}]},
{"type":"function","name":"test","constant":false,"inputs":[{"name":"number","type":"uint32"}]},
{"type":"function","name":"string","constant":false,"inputs":[{"name":"inputs","type":"string"}]},
{"type":"function","name":"bool","constant":false,"inputs":[{"name":"inputs","type":"bool"}]},
{"type":"function","name":"address","constant":false,"inputs":[{"name":"inputs","type":"address"}]},
{"type":"function","name":"uint64[2]","constant":false,"inputs":[{"name":"inputs","type":"uint64[2]"}]},
{"type":"function","name":"uint64[]","constant":false,"inputs":[{"name":"inputs","type":"uint64[]"}]},
{"type":"function","name":"foo","constant":false,"inputs":[{"name":"inputs","type":"uint32"}]},
{"type":"function","name":"bar","constant":false,"inputs":[{"name":"inputs","type":"uint32"},{"name":"string","type":"uint16"}]},
{"type":"function","name":"_slice","constant":false,"inputs":[{"name":"inputs","type":"uint32[2]"}]},
{"type":"function","name":"__slice256","constant":false,"inputs":[{"name":"inputs","type":"uint256[2]"}]},
{"type":"function","name":"sliceAddress","constant":false,"inputs":[{"name":"inputs","type":"address[]"}]},
{"type":"function","name":"sliceMultiAddress","constant":false,"inputs":[{"name":"a","type":"address[]"},{"name":"b","type":"address[]"}]}
]
`
abi
,
err
:=
JSON
(
strings
.
NewReader
(
abiJSON
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
for
name
,
m
:=
range
abi
.
Methods
{
a
:=
fmt
.
Sprintf
(
"%v"
,
m
)
m2
,
err
:=
abi
.
MethodByID
(
m
.
ID
())
if
err
!=
nil
{
t
.
Fatalf
(
"Failed to look up ABI method: %v"
,
err
)
}
b
:=
fmt
.
Sprintf
(
"%v"
,
m2
)
if
a
!=
b
{
t
.
Errorf
(
"Method %v (id %v) not 'findable' by id in ABI"
,
name
,
common
.
Bytes2Hex
(
m
.
ID
()))
}
}
// Also test empty
if
_
,
err
:=
abi
.
MethodByID
([]
byte
{
0x00
});
err
==
nil
{
t
.
Errorf
(
"Expected error, too short to decode data"
)
}
if
_
,
err
:=
abi
.
MethodByID
([]
byte
{});
err
==
nil
{
t
.
Errorf
(
"Expected error, too short to decode data"
)
}
if
_
,
err
:=
abi
.
MethodByID
(
nil
);
err
==
nil
{
t
.
Errorf
(
"Expected error, nil is short to decode data"
)
}
}
plugin/dapp/evm/executor/abi/api.go
0 → 100644
View file @
b2ebdcd4
package
abi
import
(
"encoding/json"
"fmt"
"math/big"
"reflect"
"strconv"
"strings"
"errors"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/golang-collections/collections/stack"
)
// Pack 使用ABI方式调用时,将调用方式转换为EVM底层处理的十六进制编码
// abiData 完整的ABI定义
// param 调用方法及参数
// readOnly 是否只读,如果调用的方法不为只读,则报错
// 调用方式: foo(param1,param2)
func
Pack
(
param
,
abiData
string
,
readOnly
bool
)
(
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
}
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
{
// 首先检查参数个数和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
,
methodName
,
abiData
string
)
(
output
string
,
err
error
)
{
if
len
(
data
)
==
0
{
return
output
,
err
}
// 解析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
)
}
if
method
.
Outputs
.
LengthNonIndexed
()
==
0
{
return
output
,
err
}
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
}
// Param 返回值参数结构定义
type
Param
struct
{
// Name 参数名称
Name
string
`json:"name"`
// Type 参数类型
Type
string
`json:"type"`
// Value 参数取值
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
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
val
}
return
val
}
// 从字符串格式的输入参数取值(单个),获取Go类型的
func
str2GoValue
(
typ
Type
,
val
string
)
(
res
interface
{},
err
error
)
{
switch
typ
.
T
{
case
IntTy
:
if
typ
.
Size
<
256
{
x
,
err
:=
strconv
.
ParseInt
(
val
,
10
,
typ
.
Size
)
if
err
!=
nil
{
return
res
,
err
}
return
convertInt
(
x
,
typ
.
Kind
),
nil
}
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
)
if
err
!=
nil
{
return
res
,
err
}
return
convertUint
(
x
,
typ
.
Kind
),
nil
}
b
:=
new
(
big
.
Int
)
b
.
SetString
(
val
,
10
)
return
b
,
err
case
BoolTy
:
x
,
err
:=
strconv
.
ParseBool
(
val
)
if
err
!=
nil
{
return
res
,
err
}
return
x
,
nil
case
StringTy
:
return
val
,
nil
case
SliceTy
:
subs
,
err
:=
procArrayItem
(
val
)
if
err
!=
nil
{
return
res
,
err
}
rval
:=
reflect
.
MakeSlice
(
typ
.
Type
,
len
(
subs
),
len
(
subs
))
for
idx
,
sub
:=
range
subs
{
subVal
,
er
:=
str2GoValue
(
*
typ
.
Elem
,
sub
)
if
er
!=
nil
{
return
res
,
er
}
rval
.
Index
(
idx
)
.
Set
(
reflect
.
ValueOf
(
subVal
))
}
return
rval
.
Interface
(),
nil
case
ArrayTy
:
rval
:=
reflect
.
New
(
typ
.
Type
)
.
Elem
()
subs
,
err
:=
procArrayItem
(
val
)
if
err
!=
nil
{
return
res
,
err
}
for
idx
,
sub
:=
range
subs
{
subVal
,
er
:=
str2GoValue
(
*
typ
.
Elem
,
sub
)
if
er
!=
nil
{
return
res
,
er
}
rval
.
Index
(
idx
)
.
Set
(
reflect
.
ValueOf
(
subVal
))
}
return
rval
.
Interface
(),
nil
case
AddressTy
:
addr
:=
common
.
StringToAddress
(
val
)
if
addr
==
nil
{
return
res
,
fmt
.
Errorf
(
"invalid address: %v"
,
val
)
}
return
addr
.
ToHash160
(),
nil
case
FixedBytesTy
:
// 固定长度多字节,输入时以十六进制方式表示,如 0xabcd00ff
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
,
nil
case
HashTy
:
// 哈希类型,也是以十六进制为输入,如:0xabcdef
x
,
err
:=
common
.
HexToBytes
(
val
)
if
err
!=
nil
{
return
res
,
err
}
return
common
.
BytesToHash
(
x
),
nil
default
:
return
res
,
fmt
.
Errorf
(
"not support type: %v"
,
typ
.
stringKind
)
}
}
// 本方法可以将一个表示数组的字符串,经过处理后,返回数组内的字面元素;
// 如果数组为多层,则只返回第一级
// 例如:"[a,b,c]" -> "a","b","c"
// 例如:"[[a,b],[c,d]]" -> "[a,b]", "[c,d]"
// 因为格式比较复杂,正则表达式不适合处理,所以使用栈的方式来处理
func
procArrayItem
(
val
string
)
(
res
[]
string
,
err
error
)
{
ss
:=
stack
.
New
()
data
:=
[]
rune
{}
for
_
,
b
:=
range
val
{
switch
b
{
case
' '
:
// 只有字符串元素中间的空格才是有效的
if
ss
.
Len
()
>
0
&&
peekRune
(
ss
)
==
'"'
{
data
=
append
(
data
,
b
)
}
case
','
:
// 逗号有可能是多级数组里面的分隔符,我们只处理最外层数组的分隔,
// 因此,需要判断当前栈中是否只有一个'[',否则就当做普通内容对待
if
ss
.
Len
()
==
1
&&
peekRune
(
ss
)
==
'['
{
// 当前元素结束
res
=
append
(
res
,
string
(
data
))
data
=
[]
rune
{}
}
else
{
data
=
append
(
data
,
b
)
}
case
'"'
:
// 双引号首次出现时需要入栈,下次出现时需要将两者之间的内容进行拼接
if
ss
.
Peek
()
==
b
{
ss
.
Pop
()
}
else
{
ss
.
Push
(
b
)
}
//data = append(data, b)
case
'['
:
// 只有当栈为空时,'['才会当做数组的开始,否则全部视作普通内容
if
ss
.
Len
()
==
0
{
data
=
[]
rune
{}
}
else
{
data
=
append
(
data
,
b
)
}
ss
.
Push
(
b
)
case
']'
:
// 只有当栈中只有一个']'时,才会被当做数组结束,否则就当做普通内容对待
if
ss
.
Len
()
==
1
&&
peekRune
(
ss
)
==
'['
{
// 整个数组结束
res
=
append
(
res
,
string
(
data
))
}
else
{
data
=
append
(
data
,
b
)
}
ss
.
Pop
()
default
:
// 其它情况全部视作普通内容
data
=
append
(
data
,
b
)
}
}
if
ss
.
Len
()
!=
0
{
return
nil
,
fmt
.
Errorf
(
"invalid array format:%v"
,
val
)
}
return
res
,
err
}
func
peekRune
(
ss
*
stack
.
Stack
)
rune
{
return
ss
.
Peek
()
.
(
rune
)
}
// 解析方法调用字符串,返回方法名以及方法参数
// 例如: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
0 → 100644
View file @
b2ebdcd4
package
abi
import
(
"bytes"
"fmt"
"reflect"
"testing"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/stretchr/testify/assert"
)
func
TestABI_Pack
(
t
*
testing
.
T
)
{
abiData
:=
`[{"constant":false,"inputs":[],"Name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"Name":"newValue","type":"uint256"}],"Name":"set","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"Name":"get","outputs":[{"Name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]`
for
_
,
test
:=
range
[]
struct
{
input
string
output
string
}{
{
"get()"
,
"0x6d4ce63c"
,
},
{
"kill()"
,
"0x41c0e1b5"
,
},
{
"set(100)"
,
"0x60fe47b10000000000000000000000000000000000000000000000000000000000000064"
,
},
{
`set("100")`
,
"0x60fe47b10000000000000000000000000000000000000000000000000000000000000064"
,
},
}
{
_
,
data
,
err
:=
Pack
(
test
.
input
,
abiData
,
false
)
assert
.
NoError
(
t
,
err
)
assert
.
EqualValues
(
t
,
test
.
output
,
common
.
Bytes2Hex
(
data
))
}
}
func
TestABI_Unpack
(
t
*
testing
.
T
)
{
abiData
:=
`[{"constant":false,"inputs":[],"Name":"get1","outputs":[{"Name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"Name":"f","outputs":[{"Name":"","type":"uint256"},{"Name":"","type":"bool"},{"Name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"Name":"_a","type":"uint256"},{"Name":"_b","type":"uint256"}],"Name":"arithmetics","outputs":[{"Name":"o_sum","type":"uint256"},{"Name":"o_product","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[{"Name":"index","type":"uint256"}],"Name":"getUser","outputs":[{"Name":"","type":"uint256"},{"Name":"","type":"string"},{"Name":"","type":"string"},{"Name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"Name":"get2","outputs":[{"Name":"_winningProposal","type":"uint8"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]`
for
_
,
test
:=
range
[]
struct
{
method
string
input
string
output
string
}{
{
"get1"
,
"0x0000000000000000000000000000000000000000000000000000000000000021"
,
`[{"name":"","type":"uint256","value":33}]`
,
},
{
"get2"
,
"0x0000000000000000000000000000000000000000000000000000000000000021"
,
`[{"name":"_winningProposal","type":"uint8","value":33}]`
,
},
{
"arithmetics"
,
"0x000000000000000000000000000000000000000000000000000000000000002100000000000000000000000000000000000000000000000000000000000000f2"
,
`[{"name":"o_sum","type":"uint256","value":33},{"name":"o_product","type":"uint256","value":242}]`
,
},
{
"f"
,
"0x000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
`[{"name":"","type":"uint256","value":7},{"name":"","type":"bool","value":true},{"name":"","type":"uint256","value":2}]`
,
},
{
"getUser"
,
"0x0000000000000000000000000000000000000000000000000000000000000021000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000032dcd5000000000000000000000000000000000000000000000000000000000000000a75736572732e6e616d6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001175736572732e7573657241646472657373000000000000000000000000000000"
,
`[{"name":"","type":"uint256","value":33},{"name":"","type":"string","value":"users.name"},{"name":"","type":"string","value":"users.userAddress"},{"name":"","type":"uint256","value":3333333}]`
,
},
}
{
data
,
err
:=
Unpack
(
common
.
FromHex
(
test
.
input
),
test
.
method
,
abiData
)
assert
.
NoError
(
t
,
err
)
assert
.
EqualValues
(
t
,
test
.
output
,
data
)
}
}
func
TestProcFuncCall
(
t
*
testing
.
T
)
{
for
_
,
test
:=
range
[]
struct
{
input
string
funcName
string
params
[]
string
}{
{
"foo(1,2,3)"
,
"foo"
,
[]
string
{
"1"
,
"2"
,
"3"
},
},
{
"foo()"
,
"foo"
,
nil
,
},
{
`foo("a",1,[1,2,3])`
,
"foo"
,
[]
string
{
"a"
,
"1"
,
"[1,2,3]"
},
},
}
{
fn
,
res
,
err
:=
procFuncCall
(
test
.
input
)
assert
.
NoError
(
t
,
err
,
"process array string error"
)
assert
.
EqualValues
(
t
,
test
.
funcName
,
fn
,
"parse array string error"
)
assert
.
EqualValues
(
t
,
test
.
params
,
res
,
"parse array string error"
)
}
}
// TestProcArray 测试根据ABI解析数组结构的逻辑
func
TestProcArray
(
t
*
testing
.
T
)
{
for
_
,
test
:=
range
[]
struct
{
input
string
output
[]
string
}{
{
"[1,2,3]"
,
[]
string
{
"1"
,
"2"
,
"3"
},
},
{
"[[1,2,3],[4,5]]"
,
[]
string
{
"[1,2,3]"
,
"[4,5]"
},
},
{
`["abc","def", "x,y, z"]`
,
[]
string
{
"abc"
,
"def"
,
"x,y, z"
},
},
{
`["[1,2,3]"]`
,
[]
string
{
"[1,2,3]"
},
},
}
{
res
,
err
:=
procArrayItem
(
test
.
input
)
assert
.
NoError
(
t
,
err
,
"process array string error"
)
assert
.
EqualValues
(
t
,
test
.
output
,
res
,
"parse array string error"
)
}
}
// Test_GoValue 测试从字符串依据ABI类型定义,转换为正确的类型并编码的逻辑
func
Test_GoValue
(
t
*
testing
.
T
)
{
for
i
,
test
:=
range
[]
struct
{
typ
string
input
string
output
[]
byte
}{
{
"uint8"
,
"2"
,
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint8[]"
,
"[1, 2]"
,
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint16"
,
"2"
,
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint16[]"
,
"[1, 2]"
,
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint32"
,
"2"
,
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint32[]"
,
"[1, 2]"
,
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint64"
,
"2"
,
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint64[]"
,
"[1,2]"
,
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint256"
,
"2"
,
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint256[]"
,
"[1,2]"
,
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int8"
,
"2"
,
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int8[]"
,
"[1,2]"
,
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int16"
,
"2"
,
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int16[]"
,
"[1,2]"
,
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int32"
,
"2"
,
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int32[]"
,
"[1,2]"
,
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int64"
,
"2"
,
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int64[]"
,
"[1,2]"
,
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int256"
,
"2"
,
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int256[]"
,
"[1,2]"
,
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"bytes1"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes2"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes3"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes4"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes5"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes6"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes7"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes8"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes9"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes10"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes11"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes12"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes13"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes14"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes15"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes16"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes17"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes18"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes19"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes20"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes21"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes22"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes23"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes24"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes24"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes25"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes26"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes27"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes28"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes29"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes30"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes31"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes32"
,
"0x01"
,
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"uint32[2][3][4]"
,
"[[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]], [[13, 14], [15, 16], [17, 18]], [[19, 20], [21, 22], [23, 24]]]"
,
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018"
),
},
{
"address"
,
common
.
Hash160Address
{
1
}
.
ToAddress
()
.
String
(),
common
.
Hex2Bytes
(
"0000000000000000000000000100000000000000000000000000000000000000"
),
},
{
"address[]"
,
fmt
.
Sprintf
(
"[%v,%v]"
,
common
.
Hash160Address
{
1
}
.
ToAddress
(),
common
.
Hash160Address
{
2
}
.
ToAddress
()),
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000"
),
},
{
"bytes32[]"
,
//[]common.Hash{{1}, {2}},
"[0x01, 0x02]"
,
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000"
),
},
{
"string"
,
"foobar"
,
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000"
),
},
}
{
typ
,
err
:=
NewType
(
test
.
typ
)
if
err
!=
nil
{
t
.
Fatalf
(
"%v failed. Unexpected new type error: %v"
,
i
,
err
)
}
value
,
err
:=
str2GoValue
(
typ
,
test
.
input
)
if
err
!=
nil
{
t
.
Fatalf
(
"%v failed. Unexpected parse go Value error: %v"
,
i
,
err
)
}
output
,
err
:=
typ
.
pack
(
reflect
.
ValueOf
(
value
))
if
err
!=
nil
{
t
.
Fatalf
(
"%v failed. Unexpected pack error: %v"
,
i
,
err
)
}
if
!
bytes
.
Equal
(
output
,
test
.
output
)
{
t
.
Errorf
(
"%d failed. Expected bytes: '%x' Got: '%x'"
,
i
,
test
.
output
,
output
)
}
}
}
plugin/dapp/evm/executor/abi/argument.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"encoding/json"
"fmt"
"reflect"
"strings"
)
// Argument holds the name of the argument and the corresponding type.
// Types are used when packing and testing arguments.
type
Argument
struct
{
Name
string
Type
Type
Indexed
bool
// indexed is only used by events
}
// Arguments Argument slice type
type
Arguments
[]
Argument
// UnmarshalJSON implements json.Unmarshaler interface
func
(
argument
*
Argument
)
UnmarshalJSON
(
data
[]
byte
)
error
{
var
extarg
struct
{
Name
string
Type
string
Indexed
bool
}
err
:=
json
.
Unmarshal
(
data
,
&
extarg
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"argument json err: %v"
,
err
)
}
argument
.
Type
,
err
=
NewType
(
extarg
.
Type
)
if
err
!=
nil
{
return
err
}
argument
.
Name
=
extarg
.
Name
argument
.
Indexed
=
extarg
.
Indexed
return
nil
}
// LengthNonIndexed returns the number of arguments when not counting 'indexed' ones. Only events
// can ever have 'indexed' arguments, it should always be false on arguments for method input/output
func
(
arguments
Arguments
)
LengthNonIndexed
()
int
{
out
:=
0
for
_
,
arg
:=
range
arguments
{
if
!
arg
.
Indexed
{
out
++
}
}
return
out
}
// NonIndexed returns the arguments with indexed arguments filtered out
func
(
arguments
Arguments
)
NonIndexed
()
Arguments
{
var
ret
[]
Argument
for
_
,
arg
:=
range
arguments
{
if
!
arg
.
Indexed
{
ret
=
append
(
ret
,
arg
)
}
}
return
ret
}
// isTuple returns true for non-atomic constructs, like (uint,uint) or uint[]
func
(
arguments
Arguments
)
isTuple
()
bool
{
return
len
(
arguments
)
>
1
}
// Unpack performs the operation hexdata -> Go format
func
(
arguments
Arguments
)
Unpack
(
v
interface
{},
data
[]
byte
)
error
{
// make sure the passed value is arguments pointer
if
reflect
.
Ptr
!=
reflect
.
ValueOf
(
v
)
.
Kind
()
{
return
fmt
.
Errorf
(
"abi: Unpack(non-pointer %T)"
,
v
)
}
marshalledValues
,
err
:=
arguments
.
UnpackValues
(
data
)
if
err
!=
nil
{
return
err
}
if
arguments
.
isTuple
()
{
return
arguments
.
unpackTuple
(
v
,
marshalledValues
)
}
return
arguments
.
unpackAtomic
(
v
,
marshalledValues
)
}
func
(
arguments
Arguments
)
unpackTuple
(
v
interface
{},
marshalledValues
[]
interface
{})
error
{
var
(
value
=
reflect
.
ValueOf
(
v
)
.
Elem
()
typ
=
value
.
Type
()
kind
=
value
.
Kind
()
)
if
err
:=
requireUnpackKind
(
value
,
typ
,
kind
,
arguments
);
err
!=
nil
{
return
err
}
// If the interface is a struct, get of abi->struct_field mapping
var
abi2struct
map
[
string
]
string
if
kind
==
reflect
.
Struct
{
var
err
error
abi2struct
,
err
=
mapAbiToStructFields
(
arguments
,
value
)
if
err
!=
nil
{
return
err
}
}
for
i
,
arg
:=
range
arguments
.
NonIndexed
()
{
reflectValue
:=
reflect
.
ValueOf
(
marshalledValues
[
i
])
switch
kind
{
case
reflect
.
Struct
:
if
structField
,
ok
:=
abi2struct
[
arg
.
Name
];
ok
{
if
err
:=
set
(
value
.
FieldByName
(
structField
),
reflectValue
,
arg
);
err
!=
nil
{
return
err
}
}
case
reflect
.
Slice
,
reflect
.
Array
:
if
value
.
Len
()
<
i
{
return
fmt
.
Errorf
(
"abi: insufficient number of arguments for unpack, want %d, got %d"
,
len
(
arguments
),
value
.
Len
())
}
v
:=
value
.
Index
(
i
)
if
err
:=
requireAssignable
(
v
,
reflectValue
);
err
!=
nil
{
return
err
}
if
err
:=
set
(
v
.
Elem
(),
reflectValue
,
arg
);
err
!=
nil
{
return
err
}
default
:
return
fmt
.
Errorf
(
"abi:[2] cannot unmarshal tuple in to %v"
,
typ
)
}
}
return
nil
}
// unpackAtomic unpacks ( hexdata -> go ) a single value
func
(
arguments
Arguments
)
unpackAtomic
(
v
interface
{},
marshalledValues
[]
interface
{})
error
{
if
len
(
marshalledValues
)
!=
1
{
return
fmt
.
Errorf
(
"abi: wrong length, expected single value, got %d"
,
len
(
marshalledValues
))
}
elem
:=
reflect
.
ValueOf
(
v
)
.
Elem
()
kind
:=
elem
.
Kind
()
reflectValue
:=
reflect
.
ValueOf
(
marshalledValues
[
0
])
var
abi2struct
map
[
string
]
string
if
kind
==
reflect
.
Struct
{
var
err
error
if
abi2struct
,
err
=
mapAbiToStructFields
(
arguments
,
elem
);
err
!=
nil
{
return
err
}
arg
:=
arguments
.
NonIndexed
()[
0
]
if
structField
,
ok
:=
abi2struct
[
arg
.
Name
];
ok
{
return
set
(
elem
.
FieldByName
(
structField
),
reflectValue
,
arg
)
}
return
nil
}
return
set
(
elem
,
reflectValue
,
arguments
.
NonIndexed
()[
0
])
}
// Computes the full size of an array;
// i.e. counting nested arrays, which count towards size for unpacking.
func
getArraySize
(
arr
*
Type
)
int
{
size
:=
arr
.
Size
// Arrays can be nested, with each element being the same size
arr
=
arr
.
Elem
for
arr
.
T
==
ArrayTy
{
// Keep multiplying by elem.Size while the elem is an array.
size
*=
arr
.
Size
arr
=
arr
.
Elem
}
// Now we have the full array size, including its children.
return
size
}
// UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification,
// without supplying a struct to unpack into. Instead, this method returns a list containing the
// values. An atomic argument will be a list with one element.
func
(
arguments
Arguments
)
UnpackValues
(
data
[]
byte
)
([]
interface
{},
error
)
{
retval
:=
make
([]
interface
{},
0
,
arguments
.
LengthNonIndexed
())
virtualArgs
:=
0
for
index
,
arg
:=
range
arguments
.
NonIndexed
()
{
marshalledValue
,
err
:=
toGoType
((
index
+
virtualArgs
)
*
32
,
arg
.
Type
,
data
)
if
arg
.
Type
.
T
==
ArrayTy
{
// If we have a static array, like [3]uint256, these are coded as
// just like uint256,uint256,uint256.
// This means that we need to add two 'virtual' arguments when
// we count the index from now on.
//
// Array values nested multiple levels deep are also encoded inline:
// [2][3]uint256: uint256,uint256,uint256,uint256,uint256,uint256
//
// Calculate the full array size to get the correct offset for the next argument.
// Decrement it by 1, as the normal index increment is still applied.
virtualArgs
+=
getArraySize
(
&
arg
.
Type
)
-
1
}
if
err
!=
nil
{
return
nil
,
err
}
retval
=
append
(
retval
,
marshalledValue
)
}
return
retval
,
nil
}
// PackValues performs the operation Go format -> Hexdata
// It is the semantic opposite of UnpackValues
func
(
arguments
Arguments
)
PackValues
(
args
[]
interface
{})
([]
byte
,
error
)
{
return
arguments
.
Pack
(
args
...
)
}
// Pack performs the operation Go format -> Hexdata
func
(
arguments
Arguments
)
Pack
(
args
...
interface
{})
([]
byte
,
error
)
{
// Make sure arguments match up and pack them
abiArgs
:=
arguments
if
len
(
args
)
!=
len
(
abiArgs
)
{
return
nil
,
fmt
.
Errorf
(
"argument count mismatch: %d for %d"
,
len
(
args
),
len
(
abiArgs
))
}
// variable input is the output appended at the end of packed
// output. This is used for strings and bytes types input.
var
variableInput
[]
byte
// input offset is the bytes offset for packed output
inputOffset
:=
0
for
_
,
abiArg
:=
range
abiArgs
{
if
abiArg
.
Type
.
T
==
ArrayTy
{
inputOffset
+=
32
*
abiArg
.
Type
.
Size
}
else
{
inputOffset
+=
32
}
}
var
ret
[]
byte
for
i
,
a
:=
range
args
{
input
:=
abiArgs
[
i
]
// pack the input
packed
,
err
:=
input
.
Type
.
pack
(
reflect
.
ValueOf
(
a
))
if
err
!=
nil
{
return
nil
,
err
}
// check for a slice type (string, bytes, slice)
if
input
.
Type
.
requiresLengthPrefix
()
{
// calculate the offset
offset
:=
inputOffset
+
len
(
variableInput
)
// set the offset
ret
=
append
(
ret
,
packNum
(
reflect
.
ValueOf
(
offset
))
...
)
// Append the packed output to the variable input. The variable input
// will be appended at the end of the input.
variableInput
=
append
(
variableInput
,
packed
...
)
}
else
{
// append the packed value to the input
ret
=
append
(
ret
,
packed
...
)
}
}
// append the variable input at the end of the packed input
ret
=
append
(
ret
,
variableInput
...
)
return
ret
,
nil
}
// capitalise makes the first character of a string upper case, also removing any
// prefixing underscores from the variable names.
func
capitalise
(
input
string
)
string
{
for
len
(
input
)
>
0
&&
input
[
0
]
==
'_'
{
input
=
input
[
1
:
]
}
if
len
(
input
)
==
0
{
return
""
}
return
strings
.
ToUpper
(
input
[
:
1
])
+
input
[
1
:
]
}
plugin/dapp/evm/executor/abi/error.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"errors"
"fmt"
"reflect"
)
var
(
errBadBool
=
errors
.
New
(
"abi: improperly encoded boolean value"
)
)
// formatSliceString formats the reflection kind with the given slice size
// and returns a formatted string representation.
func
formatSliceString
(
kind
reflect
.
Kind
,
sliceSize
int
)
string
{
if
sliceSize
==
-
1
{
return
fmt
.
Sprintf
(
"[]%v"
,
kind
)
}
return
fmt
.
Sprintf
(
"[%d]%v"
,
sliceSize
,
kind
)
}
// sliceTypeCheck checks that the given slice can by assigned to the reflection
// type in t.
func
sliceTypeCheck
(
t
Type
,
val
reflect
.
Value
)
error
{
if
val
.
Kind
()
!=
reflect
.
Slice
&&
val
.
Kind
()
!=
reflect
.
Array
{
return
typeErr
(
formatSliceString
(
t
.
Kind
,
t
.
Size
),
val
.
Type
())
}
if
t
.
T
==
ArrayTy
&&
val
.
Len
()
!=
t
.
Size
{
return
typeErr
(
formatSliceString
(
t
.
Elem
.
Kind
,
t
.
Size
),
formatSliceString
(
val
.
Type
()
.
Elem
()
.
Kind
(),
val
.
Len
()))
}
if
t
.
Elem
.
T
==
SliceTy
{
if
val
.
Len
()
>
0
{
return
sliceTypeCheck
(
*
t
.
Elem
,
val
.
Index
(
0
))
}
}
else
if
t
.
Elem
.
T
==
ArrayTy
{
return
sliceTypeCheck
(
*
t
.
Elem
,
val
.
Index
(
0
))
}
if
elemKind
:=
val
.
Type
()
.
Elem
()
.
Kind
();
elemKind
!=
t
.
Elem
.
Kind
{
return
typeErr
(
formatSliceString
(
t
.
Elem
.
Kind
,
t
.
Size
),
val
.
Type
())
}
return
nil
}
// typeCheck checks that the given reflection value can be assigned to the reflection
// type in t.
func
typeCheck
(
t
Type
,
value
reflect
.
Value
)
error
{
if
t
.
T
==
SliceTy
||
t
.
T
==
ArrayTy
{
return
sliceTypeCheck
(
t
,
value
)
}
// Check base type validity. Element types will be checked later on.
if
t
.
Kind
!=
value
.
Kind
()
{
return
typeErr
(
t
.
Kind
,
value
.
Kind
())
}
else
if
t
.
T
==
FixedBytesTy
&&
t
.
Size
!=
value
.
Len
()
{
return
typeErr
(
t
.
Type
,
value
.
Type
())
}
else
{
return
nil
}
}
// typeErr returns a formatted type casting error.
func
typeErr
(
expected
,
got
interface
{})
error
{
return
fmt
.
Errorf
(
"abi: cannot use %v as type %v as argument"
,
got
,
expected
)
}
plugin/dapp/evm/executor/abi/event.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"fmt"
"strings"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common/crypto"
)
// Event is an event potentially triggered by the EVM's LOG mechanism. The Event
// holds type information (inputs) about the yielded output. Anonymous events
// don't get the signature canonical representation as the first LOG topic.
type
Event
struct
{
Name
string
Anonymous
bool
Inputs
Arguments
}
func
(
e
Event
)
String
()
string
{
inputs
:=
make
([]
string
,
len
(
e
.
Inputs
))
for
i
,
input
:=
range
e
.
Inputs
{
inputs
[
i
]
=
fmt
.
Sprintf
(
"%v %v"
,
input
.
Name
,
input
.
Type
)
if
input
.
Indexed
{
inputs
[
i
]
=
fmt
.
Sprintf
(
"%v indexed %v"
,
input
.
Name
,
input
.
Type
)
}
}
return
fmt
.
Sprintf
(
"e %v(%v)"
,
e
.
Name
,
strings
.
Join
(
inputs
,
", "
))
}
// ID returns the canonical representation of the event's signature used by the
// abi definition to identify event names and types.
func
(
e
Event
)
ID
()
common
.
Hash
{
types
:=
make
([]
string
,
len
(
e
.
Inputs
))
i
:=
0
for
_
,
input
:=
range
e
.
Inputs
{
types
[
i
]
=
input
.
Type
.
String
()
i
++
}
return
common
.
BytesToHash
(
crypto
.
Keccak256
([]
byte
(
fmt
.
Sprintf
(
"%v(%v)"
,
e
.
Name
,
strings
.
Join
(
types
,
","
)))))
}
plugin/dapp/evm/executor/abi/event_test.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"bytes"
"encoding/hex"
"encoding/json"
"math/big"
"reflect"
"strings"
"testing"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common/crypto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var
jsonEventTransfer
=
[]
byte
(
`{
"anonymous": false,
"inputs": [
{
"indexed": true, "name": "from", "type": "address"
}, {
"indexed": true, "name": "to", "type": "address"
}, {
"indexed": false, "name": "value", "type": "uint256"
}],
"name": "Transfer",
"type": "event"
}`
)
var
jsonEventPledge
=
[]
byte
(
`{
"anonymous": false,
"inputs": [{
"indexed": false, "name": "who", "type": "address"
}, {
"indexed": false, "name": "wad", "type": "uint128"
}, {
"indexed": false, "name": "currency", "type": "bytes3"
}],
"name": "Pledge",
"type": "event"
}`
)
var
jsonEventMixedCase
=
[]
byte
(
`{
"anonymous": false,
"inputs": [{
"indexed": false, "name": "value", "type": "uint256"
}, {
"indexed": false, "name": "_value", "type": "uint256"
}, {
"indexed": false, "name": "Value", "type": "uint256"
}],
"name": "MixedCase",
"type": "event"
}`
)
// 1000000
var
transferData1
=
"00000000000000000000000000000000000000000000000000000000000f4240"
// "0x00Ce0d46d924CC8437c806721496599FC3FFA268", 2218516807680, "usd"
var
pledgeData1
=
"00000000000000000000000000ce0d46d924cc8437c806721496599fc3ffa2680000000000000000000000000000000000000000000000000000020489e800007573640000000000000000000000000000000000000000000000000000000000"
// 1000000,2218516807680,1000001
var
mixedCaseData1
=
"00000000000000000000000000000000000000000000000000000000000f42400000000000000000000000000000000000000000000000000000020489e8000000000000000000000000000000000000000000000000000000000000000f4241"
func
TestEventId
(
t
*
testing
.
T
)
{
var
table
=
[]
struct
{
definition
string
expectations
map
[
string
]
common
.
Hash
}{
{
definition
:
`[
{ "type" : "event", "name" : "balance", "inputs": [{ "name" : "in", "type": "uint256" }] },
{ "type" : "event", "name" : "check", "inputs": [{ "name" : "t", "type": "address" }, { "name": "b", "type": "uint256" }] }
]`
,
expectations
:
map
[
string
]
common
.
Hash
{
"balance"
:
crypto
.
Keccak256Hash
([]
byte
(
"balance(uint256)"
)),
"check"
:
crypto
.
Keccak256Hash
([]
byte
(
"check(address,uint256)"
)),
},
},
}
for
_
,
test
:=
range
table
{
abi
,
err
:=
JSON
(
strings
.
NewReader
(
test
.
definition
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
for
name
,
event
:=
range
abi
.
Events
{
if
event
.
ID
()
!=
test
.
expectations
[
name
]
{
t
.
Errorf
(
"expected id to be %x, got %x"
,
test
.
expectations
[
name
],
event
.
ID
())
}
}
}
}
// TestEventMultiValueWithArrayUnpack verifies that array fields will be counted after parsing array.
func
TestEventMultiValueWithArrayUnpack
(
t
*
testing
.
T
)
{
definition
:=
`[{"name": "test", "type": "event", "inputs": [{"indexed": false, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
type
testStruct
struct
{
Value1
[
2
]
uint8
Value2
uint8
}
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
require
.
NoError
(
t
,
err
)
var
b
bytes
.
Buffer
var
i
uint8
=
1
for
;
i
<=
3
;
i
++
{
b
.
Write
(
packNum
(
reflect
.
ValueOf
(
i
)))
}
var
rst
testStruct
require
.
NoError
(
t
,
abi
.
Unpack
(
&
rst
,
"test"
,
b
.
Bytes
()))
require
.
Equal
(
t
,
[
2
]
uint8
{
1
,
2
},
rst
.
Value1
)
require
.
Equal
(
t
,
uint8
(
3
),
rst
.
Value2
)
}
func
TestEventTupleUnpack
(
t
*
testing
.
T
)
{
type
EventTransfer
struct
{
Value
*
big
.
Int
}
type
EventTransferWithTag
struct
{
// this is valid because `value` is not exportable,
// so value is only unmarshalled into `Value1`.
// value *big.Int
Value1
*
big
.
Int
`abi:"value"`
}
type
BadEventTransferWithSameFieldAndTag
struct
{
Value
*
big
.
Int
Value1
*
big
.
Int
`abi:"value"`
}
type
BadEventTransferWithDuplicatedTag
struct
{
Value1
*
big
.
Int
`abi:"value"`
Value2
*
big
.
Int
`abi:"value"`
}
type
BadEventTransferWithEmptyTag
struct
{
Value
*
big
.
Int
`abi:""`
}
type
EventPledge
struct
{
Who
common
.
Hash160Address
Wad
*
big
.
Int
Currency
[
3
]
byte
}
type
BadEventPledge
struct
{
Who
string
Wad
int
Currency
[
3
]
byte
}
type
EventMixedCase
struct
{
Value1
*
big
.
Int
`abi:"value"`
Value2
*
big
.
Int
`abi:"_value"`
Value3
*
big
.
Int
`abi:"Value"`
}
bigint
:=
new
(
big
.
Int
)
bigintExpected
:=
big
.
NewInt
(
1000000
)
bigintExpected2
:=
big
.
NewInt
(
2218516807680
)
bigintExpected3
:=
big
.
NewInt
(
1000001
)
addr
:=
common
.
HexToAddress
(
"0x00Ce0d46d924CC8437c806721496599FC3FFA268"
)
var
testCases
=
[]
struct
{
data
string
dest
interface
{}
expected
interface
{}
jsonLog
[]
byte
error
string
name
string
}{{
transferData1
,
&
EventTransfer
{},
&
EventTransfer
{
Value
:
bigintExpected
},
jsonEventTransfer
,
""
,
"Can unpack ERC20 Transfer event into structure"
,
},
{
transferData1
,
&
[]
interface
{}{
&
bigint
},
&
[]
interface
{}{
&
bigintExpected
},
jsonEventTransfer
,
""
,
"Can unpack ERC20 Transfer event into slice"
,
},
{
transferData1
,
&
EventTransferWithTag
{},
&
EventTransferWithTag
{
Value1
:
bigintExpected
},
jsonEventTransfer
,
""
,
"Can unpack ERC20 Transfer event into structure with abi: tag"
,
},
{
transferData1
,
&
BadEventTransferWithDuplicatedTag
{},
&
BadEventTransferWithDuplicatedTag
{},
jsonEventTransfer
,
"struct: abi tag in 'Value2' already mapped"
,
"Can not unpack ERC20 Transfer event with duplicated abi tag"
,
},
{
transferData1
,
&
BadEventTransferWithSameFieldAndTag
{},
&
BadEventTransferWithSameFieldAndTag
{},
jsonEventTransfer
,
"abi: multiple variables maps to the same abi field 'value'"
,
"Can not unpack ERC20 Transfer event with a field and a tag mapping to the same abi variable"
,
},
{
transferData1
,
&
BadEventTransferWithEmptyTag
{},
&
BadEventTransferWithEmptyTag
{},
jsonEventTransfer
,
"struct: abi tag in 'Value' is empty"
,
"Can not unpack ERC20 Transfer event with an empty tag"
,
},
{
pledgeData1
,
&
EventPledge
{},
&
EventPledge
{
addr
,
bigintExpected2
,
[
3
]
byte
{
'u'
,
's'
,
'd'
}},
jsonEventPledge
,
""
,
"Can unpack Pledge event into structure"
,
},
{
pledgeData1
,
&
[]
interface
{}{
&
common
.
Hash160Address
{},
&
bigint
,
&
[
3
]
byte
{}},
&
[]
interface
{}{
&
addr
,
&
bigintExpected2
,
&
[
3
]
byte
{
'u'
,
's'
,
'd'
}},
jsonEventPledge
,
""
,
"Can unpack Pledge event into slice"
,
},
{
pledgeData1
,
&
[
3
]
interface
{}{
&
common
.
Hash160Address
{},
&
bigint
,
&
[
3
]
byte
{}},
&
[
3
]
interface
{}{
&
addr
,
&
bigintExpected2
,
&
[
3
]
byte
{
'u'
,
's'
,
'd'
}},
jsonEventPledge
,
""
,
"Can unpack Pledge event into an array"
,
},
{
pledgeData1
,
&
[]
interface
{}{
new
(
int
),
0
,
0
},
&
[]
interface
{}{},
jsonEventPledge
,
"abi: cannot unmarshal common.Hash160Address in to int"
,
"Can not unpack Pledge event into slice with wrong types"
,
},
{
pledgeData1
,
&
BadEventPledge
{},
&
BadEventPledge
{},
jsonEventPledge
,
"abi: cannot unmarshal common.Hash160Address in to string"
,
"Can not unpack Pledge event into struct with wrong filed types"
,
},
{
pledgeData1
,
&
[]
interface
{}{
common
.
Hash160Address
{},
new
(
big
.
Int
)},
&
[]
interface
{}{},
jsonEventPledge
,
"abi: insufficient number of elements in the list/array for unpack, want 3, got 2"
,
"Can not unpack Pledge event into too short slice"
,
},
{
pledgeData1
,
new
(
map
[
string
]
interface
{}),
&
[]
interface
{}{},
jsonEventPledge
,
"abi: cannot unmarshal tuple into map[string]interface {}"
,
"Can not unpack Pledge event into map"
,
},
{
mixedCaseData1
,
&
EventMixedCase
{},
&
EventMixedCase
{
Value1
:
bigintExpected
,
Value2
:
bigintExpected2
,
Value3
:
bigintExpected3
},
jsonEventMixedCase
,
""
,
"Can unpack abi variables with mixed case"
,
}}
for
_
,
tc
:=
range
testCases
{
assert
:=
assert
.
New
(
t
)
tc
:=
tc
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
err
:=
unpackTestEventData
(
tc
.
dest
,
tc
.
data
,
tc
.
jsonLog
,
assert
)
if
tc
.
error
==
""
{
assert
.
Nil
(
err
,
"Should be able to unpack event data."
)
assert
.
Equal
(
tc
.
expected
,
tc
.
dest
,
tc
.
name
)
}
else
{
assert
.
EqualError
(
err
,
tc
.
error
,
tc
.
name
)
}
})
}
}
func
unpackTestEventData
(
dest
interface
{},
hexData
string
,
jsonEvent
[]
byte
,
assert
*
assert
.
Assertions
)
error
{
data
,
err
:=
hex
.
DecodeString
(
hexData
)
assert
.
NoError
(
err
,
"Hex data should be a correct hex-string"
)
var
e
Event
assert
.
NoError
(
json
.
Unmarshal
(
jsonEvent
,
&
e
),
"Should be able to unmarshal event ABI"
)
a
:=
ABI
{
Events
:
map
[
string
]
Event
{
"e"
:
e
}}
return
a
.
Unpack
(
dest
,
"e"
,
data
)
}
/*
Taken from
https://github.com/ethereum/go-ethereum/pull/15568
*/
type
testResult
struct
{
Values
[
2
]
*
big
.
Int
Value1
*
big
.
Int
Value2
*
big
.
Int
}
// TestEventUnpackIndexed verifies that indexed field will be skipped by event decoder.
func
TestEventUnpackIndexed
(
t
*
testing
.
T
)
{
definition
:=
`[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8"},{"indexed": false, "name":"value2", "type":"uint8"}]}]`
type
testStruct
struct
{
Value1
uint8
Value2
uint8
}
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
require
.
NoError
(
t
,
err
)
var
b
bytes
.
Buffer
b
.
Write
(
packNum
(
reflect
.
ValueOf
(
uint8
(
8
))))
var
rst
testStruct
require
.
NoError
(
t
,
abi
.
Unpack
(
&
rst
,
"test"
,
b
.
Bytes
()))
require
.
Equal
(
t
,
uint8
(
0
),
rst
.
Value1
)
require
.
Equal
(
t
,
uint8
(
8
),
rst
.
Value2
)
}
// TestEventIndexedWithArrayUnpack verifies that decoder will not overlow when static array is indexed input.
func
TestEventIndexedWithArrayUnpack
(
t
*
testing
.
T
)
{
definition
:=
`[{"name": "test", "type": "event", "inputs": [{"indexed": true, "name":"value1", "type":"uint8[2]"},{"indexed": false, "name":"value2", "type":"string"}]}]`
type
testStruct
struct
{
Value1
[
2
]
uint8
Value2
string
}
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
require
.
NoError
(
t
,
err
)
var
b
bytes
.
Buffer
stringOut
:=
"abc"
// number of fields that will be encoded * 32
b
.
Write
(
packNum
(
reflect
.
ValueOf
(
32
)))
b
.
Write
(
packNum
(
reflect
.
ValueOf
(
len
(
stringOut
))))
b
.
Write
(
common
.
RightPadBytes
([]
byte
(
stringOut
),
32
))
var
rst
testStruct
require
.
NoError
(
t
,
abi
.
Unpack
(
&
rst
,
"test"
,
b
.
Bytes
()))
require
.
Equal
(
t
,
[
2
]
uint8
{
0
,
0
},
rst
.
Value1
)
require
.
Equal
(
t
,
stringOut
,
rst
.
Value2
)
}
plugin/dapp/evm/executor/abi/method.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"fmt"
"strings"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common/crypto"
)
// Method represents a callable given a `Name` and whether the method is a constant.
// If the method is `Const` no transaction needs to be created for this
// particular Method call. It can easily be simulated using a local VM.
// For example a `Balance()` method only needs to retrieve something
// from the storage and therefor requires no Tx to be send to the
// network. A method such as `Transact` does require a Tx and thus will
// be flagged `true`.
// Input specifies the required input parameters for this gives method.
type
Method
struct
{
Name
string
Const
bool
Inputs
Arguments
Outputs
Arguments
}
// Sig returns the methods string signature according to the ABI spec.
//
// Example
//
// function foo(uint32 a, int b) = "foo(uint32,int256)"
//
// Please note that "int" is substitute for its canonical representation "int256"
func
(
method
Method
)
Sig
()
string
{
types
:=
make
([]
string
,
len
(
method
.
Inputs
))
for
i
,
input
:=
range
method
.
Inputs
{
types
[
i
]
=
input
.
Type
.
String
()
}
return
fmt
.
Sprintf
(
"%v(%v)"
,
method
.
Name
,
strings
.
Join
(
types
,
","
))
}
func
(
method
Method
)
String
()
string
{
inputs
:=
make
([]
string
,
len
(
method
.
Inputs
))
for
i
,
input
:=
range
method
.
Inputs
{
inputs
[
i
]
=
fmt
.
Sprintf
(
"%v %v"
,
input
.
Name
,
input
.
Type
)
}
outputs
:=
make
([]
string
,
len
(
method
.
Outputs
))
for
i
,
output
:=
range
method
.
Outputs
{
if
len
(
output
.
Name
)
>
0
{
outputs
[
i
]
=
fmt
.
Sprintf
(
"%v "
,
output
.
Name
)
}
outputs
[
i
]
+=
output
.
Type
.
String
()
}
constant
:=
""
if
method
.
Const
{
constant
=
"constant "
}
return
fmt
.
Sprintf
(
"function %v(%v) %sreturns(%v)"
,
method
.
Name
,
strings
.
Join
(
inputs
,
", "
),
constant
,
strings
.
Join
(
outputs
,
", "
))
}
// ID method name hash
func
(
method
Method
)
ID
()
[]
byte
{
return
crypto
.
Keccak256
([]
byte
(
method
.
Sig
()))[
:
4
]
}
plugin/dapp/evm/executor/abi/numbers.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"math/big"
"reflect"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
)
var
(
bigT
=
reflect
.
TypeOf
(
&
big
.
Int
{})
derefbigT
=
reflect
.
TypeOf
(
big
.
Int
{})
uint8T
=
reflect
.
TypeOf
(
uint8
(
0
))
uint16T
=
reflect
.
TypeOf
(
uint16
(
0
))
uint32T
=
reflect
.
TypeOf
(
uint32
(
0
))
uint64T
=
reflect
.
TypeOf
(
uint64
(
0
))
int8T
=
reflect
.
TypeOf
(
int8
(
0
))
int16T
=
reflect
.
TypeOf
(
int16
(
0
))
int32T
=
reflect
.
TypeOf
(
int32
(
0
))
int64T
=
reflect
.
TypeOf
(
int64
(
0
))
addressT
=
reflect
.
TypeOf
(
common
.
Hash160Address
{})
)
// U256 converts a big Int into a 256bit EVM number.
func
U256
(
n
*
big
.
Int
)
[]
byte
{
return
common
.
PaddedBigBytes
(
common
.
U256
(
n
),
32
)
}
plugin/dapp/evm/executor/abi/numbers_test.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"bytes"
"math/big"
"testing"
)
func
TestNumberTypes
(
t
*
testing
.
T
)
{
ubytes
:=
make
([]
byte
,
32
)
ubytes
[
31
]
=
1
unsigned
:=
U256
(
big
.
NewInt
(
1
))
if
!
bytes
.
Equal
(
unsigned
,
ubytes
)
{
t
.
Errorf
(
"expected %x got %x"
,
ubytes
,
unsigned
)
}
}
plugin/dapp/evm/executor/abi/pack.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"math/big"
"reflect"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
)
// packBytesSlice packs the given bytes as [L, V] as the canonical representation
// bytes slice
func
packBytesSlice
(
bytes
[]
byte
,
l
int
)
[]
byte
{
len
:=
packNum
(
reflect
.
ValueOf
(
l
))
return
append
(
len
,
common
.
RightPadBytes
(
bytes
,
(
l
+
31
)
/
32
*
32
)
...
)
}
// packElement packs the given reflect value according to the abi specification in
// t.
func
packElement
(
t
Type
,
reflectValue
reflect
.
Value
)
[]
byte
{
switch
t
.
T
{
case
IntTy
,
UintTy
:
return
packNum
(
reflectValue
)
case
StringTy
:
return
packBytesSlice
([]
byte
(
reflectValue
.
String
()),
reflectValue
.
Len
())
case
AddressTy
:
if
reflectValue
.
Kind
()
==
reflect
.
Array
{
reflectValue
=
mustArrayToByteSlice
(
reflectValue
)
}
return
common
.
LeftPadBytes
(
reflectValue
.
Bytes
(),
32
)
case
BoolTy
:
if
reflectValue
.
Bool
()
{
return
common
.
PaddedBigBytes
(
common
.
Big1
,
32
)
}
return
common
.
PaddedBigBytes
(
common
.
Big0
,
32
)
case
BytesTy
:
if
reflectValue
.
Kind
()
==
reflect
.
Array
{
reflectValue
=
mustArrayToByteSlice
(
reflectValue
)
}
return
packBytesSlice
(
reflectValue
.
Bytes
(),
reflectValue
.
Len
())
case
FixedBytesTy
,
FunctionTy
:
if
reflectValue
.
Kind
()
==
reflect
.
Array
{
reflectValue
=
mustArrayToByteSlice
(
reflectValue
)
}
return
common
.
RightPadBytes
(
reflectValue
.
Bytes
(),
32
)
default
:
panic
(
"abi: fatal error"
)
}
}
// packNum packs the given number (using the reflect value) and will cast it to appropriate number representation
func
packNum
(
value
reflect
.
Value
)
[]
byte
{
switch
kind
:=
value
.
Kind
();
kind
{
case
reflect
.
Uint
,
reflect
.
Uint8
,
reflect
.
Uint16
,
reflect
.
Uint32
,
reflect
.
Uint64
:
return
U256
(
new
(
big
.
Int
)
.
SetUint64
(
value
.
Uint
()))
case
reflect
.
Int
,
reflect
.
Int8
,
reflect
.
Int16
,
reflect
.
Int32
,
reflect
.
Int64
:
return
U256
(
big
.
NewInt
(
value
.
Int
()))
case
reflect
.
Ptr
:
return
U256
(
value
.
Interface
()
.
(
*
big
.
Int
))
default
:
panic
(
"abi: fatal error"
)
}
}
plugin/dapp/evm/executor/abi/pack_test.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"bytes"
"math"
"math/big"
"reflect"
"strings"
"testing"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
)
func
TestPack
(
t
*
testing
.
T
)
{
for
i
,
test
:=
range
[]
struct
{
typ
string
input
interface
{}
output
[]
byte
}{
{
"uint8"
,
uint8
(
2
),
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint8[]"
,
[]
uint8
{
1
,
2
},
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint16"
,
uint16
(
2
),
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint16[]"
,
[]
uint16
{
1
,
2
},
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint32"
,
uint32
(
2
),
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint32[]"
,
[]
uint32
{
1
,
2
},
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint64"
,
uint64
(
2
),
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint64[]"
,
[]
uint64
{
1
,
2
},
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint256"
,
big
.
NewInt
(
2
),
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"uint256[]"
,
[]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
)},
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int8"
,
int8
(
2
),
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int8[]"
,
[]
int8
{
1
,
2
},
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int16"
,
int16
(
2
),
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int16[]"
,
[]
int16
{
1
,
2
},
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int32"
,
int32
(
2
),
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int32[]"
,
[]
int32
{
1
,
2
},
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int64"
,
int64
(
2
),
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int64[]"
,
[]
int64
{
1
,
2
},
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int256"
,
big
.
NewInt
(
2
),
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"int256[]"
,
[]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
)},
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
),
},
{
"bytes1"
,
[
1
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes2"
,
[
2
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes3"
,
[
3
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes4"
,
[
4
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes5"
,
[
5
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes6"
,
[
6
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes7"
,
[
7
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes8"
,
[
8
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes9"
,
[
9
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes10"
,
[
10
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes11"
,
[
11
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes12"
,
[
12
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes13"
,
[
13
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes14"
,
[
14
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes15"
,
[
15
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes16"
,
[
16
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes17"
,
[
17
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes18"
,
[
18
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes19"
,
[
19
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes20"
,
[
20
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes21"
,
[
21
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes22"
,
[
22
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes23"
,
[
23
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes24"
,
[
24
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes24"
,
[
24
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes25"
,
[
25
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes26"
,
[
26
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes27"
,
[
27
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes28"
,
[
28
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes29"
,
[
29
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes30"
,
[
30
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes31"
,
[
31
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"bytes32"
,
[
32
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"uint32[2][3][4]"
,
[
4
][
3
][
2
]
uint32
{{{
1
,
2
},
{
3
,
4
},
{
5
,
6
}},
{{
7
,
8
},
{
9
,
10
},
{
11
,
12
}},
{{
13
,
14
},
{
15
,
16
},
{
17
,
18
}},
{{
19
,
20
},
{
21
,
22
},
{
23
,
24
}}},
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018"
),
},
{
"address[]"
,
[]
common
.
Hash160Address
{{
1
},
{
2
}},
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000"
),
},
{
"bytes32[]"
,
[]
common
.
Hash
{{
1
},
{
2
}},
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000"
),
},
{
"function"
,
[
24
]
byte
{
1
},
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
"string"
,
"foobar"
,
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000006666f6f6261720000000000000000000000000000000000000000000000000000"
),
},
}
{
typ
,
err
:=
NewType
(
test
.
typ
)
if
err
!=
nil
{
t
.
Fatalf
(
"%v failed. Unexpected parse error: %v"
,
i
,
err
)
}
output
,
err
:=
typ
.
pack
(
reflect
.
ValueOf
(
test
.
input
))
if
err
!=
nil
{
t
.
Fatalf
(
"%v failed. Unexpected pack error: %v"
,
i
,
err
)
}
if
!
bytes
.
Equal
(
output
,
test
.
output
)
{
t
.
Errorf
(
"%d failed. Expected bytes: '%x' Got: '%x'"
,
i
,
test
.
output
,
output
)
}
}
}
func
TestMethodPack
(
t
*
testing
.
T
)
{
abi
,
err
:=
JSON
(
strings
.
NewReader
(
jsondata2
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
sig
:=
abi
.
Methods
[
"slice"
]
.
ID
()
sig
=
append
(
sig
,
common
.
LeftPadBytes
([]
byte
{
1
},
32
)
...
)
sig
=
append
(
sig
,
common
.
LeftPadBytes
([]
byte
{
2
},
32
)
...
)
packed
,
err
:=
abi
.
Pack
(
"slice"
,
[]
uint32
{
1
,
2
})
if
err
!=
nil
{
t
.
Error
(
err
)
}
if
!
bytes
.
Equal
(
packed
,
sig
)
{
t
.
Errorf
(
"expected %x got %x"
,
sig
,
packed
)
}
var
addrA
,
addrB
=
common
.
Hash160Address
{
1
},
common
.
Hash160Address
{
2
}
sig
=
abi
.
Methods
[
"sliceAddress"
]
.
ID
()
sig
=
append
(
sig
,
common
.
LeftPadBytes
([]
byte
{
32
},
32
)
...
)
sig
=
append
(
sig
,
common
.
LeftPadBytes
([]
byte
{
2
},
32
)
...
)
sig
=
append
(
sig
,
common
.
LeftPadBytes
(
addrA
[
:
],
32
)
...
)
sig
=
append
(
sig
,
common
.
LeftPadBytes
(
addrB
[
:
],
32
)
...
)
packed
,
err
=
abi
.
Pack
(
"sliceAddress"
,
[]
common
.
Hash160Address
{
addrA
,
addrB
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
!
bytes
.
Equal
(
packed
,
sig
)
{
t
.
Errorf
(
"expected %x got %x"
,
sig
,
packed
)
}
var
addrC
,
addrD
=
common
.
Hash160Address
{
3
},
common
.
Hash160Address
{
4
}
sig
=
abi
.
Methods
[
"sliceMultiAddress"
]
.
ID
()
sig
=
append
(
sig
,
common
.
LeftPadBytes
([]
byte
{
64
},
32
)
...
)
sig
=
append
(
sig
,
common
.
LeftPadBytes
([]
byte
{
160
},
32
)
...
)
sig
=
append
(
sig
,
common
.
LeftPadBytes
([]
byte
{
2
},
32
)
...
)
sig
=
append
(
sig
,
common
.
LeftPadBytes
(
addrA
[
:
],
32
)
...
)
sig
=
append
(
sig
,
common
.
LeftPadBytes
(
addrB
[
:
],
32
)
...
)
sig
=
append
(
sig
,
common
.
LeftPadBytes
([]
byte
{
2
},
32
)
...
)
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
})
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
!
bytes
.
Equal
(
packed
,
sig
)
{
t
.
Errorf
(
"expected %x got %x"
,
sig
,
packed
)
}
sig
=
abi
.
Methods
[
"slice256"
]
.
ID
()
sig
=
append
(
sig
,
common
.
LeftPadBytes
([]
byte
{
1
},
32
)
...
)
sig
=
append
(
sig
,
common
.
LeftPadBytes
([]
byte
{
2
},
32
)
...
)
packed
,
err
=
abi
.
Pack
(
"slice256"
,
[]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
)})
if
err
!=
nil
{
t
.
Error
(
err
)
}
if
!
bytes
.
Equal
(
packed
,
sig
)
{
t
.
Errorf
(
"expected %x got %x"
,
sig
,
packed
)
}
}
func
TestPackNumber
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
value
reflect
.
Value
packed
[]
byte
}{
// Protocol limits
{
reflect
.
ValueOf
(
0
),
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000000"
)},
{
reflect
.
ValueOf
(
1
),
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000001"
)},
{
reflect
.
ValueOf
(
-
1
),
common
.
Hex2Bytes
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
)},
// Type corner cases
{
reflect
.
ValueOf
(
uint8
(
math
.
MaxUint8
)),
common
.
Hex2Bytes
(
"00000000000000000000000000000000000000000000000000000000000000ff"
)},
{
reflect
.
ValueOf
(
uint16
(
math
.
MaxUint16
)),
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000ffff"
)},
{
reflect
.
ValueOf
(
uint32
(
math
.
MaxUint32
)),
common
.
Hex2Bytes
(
"00000000000000000000000000000000000000000000000000000000ffffffff"
)},
{
reflect
.
ValueOf
(
uint64
(
math
.
MaxUint64
)),
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000ffffffffffffffff"
)},
{
reflect
.
ValueOf
(
int8
(
math
.
MaxInt8
)),
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000007f"
)},
{
reflect
.
ValueOf
(
int16
(
math
.
MaxInt16
)),
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000007fff"
)},
{
reflect
.
ValueOf
(
int32
(
math
.
MaxInt32
)),
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000007fffffff"
)},
{
reflect
.
ValueOf
(
int64
(
math
.
MaxInt64
)),
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000007fffffffffffffff"
)},
{
reflect
.
ValueOf
(
int8
(
math
.
MinInt8
)),
common
.
Hex2Bytes
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80"
)},
{
reflect
.
ValueOf
(
int16
(
math
.
MinInt16
)),
common
.
Hex2Bytes
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000"
)},
{
reflect
.
ValueOf
(
int32
(
math
.
MinInt32
)),
common
.
Hex2Bytes
(
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffff80000000"
)},
{
reflect
.
ValueOf
(
int64
(
math
.
MinInt64
)),
common
.
Hex2Bytes
(
"ffffffffffffffffffffffffffffffffffffffffffffffff8000000000000000"
)},
}
for
i
,
tt
:=
range
tests
{
packed
:=
packNum
(
tt
.
value
)
if
!
bytes
.
Equal
(
packed
,
tt
.
packed
)
{
t
.
Errorf
(
"test %d: pack mismatch: have %x, want %x"
,
i
,
packed
,
tt
.
packed
)
}
}
}
plugin/dapp/evm/executor/abi/reflect.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"fmt"
"reflect"
"strings"
)
// indirect recursively dereferences the value until it either gets the value
// or finds a big.Int
func
indirect
(
v
reflect
.
Value
)
reflect
.
Value
{
if
v
.
Kind
()
==
reflect
.
Ptr
&&
v
.
Elem
()
.
Type
()
!=
derefbigT
{
return
indirect
(
v
.
Elem
())
}
return
v
}
// reflectIntKind returns the reflect using the given size and
// unsignedness.
func
reflectIntKindAndType
(
unsigned
bool
,
size
int
)
(
reflect
.
Kind
,
reflect
.
Type
)
{
switch
size
{
case
8
:
if
unsigned
{
return
reflect
.
Uint8
,
uint8T
}
return
reflect
.
Int8
,
int8T
case
16
:
if
unsigned
{
return
reflect
.
Uint16
,
uint16T
}
return
reflect
.
Int16
,
int16T
case
32
:
if
unsigned
{
return
reflect
.
Uint32
,
uint32T
}
return
reflect
.
Int32
,
int32T
case
64
:
if
unsigned
{
return
reflect
.
Uint64
,
uint64T
}
return
reflect
.
Int64
,
int64T
}
return
reflect
.
Ptr
,
bigT
}
// mustArrayToBytesSlice creates a new byte slice with the exact same size as value
// and copies the bytes in value to the new slice.
func
mustArrayToByteSlice
(
value
reflect
.
Value
)
reflect
.
Value
{
slice
:=
reflect
.
MakeSlice
(
reflect
.
TypeOf
([]
byte
{}),
value
.
Len
(),
value
.
Len
())
reflect
.
Copy
(
slice
,
value
)
return
slice
}
// set attempts to assign src to dst by either setting, copying or otherwise.
//
// set is a bit more lenient when it comes to assignment and doesn't force an as
// strict ruleset as bare `reflect` does.
func
set
(
dst
,
src
reflect
.
Value
,
output
Argument
)
error
{
dstType
:=
dst
.
Type
()
srcType
:=
src
.
Type
()
switch
{
case
dstType
.
AssignableTo
(
srcType
)
:
dst
.
Set
(
src
)
case
dstType
.
Kind
()
==
reflect
.
Interface
:
dst
.
Set
(
src
)
case
dstType
.
Kind
()
==
reflect
.
Ptr
:
return
set
(
dst
.
Elem
(),
src
,
output
)
default
:
return
fmt
.
Errorf
(
"abi: cannot unmarshal %v in to %v"
,
src
.
Type
(),
dst
.
Type
())
}
return
nil
}
// requireAssignable assures that `dest` is a pointer and it's not an interface.
func
requireAssignable
(
dst
,
src
reflect
.
Value
)
error
{
if
dst
.
Kind
()
!=
reflect
.
Ptr
&&
dst
.
Kind
()
!=
reflect
.
Interface
{
return
fmt
.
Errorf
(
"abi: cannot unmarshal %v into %v"
,
src
.
Type
(),
dst
.
Type
())
}
return
nil
}
// requireUnpackKind verifies preconditions for unpacking `args` into `kind`
func
requireUnpackKind
(
v
reflect
.
Value
,
t
reflect
.
Type
,
k
reflect
.
Kind
,
args
Arguments
)
error
{
switch
k
{
case
reflect
.
Struct
:
case
reflect
.
Slice
,
reflect
.
Array
:
if
minLen
:=
args
.
LengthNonIndexed
();
v
.
Len
()
<
minLen
{
return
fmt
.
Errorf
(
"abi: insufficient number of elements in the list/array for unpack, want %d, got %d"
,
minLen
,
v
.
Len
())
}
default
:
return
fmt
.
Errorf
(
"abi: cannot unmarshal tuple into %v"
,
t
)
}
return
nil
}
// mapAbiToStringField maps abi to struct fields.
// first round: for each Exportable field that contains a `abi:""` tag
// and this field name exists in the arguments, pair them together.
// 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.
func
mapAbiToStructFields
(
args
Arguments
,
value
reflect
.
Value
)
(
map
[
string
]
string
,
error
)
{
typ
:=
value
.
Type
()
abi2struct
:=
make
(
map
[
string
]
string
)
struct2abi
:=
make
(
map
[
string
]
string
)
// first round ~~~
for
i
:=
0
;
i
<
typ
.
NumField
();
i
++
{
structFieldName
:=
typ
.
Field
(
i
)
.
Name
// skip private struct fields.
if
structFieldName
[
:
1
]
!=
strings
.
ToUpper
(
structFieldName
[
:
1
])
{
continue
}
// skip fields that have no abi:"" tag.
var
ok
bool
var
tagName
string
if
tagName
,
ok
=
typ
.
Field
(
i
)
.
Tag
.
Lookup
(
"abi"
);
!
ok
{
continue
}
// check if tag is empty.
if
tagName
==
""
{
return
nil
,
fmt
.
Errorf
(
"struct: abi tag in '%s' is empty"
,
structFieldName
)
}
// check which argument field matches with the abi tag.
found
:=
false
for
_
,
abiField
:=
range
args
.
NonIndexed
()
{
if
abiField
.
Name
==
tagName
{
if
abi2struct
[
abiField
.
Name
]
!=
""
{
return
nil
,
fmt
.
Errorf
(
"struct: abi tag in '%s' already mapped"
,
structFieldName
)
}
// pair them
abi2struct
[
abiField
.
Name
]
=
structFieldName
struct2abi
[
structFieldName
]
=
abiField
.
Name
found
=
true
}
}
// check if this tag has been mapped.
if
!
found
{
return
nil
,
fmt
.
Errorf
(
"struct: abi tag '%s' defined but not found in abi"
,
tagName
)
}
}
// second round ~~~
for
_
,
arg
:=
range
args
{
abiFieldName
:=
arg
.
Name
structFieldName
:=
capitalise
(
abiFieldName
)
if
structFieldName
==
""
{
return
nil
,
fmt
.
Errorf
(
"abi: purely underscored output cannot unpack to struct"
)
}
// this abi has already been paired, skip it... unless there exists another, yet unassigned
// struct field with the same field name. If so, raise an error:
// abi: [ { "name": "value" } ]
// struct { Value *big.Int , Value1 *big.Int `abi:"value"`}
if
abi2struct
[
abiFieldName
]
!=
""
{
if
abi2struct
[
abiFieldName
]
!=
structFieldName
&&
struct2abi
[
structFieldName
]
==
""
&&
value
.
FieldByName
(
structFieldName
)
.
IsValid
()
{
return
nil
,
fmt
.
Errorf
(
"abi: multiple variables maps to the same abi field '%s'"
,
abiFieldName
)
}
continue
}
// return an error if this struct field has already been paired.
if
struct2abi
[
structFieldName
]
!=
""
{
return
nil
,
fmt
.
Errorf
(
"abi: multiple outputs mapping to the same struct field '%s'"
,
structFieldName
)
}
if
value
.
FieldByName
(
structFieldName
)
.
IsValid
()
{
// pair them
abi2struct
[
abiFieldName
]
=
structFieldName
struct2abi
[
structFieldName
]
=
abiFieldName
}
else
{
// not paired, but annotate as used, to detect cases like
// abi : [ { "name": "value" }, { "name": "_value" } ]
// struct { Value *big.Int }
struct2abi
[
structFieldName
]
=
abiFieldName
}
}
return
abi2struct
,
nil
}
plugin/dapp/evm/executor/abi/type.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"fmt"
"reflect"
"regexp"
"strconv"
"strings"
)
// Type enumerator
const
(
IntTy
byte
=
iota
UintTy
BoolTy
StringTy
SliceTy
ArrayTy
AddressTy
FixedBytesTy
BytesTy
HashTy
FixedPointTy
FunctionTy
)
// Type is the reflection of the supported argument type
type
Type
struct
{
Elem
*
Type
Kind
reflect
.
Kind
Type
reflect
.
Type
Size
int
T
byte
// Our own type checking
stringKind
string
// holds the unparsed string for deriving signatures
}
var
(
// typeRegex parses the abi sub types
typeRegex
=
regexp
.
MustCompile
(
"([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?"
)
)
// NewType creates a new reflection type of abi type given in t.
func
NewType
(
t
string
)
(
typ
Type
,
err
error
)
{
// check that array brackets are equal if they exist
if
strings
.
Count
(
t
,
"["
)
!=
strings
.
Count
(
t
,
"]"
)
{
return
Type
{},
fmt
.
Errorf
(
"invalid arg type in abi"
)
}
typ
.
stringKind
=
t
// if there are brackets, get ready to go into slice/array mode and
// recursively create the type
if
strings
.
Count
(
t
,
"["
)
!=
0
{
i
:=
strings
.
LastIndex
(
t
,
"["
)
// recursively embed the type
embeddedType
,
err
:=
NewType
(
t
[
:
i
])
if
err
!=
nil
{
return
Type
{},
err
}
// grab the last cell and create a type from there
sliced
:=
t
[
i
:
]
// grab the slice size with regexp
re
:=
regexp
.
MustCompile
(
"[0-9]+"
)
intz
:=
re
.
FindAllString
(
sliced
,
-
1
)
if
len
(
intz
)
==
0
{
// is a slice
typ
.
T
=
SliceTy
typ
.
Kind
=
reflect
.
Slice
typ
.
Elem
=
&
embeddedType
typ
.
Type
=
reflect
.
SliceOf
(
embeddedType
.
Type
)
}
else
if
len
(
intz
)
==
1
{
// is a array
typ
.
T
=
ArrayTy
typ
.
Kind
=
reflect
.
Array
typ
.
Elem
=
&
embeddedType
typ
.
Size
,
err
=
strconv
.
Atoi
(
intz
[
0
])
if
err
!=
nil
{
return
Type
{},
fmt
.
Errorf
(
"abi: error parsing variable size: %v"
,
err
)
}
typ
.
Type
=
reflect
.
ArrayOf
(
typ
.
Size
,
embeddedType
.
Type
)
}
else
{
return
Type
{},
fmt
.
Errorf
(
"invalid formatting of array type"
)
}
return
typ
,
err
}
// parse the type and size of the abi-type.
matches
:=
typeRegex
.
FindAllStringSubmatch
(
t
,
-
1
)
if
len
(
matches
)
==
0
{
return
Type
{},
fmt
.
Errorf
(
"invalid type '%v'"
,
t
)
}
parsedType
:=
matches
[
0
]
// varSize is the size of the variable
var
varSize
int
if
len
(
parsedType
[
3
])
>
0
{
var
err
error
varSize
,
err
=
strconv
.
Atoi
(
parsedType
[
2
])
if
err
!=
nil
{
return
Type
{},
fmt
.
Errorf
(
"abi: error parsing variable size: %v"
,
err
)
}
}
else
{
if
parsedType
[
0
]
==
"uint"
||
parsedType
[
0
]
==
"int"
{
// this should fail because it means that there's something wrong with
// the abi type (the compiler should always format it to the size...always)
return
Type
{},
fmt
.
Errorf
(
"unsupported arg type: %s"
,
t
)
}
}
// varType is the parsed abi type
switch
varType
:=
parsedType
[
1
];
varType
{
case
"int"
:
typ
.
Kind
,
typ
.
Type
=
reflectIntKindAndType
(
false
,
varSize
)
typ
.
Size
=
varSize
typ
.
T
=
IntTy
case
"uint"
:
typ
.
Kind
,
typ
.
Type
=
reflectIntKindAndType
(
true
,
varSize
)
typ
.
Size
=
varSize
typ
.
T
=
UintTy
case
"bool"
:
typ
.
Kind
=
reflect
.
Bool
typ
.
T
=
BoolTy
typ
.
Type
=
reflect
.
TypeOf
(
bool
(
false
))
case
"address"
:
typ
.
Kind
=
reflect
.
Array
typ
.
Type
=
addressT
typ
.
Size
=
20
typ
.
T
=
AddressTy
case
"string"
:
typ
.
Kind
=
reflect
.
String
typ
.
Type
=
reflect
.
TypeOf
(
""
)
typ
.
T
=
StringTy
case
"bytes"
:
if
varSize
==
0
{
typ
.
T
=
BytesTy
typ
.
Kind
=
reflect
.
Slice
typ
.
Type
=
reflect
.
SliceOf
(
reflect
.
TypeOf
(
byte
(
0
)))
}
else
{
typ
.
T
=
FixedBytesTy
typ
.
Kind
=
reflect
.
Array
typ
.
Size
=
varSize
typ
.
Type
=
reflect
.
ArrayOf
(
varSize
,
reflect
.
TypeOf
(
byte
(
0
)))
}
case
"function"
:
typ
.
Kind
=
reflect
.
Array
typ
.
T
=
FunctionTy
typ
.
Size
=
24
typ
.
Type
=
reflect
.
ArrayOf
(
24
,
reflect
.
TypeOf
(
byte
(
0
)))
default
:
return
Type
{},
fmt
.
Errorf
(
"unsupported arg type: %s"
,
t
)
}
return
}
// String implements Stringer
func
(
t
Type
)
String
()
(
out
string
)
{
return
t
.
stringKind
}
func
(
t
Type
)
pack
(
v
reflect
.
Value
)
([]
byte
,
error
)
{
// dereference pointer first if it's a pointer
v
=
indirect
(
v
)
if
err
:=
typeCheck
(
t
,
v
);
err
!=
nil
{
return
nil
,
err
}
if
t
.
T
==
SliceTy
||
t
.
T
==
ArrayTy
{
var
packed
[]
byte
for
i
:=
0
;
i
<
v
.
Len
();
i
++
{
val
,
err
:=
t
.
Elem
.
pack
(
v
.
Index
(
i
))
if
err
!=
nil
{
return
nil
,
err
}
packed
=
append
(
packed
,
val
...
)
}
if
t
.
T
==
SliceTy
{
return
packBytesSlice
(
packed
,
v
.
Len
()),
nil
}
else
if
t
.
T
==
ArrayTy
{
return
packed
,
nil
}
}
return
packElement
(
t
,
v
),
nil
}
// requireLengthPrefix returns whether the type requires any sort of length
// prefixing.
func
(
t
Type
)
requiresLengthPrefix
()
bool
{
return
t
.
T
==
StringTy
||
t
.
T
==
BytesTy
||
t
.
T
==
SliceTy
}
plugin/dapp/evm/executor/abi/type_test.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"math/big"
"reflect"
"testing"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
)
// typeWithoutStringer is a alias for the Type type which simply doesn't implement
// the stringer interface to allow printing type details in the tests below.
type
typeWithoutStringer
Type
// Tests that all allowed types get recognized by the type parser.
func
TestTypeRegexp
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
blob
string
kind
Type
}{
{
"bool"
,
Type
{
Kind
:
reflect
.
Bool
,
T
:
BoolTy
,
Type
:
reflect
.
TypeOf
(
bool
(
false
)),
stringKind
:
"bool"
}},
{
"bool[]"
,
Type
{
Kind
:
reflect
.
Slice
,
T
:
SliceTy
,
Type
:
reflect
.
TypeOf
([]
bool
(
nil
)),
Elem
:
&
Type
{
Kind
:
reflect
.
Bool
,
T
:
BoolTy
,
Type
:
reflect
.
TypeOf
(
bool
(
false
)),
stringKind
:
"bool"
},
stringKind
:
"bool[]"
}},
{
"bool[2]"
,
Type
{
Size
:
2
,
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Type
:
reflect
.
TypeOf
([
2
]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Bool
,
T
:
BoolTy
,
Type
:
reflect
.
TypeOf
(
bool
(
false
)),
stringKind
:
"bool"
},
stringKind
:
"bool[2]"
}},
{
"bool[2][]"
,
Type
{
Kind
:
reflect
.
Slice
,
T
:
SliceTy
,
Type
:
reflect
.
TypeOf
([][
2
]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Bool
,
T
:
BoolTy
,
Type
:
reflect
.
TypeOf
(
bool
(
false
)),
stringKind
:
"bool"
},
stringKind
:
"bool[2]"
},
stringKind
:
"bool[2][]"
}},
{
"bool[][]"
,
Type
{
Kind
:
reflect
.
Slice
,
T
:
SliceTy
,
Type
:
reflect
.
TypeOf
([][]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Slice
,
T
:
SliceTy
,
Type
:
reflect
.
TypeOf
([]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Bool
,
T
:
BoolTy
,
Type
:
reflect
.
TypeOf
(
bool
(
false
)),
stringKind
:
"bool"
},
stringKind
:
"bool[]"
},
stringKind
:
"bool[][]"
}},
{
"bool[][2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
][]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Slice
,
T
:
SliceTy
,
Type
:
reflect
.
TypeOf
([]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Bool
,
T
:
BoolTy
,
Type
:
reflect
.
TypeOf
(
bool
(
false
)),
stringKind
:
"bool"
},
stringKind
:
"bool[]"
},
stringKind
:
"bool[][2]"
}},
{
"bool[2][2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
][
2
]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Bool
,
T
:
BoolTy
,
Type
:
reflect
.
TypeOf
(
bool
(
false
)),
stringKind
:
"bool"
},
stringKind
:
"bool[2]"
},
stringKind
:
"bool[2][2]"
}},
{
"bool[2][][2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
][][
2
]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Slice
,
T
:
SliceTy
,
Type
:
reflect
.
TypeOf
([][
2
]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Bool
,
T
:
BoolTy
,
Type
:
reflect
.
TypeOf
(
bool
(
false
)),
stringKind
:
"bool"
},
stringKind
:
"bool[2]"
},
stringKind
:
"bool[2][]"
},
stringKind
:
"bool[2][][2]"
}},
{
"bool[2][2][2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
][
2
][
2
]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
][
2
]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Bool
,
T
:
BoolTy
,
Type
:
reflect
.
TypeOf
(
bool
(
false
)),
stringKind
:
"bool"
},
stringKind
:
"bool[2]"
},
stringKind
:
"bool[2][2]"
},
stringKind
:
"bool[2][2][2]"
}},
{
"bool[][][]"
,
Type
{
T
:
SliceTy
,
Kind
:
reflect
.
Slice
,
Type
:
reflect
.
TypeOf
([][][]
bool
{}),
Elem
:
&
Type
{
T
:
SliceTy
,
Kind
:
reflect
.
Slice
,
Type
:
reflect
.
TypeOf
([][]
bool
{}),
Elem
:
&
Type
{
T
:
SliceTy
,
Kind
:
reflect
.
Slice
,
Type
:
reflect
.
TypeOf
([]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Bool
,
T
:
BoolTy
,
Type
:
reflect
.
TypeOf
(
bool
(
false
)),
stringKind
:
"bool"
},
stringKind
:
"bool[]"
},
stringKind
:
"bool[][]"
},
stringKind
:
"bool[][][]"
}},
{
"bool[][2][]"
,
Type
{
T
:
SliceTy
,
Kind
:
reflect
.
Slice
,
Type
:
reflect
.
TypeOf
([][
2
][]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
][]
bool
{}),
Elem
:
&
Type
{
T
:
SliceTy
,
Kind
:
reflect
.
Slice
,
Type
:
reflect
.
TypeOf
([]
bool
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Bool
,
T
:
BoolTy
,
Type
:
reflect
.
TypeOf
(
bool
(
false
)),
stringKind
:
"bool"
},
stringKind
:
"bool[]"
},
stringKind
:
"bool[][2]"
},
stringKind
:
"bool[][2][]"
}},
{
"int8"
,
Type
{
Kind
:
reflect
.
Int8
,
Type
:
int8T
,
Size
:
8
,
T
:
IntTy
,
stringKind
:
"int8"
}},
{
"int16"
,
Type
{
Kind
:
reflect
.
Int16
,
Type
:
int16T
,
Size
:
16
,
T
:
IntTy
,
stringKind
:
"int16"
}},
{
"int32"
,
Type
{
Kind
:
reflect
.
Int32
,
Type
:
int32T
,
Size
:
32
,
T
:
IntTy
,
stringKind
:
"int32"
}},
{
"int64"
,
Type
{
Kind
:
reflect
.
Int64
,
Type
:
int64T
,
Size
:
64
,
T
:
IntTy
,
stringKind
:
"int64"
}},
{
"int256"
,
Type
{
Kind
:
reflect
.
Ptr
,
Type
:
bigT
,
Size
:
256
,
T
:
IntTy
,
stringKind
:
"int256"
}},
{
"int8[]"
,
Type
{
Kind
:
reflect
.
Slice
,
T
:
SliceTy
,
Type
:
reflect
.
TypeOf
([]
int8
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Int8
,
Type
:
int8T
,
Size
:
8
,
T
:
IntTy
,
stringKind
:
"int8"
},
stringKind
:
"int8[]"
}},
{
"int8[2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
]
int8
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Int8
,
Type
:
int8T
,
Size
:
8
,
T
:
IntTy
,
stringKind
:
"int8"
},
stringKind
:
"int8[2]"
}},
{
"int16[]"
,
Type
{
Kind
:
reflect
.
Slice
,
T
:
SliceTy
,
Type
:
reflect
.
TypeOf
([]
int16
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Int16
,
Type
:
int16T
,
Size
:
16
,
T
:
IntTy
,
stringKind
:
"int16"
},
stringKind
:
"int16[]"
}},
{
"int16[2]"
,
Type
{
Size
:
2
,
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Type
:
reflect
.
TypeOf
([
2
]
int16
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Int16
,
Type
:
int16T
,
Size
:
16
,
T
:
IntTy
,
stringKind
:
"int16"
},
stringKind
:
"int16[2]"
}},
{
"int32[]"
,
Type
{
Kind
:
reflect
.
Slice
,
T
:
SliceTy
,
Type
:
reflect
.
TypeOf
([]
int32
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Int32
,
Type
:
int32T
,
Size
:
32
,
T
:
IntTy
,
stringKind
:
"int32"
},
stringKind
:
"int32[]"
}},
{
"int32[2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
]
int32
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Int32
,
Type
:
int32T
,
Size
:
32
,
T
:
IntTy
,
stringKind
:
"int32"
},
stringKind
:
"int32[2]"
}},
{
"int64[]"
,
Type
{
Kind
:
reflect
.
Slice
,
T
:
SliceTy
,
Type
:
reflect
.
TypeOf
([]
int64
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Int64
,
Type
:
int64T
,
Size
:
64
,
T
:
IntTy
,
stringKind
:
"int64"
},
stringKind
:
"int64[]"
}},
{
"int64[2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
]
int64
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Int64
,
Type
:
int64T
,
Size
:
64
,
T
:
IntTy
,
stringKind
:
"int64"
},
stringKind
:
"int64[2]"
}},
{
"int256[]"
,
Type
{
Kind
:
reflect
.
Slice
,
T
:
SliceTy
,
Type
:
reflect
.
TypeOf
([]
*
big
.
Int
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Ptr
,
Type
:
bigT
,
Size
:
256
,
T
:
IntTy
,
stringKind
:
"int256"
},
stringKind
:
"int256[]"
}},
{
"int256[2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
]
*
big
.
Int
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Ptr
,
Type
:
bigT
,
Size
:
256
,
T
:
IntTy
,
stringKind
:
"int256"
},
stringKind
:
"int256[2]"
}},
{
"uint8"
,
Type
{
Kind
:
reflect
.
Uint8
,
Type
:
uint8T
,
Size
:
8
,
T
:
UintTy
,
stringKind
:
"uint8"
}},
{
"uint16"
,
Type
{
Kind
:
reflect
.
Uint16
,
Type
:
uint16T
,
Size
:
16
,
T
:
UintTy
,
stringKind
:
"uint16"
}},
{
"uint32"
,
Type
{
Kind
:
reflect
.
Uint32
,
Type
:
uint32T
,
Size
:
32
,
T
:
UintTy
,
stringKind
:
"uint32"
}},
{
"uint64"
,
Type
{
Kind
:
reflect
.
Uint64
,
Type
:
uint64T
,
Size
:
64
,
T
:
UintTy
,
stringKind
:
"uint64"
}},
{
"uint256"
,
Type
{
Kind
:
reflect
.
Ptr
,
Type
:
bigT
,
Size
:
256
,
T
:
UintTy
,
stringKind
:
"uint256"
}},
{
"uint8[]"
,
Type
{
Kind
:
reflect
.
Slice
,
T
:
SliceTy
,
Type
:
reflect
.
TypeOf
([]
uint8
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Uint8
,
Type
:
uint8T
,
Size
:
8
,
T
:
UintTy
,
stringKind
:
"uint8"
},
stringKind
:
"uint8[]"
}},
{
"uint8[2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
]
uint8
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Uint8
,
Type
:
uint8T
,
Size
:
8
,
T
:
UintTy
,
stringKind
:
"uint8"
},
stringKind
:
"uint8[2]"
}},
{
"uint16[]"
,
Type
{
T
:
SliceTy
,
Kind
:
reflect
.
Slice
,
Type
:
reflect
.
TypeOf
([]
uint16
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Uint16
,
Type
:
uint16T
,
Size
:
16
,
T
:
UintTy
,
stringKind
:
"uint16"
},
stringKind
:
"uint16[]"
}},
{
"uint16[2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
]
uint16
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Uint16
,
Type
:
uint16T
,
Size
:
16
,
T
:
UintTy
,
stringKind
:
"uint16"
},
stringKind
:
"uint16[2]"
}},
{
"uint32[]"
,
Type
{
T
:
SliceTy
,
Kind
:
reflect
.
Slice
,
Type
:
reflect
.
TypeOf
([]
uint32
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Uint32
,
Type
:
uint32T
,
Size
:
32
,
T
:
UintTy
,
stringKind
:
"uint32"
},
stringKind
:
"uint32[]"
}},
{
"uint32[2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
]
uint32
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Uint32
,
Type
:
uint32T
,
Size
:
32
,
T
:
UintTy
,
stringKind
:
"uint32"
},
stringKind
:
"uint32[2]"
}},
{
"uint64[]"
,
Type
{
T
:
SliceTy
,
Kind
:
reflect
.
Slice
,
Type
:
reflect
.
TypeOf
([]
uint64
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Uint64
,
Type
:
uint64T
,
Size
:
64
,
T
:
UintTy
,
stringKind
:
"uint64"
},
stringKind
:
"uint64[]"
}},
{
"uint64[2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
]
uint64
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Uint64
,
Type
:
uint64T
,
Size
:
64
,
T
:
UintTy
,
stringKind
:
"uint64"
},
stringKind
:
"uint64[2]"
}},
{
"uint256[]"
,
Type
{
T
:
SliceTy
,
Kind
:
reflect
.
Slice
,
Type
:
reflect
.
TypeOf
([]
*
big
.
Int
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Ptr
,
Type
:
bigT
,
Size
:
256
,
T
:
UintTy
,
stringKind
:
"uint256"
},
stringKind
:
"uint256[]"
}},
{
"uint256[2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Type
:
reflect
.
TypeOf
([
2
]
*
big
.
Int
{}),
Size
:
2
,
Elem
:
&
Type
{
Kind
:
reflect
.
Ptr
,
Type
:
bigT
,
Size
:
256
,
T
:
UintTy
,
stringKind
:
"uint256"
},
stringKind
:
"uint256[2]"
}},
{
"bytes32"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
FixedBytesTy
,
Size
:
32
,
Type
:
reflect
.
TypeOf
([
32
]
byte
{}),
stringKind
:
"bytes32"
}},
{
"bytes[]"
,
Type
{
T
:
SliceTy
,
Kind
:
reflect
.
Slice
,
Type
:
reflect
.
TypeOf
([][]
byte
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Slice
,
Type
:
reflect
.
TypeOf
([]
byte
{}),
T
:
BytesTy
,
stringKind
:
"bytes"
},
stringKind
:
"bytes[]"
}},
{
"bytes[2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
][]
byte
{}),
Elem
:
&
Type
{
T
:
BytesTy
,
Type
:
reflect
.
TypeOf
([]
byte
{}),
Kind
:
reflect
.
Slice
,
stringKind
:
"bytes"
},
stringKind
:
"bytes[2]"
}},
{
"bytes32[]"
,
Type
{
T
:
SliceTy
,
Kind
:
reflect
.
Slice
,
Type
:
reflect
.
TypeOf
([][
32
]
byte
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Array
,
Type
:
reflect
.
TypeOf
([
32
]
byte
{}),
T
:
FixedBytesTy
,
Size
:
32
,
stringKind
:
"bytes32"
},
stringKind
:
"bytes32[]"
}},
{
"bytes32[2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
][
32
]
byte
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
Array
,
T
:
FixedBytesTy
,
Size
:
32
,
Type
:
reflect
.
TypeOf
([
32
]
byte
{}),
stringKind
:
"bytes32"
},
stringKind
:
"bytes32[2]"
}},
{
"string"
,
Type
{
Kind
:
reflect
.
String
,
T
:
StringTy
,
Type
:
reflect
.
TypeOf
(
""
),
stringKind
:
"string"
}},
{
"string[]"
,
Type
{
T
:
SliceTy
,
Kind
:
reflect
.
Slice
,
Type
:
reflect
.
TypeOf
([]
string
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
String
,
Type
:
reflect
.
TypeOf
(
""
),
T
:
StringTy
,
stringKind
:
"string"
},
stringKind
:
"string[]"
}},
{
"string[2]"
,
Type
{
Kind
:
reflect
.
Array
,
T
:
ArrayTy
,
Size
:
2
,
Type
:
reflect
.
TypeOf
([
2
]
string
{}),
Elem
:
&
Type
{
Kind
:
reflect
.
String
,
T
:
StringTy
,
Type
:
reflect
.
TypeOf
(
""
),
stringKind
:
"string"
},
stringKind
:
"string[2]"
}},
{
"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]"
}},
// TODO when fixed types are implemented properly
// {"fixed", Type{}},
// {"fixed128x128", Type{}},
// {"fixed[]", Type{}},
// {"fixed[2]", Type{}},
// {"fixed128x128[]", Type{}},
// {"fixed128x128[2]", Type{}},
}
for
_
,
tt
:=
range
tests
{
typ
,
err
:=
NewType
(
tt
.
blob
)
if
err
!=
nil
{
t
.
Errorf
(
"type %q: failed to parse type string: %v"
,
tt
.
blob
,
err
)
}
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
,
tt
.
kind
)
}
}
}
func
TestTypeCheck
(
t
*
testing
.
T
)
{
for
i
,
test
:=
range
[]
struct
{
typ
string
input
interface
{}
err
string
}{
{
"uint"
,
big
.
NewInt
(
1
),
"unsupported arg type: uint"
},
{
"int"
,
big
.
NewInt
(
1
),
"unsupported arg type: int"
},
{
"uint256"
,
big
.
NewInt
(
1
),
""
},
{
"uint256[][3][]"
,
[][
3
][]
*
big
.
Int
{{{}}},
""
},
{
"uint256[][][3]"
,
[
3
][][]
*
big
.
Int
{{{}}},
""
},
{
"uint256[3][][]"
,
[][][
3
]
*
big
.
Int
{{{}}},
""
},
{
"uint256[3][3][3]"
,
[
3
][
3
][
3
]
*
big
.
Int
{{{}}},
""
},
{
"uint8[][]"
,
[][]
uint8
{},
""
},
{
"int256"
,
big
.
NewInt
(
1
),
""
},
{
"uint8"
,
uint8
(
1
),
""
},
{
"uint16"
,
uint16
(
1
),
""
},
{
"uint32"
,
uint32
(
1
),
""
},
{
"uint64"
,
uint64
(
1
),
""
},
{
"int8"
,
int8
(
1
),
""
},
{
"int16"
,
int16
(
1
),
""
},
{
"int32"
,
int32
(
1
),
""
},
{
"int64"
,
int64
(
1
),
""
},
{
"uint24"
,
big
.
NewInt
(
1
),
""
},
{
"uint40"
,
big
.
NewInt
(
1
),
""
},
{
"uint48"
,
big
.
NewInt
(
1
),
""
},
{
"uint56"
,
big
.
NewInt
(
1
),
""
},
{
"uint72"
,
big
.
NewInt
(
1
),
""
},
{
"uint80"
,
big
.
NewInt
(
1
),
""
},
{
"uint88"
,
big
.
NewInt
(
1
),
""
},
{
"uint96"
,
big
.
NewInt
(
1
),
""
},
{
"uint104"
,
big
.
NewInt
(
1
),
""
},
{
"uint112"
,
big
.
NewInt
(
1
),
""
},
{
"uint120"
,
big
.
NewInt
(
1
),
""
},
{
"uint128"
,
big
.
NewInt
(
1
),
""
},
{
"uint136"
,
big
.
NewInt
(
1
),
""
},
{
"uint144"
,
big
.
NewInt
(
1
),
""
},
{
"uint152"
,
big
.
NewInt
(
1
),
""
},
{
"uint160"
,
big
.
NewInt
(
1
),
""
},
{
"uint168"
,
big
.
NewInt
(
1
),
""
},
{
"uint176"
,
big
.
NewInt
(
1
),
""
},
{
"uint184"
,
big
.
NewInt
(
1
),
""
},
{
"uint192"
,
big
.
NewInt
(
1
),
""
},
{
"uint200"
,
big
.
NewInt
(
1
),
""
},
{
"uint208"
,
big
.
NewInt
(
1
),
""
},
{
"uint216"
,
big
.
NewInt
(
1
),
""
},
{
"uint224"
,
big
.
NewInt
(
1
),
""
},
{
"uint232"
,
big
.
NewInt
(
1
),
""
},
{
"uint240"
,
big
.
NewInt
(
1
),
""
},
{
"uint248"
,
big
.
NewInt
(
1
),
""
},
{
"int24"
,
big
.
NewInt
(
1
),
""
},
{
"int40"
,
big
.
NewInt
(
1
),
""
},
{
"int48"
,
big
.
NewInt
(
1
),
""
},
{
"int56"
,
big
.
NewInt
(
1
),
""
},
{
"int72"
,
big
.
NewInt
(
1
),
""
},
{
"int80"
,
big
.
NewInt
(
1
),
""
},
{
"int88"
,
big
.
NewInt
(
1
),
""
},
{
"int96"
,
big
.
NewInt
(
1
),
""
},
{
"int104"
,
big
.
NewInt
(
1
),
""
},
{
"int112"
,
big
.
NewInt
(
1
),
""
},
{
"int120"
,
big
.
NewInt
(
1
),
""
},
{
"int128"
,
big
.
NewInt
(
1
),
""
},
{
"int136"
,
big
.
NewInt
(
1
),
""
},
{
"int144"
,
big
.
NewInt
(
1
),
""
},
{
"int152"
,
big
.
NewInt
(
1
),
""
},
{
"int160"
,
big
.
NewInt
(
1
),
""
},
{
"int168"
,
big
.
NewInt
(
1
),
""
},
{
"int176"
,
big
.
NewInt
(
1
),
""
},
{
"int184"
,
big
.
NewInt
(
1
),
""
},
{
"int192"
,
big
.
NewInt
(
1
),
""
},
{
"int200"
,
big
.
NewInt
(
1
),
""
},
{
"int208"
,
big
.
NewInt
(
1
),
""
},
{
"int216"
,
big
.
NewInt
(
1
),
""
},
{
"int224"
,
big
.
NewInt
(
1
),
""
},
{
"int232"
,
big
.
NewInt
(
1
),
""
},
{
"int240"
,
big
.
NewInt
(
1
),
""
},
{
"int248"
,
big
.
NewInt
(
1
),
""
},
{
"uint30"
,
uint8
(
1
),
"abi: cannot use uint8 as type ptr as argument"
},
{
"uint8"
,
uint16
(
1
),
"abi: cannot use uint16 as type uint8 as argument"
},
{
"uint8"
,
uint32
(
1
),
"abi: cannot use uint32 as type uint8 as argument"
},
{
"uint8"
,
uint64
(
1
),
"abi: cannot use uint64 as type uint8 as argument"
},
{
"uint8"
,
int8
(
1
),
"abi: cannot use int8 as type uint8 as argument"
},
{
"uint8"
,
int16
(
1
),
"abi: cannot use int16 as type uint8 as argument"
},
{
"uint8"
,
int32
(
1
),
"abi: cannot use int32 as type uint8 as argument"
},
{
"uint8"
,
int64
(
1
),
"abi: cannot use int64 as type uint8 as argument"
},
{
"uint16"
,
uint16
(
1
),
""
},
{
"uint16"
,
uint8
(
1
),
"abi: cannot use uint8 as type uint16 as argument"
},
{
"uint16[]"
,
[]
uint16
{
1
,
2
,
3
},
""
},
{
"uint16[]"
,
[
3
]
uint16
{
1
,
2
,
3
},
""
},
{
"uint16[]"
,
[]
uint32
{
1
,
2
,
3
},
"abi: cannot use []uint32 as type [0]uint16 as argument"
},
{
"uint16[3]"
,
[
3
]
uint32
{
1
,
2
,
3
},
"abi: cannot use [3]uint32 as type [3]uint16 as argument"
},
{
"uint16[3]"
,
[
4
]
uint16
{
1
,
2
,
3
},
"abi: cannot use [4]uint16 as type [3]uint16 as argument"
},
{
"uint16[3]"
,
[]
uint16
{
1
,
2
,
3
},
""
},
{
"uint16[3]"
,
[]
uint16
{
1
,
2
,
3
,
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"
},
{
"bytes32"
,
[
32
]
byte
{},
""
},
{
"bytes31"
,
[
31
]
byte
{},
""
},
{
"bytes30"
,
[
30
]
byte
{},
""
},
{
"bytes29"
,
[
29
]
byte
{},
""
},
{
"bytes28"
,
[
28
]
byte
{},
""
},
{
"bytes27"
,
[
27
]
byte
{},
""
},
{
"bytes26"
,
[
26
]
byte
{},
""
},
{
"bytes25"
,
[
25
]
byte
{},
""
},
{
"bytes24"
,
[
24
]
byte
{},
""
},
{
"bytes23"
,
[
23
]
byte
{},
""
},
{
"bytes22"
,
[
22
]
byte
{},
""
},
{
"bytes21"
,
[
21
]
byte
{},
""
},
{
"bytes20"
,
[
20
]
byte
{},
""
},
{
"bytes19"
,
[
19
]
byte
{},
""
},
{
"bytes18"
,
[
18
]
byte
{},
""
},
{
"bytes17"
,
[
17
]
byte
{},
""
},
{
"bytes16"
,
[
16
]
byte
{},
""
},
{
"bytes15"
,
[
15
]
byte
{},
""
},
{
"bytes14"
,
[
14
]
byte
{},
""
},
{
"bytes13"
,
[
13
]
byte
{},
""
},
{
"bytes12"
,
[
12
]
byte
{},
""
},
{
"bytes11"
,
[
11
]
byte
{},
""
},
{
"bytes10"
,
[
10
]
byte
{},
""
},
{
"bytes9"
,
[
9
]
byte
{},
""
},
{
"bytes8"
,
[
8
]
byte
{},
""
},
{
"bytes7"
,
[
7
]
byte
{},
""
},
{
"bytes6"
,
[
6
]
byte
{},
""
},
{
"bytes5"
,
[
5
]
byte
{},
""
},
{
"bytes4"
,
[
4
]
byte
{},
""
},
{
"bytes3"
,
[
3
]
byte
{},
""
},
{
"bytes2"
,
[
2
]
byte
{},
""
},
{
"bytes1"
,
[
1
]
byte
{},
""
},
{
"bytes32"
,
[
33
]
byte
{},
"abi: cannot use [33]uint8 as type [32]uint8 as argument"
},
{
"bytes32"
,
common
.
Hash
{
1
},
""
},
{
"bytes31"
,
common
.
Hash
{
1
},
"abi: cannot use common.Hash as type [31]uint8 as argument"
},
{
"bytes31"
,
[
32
]
byte
{},
"abi: cannot use [32]uint8 as type [31]uint8 as argument"
},
{
"bytes"
,
[]
byte
{
0
,
1
},
""
},
{
"bytes"
,
[
2
]
byte
{
0
,
1
},
"abi: cannot use array as type slice as argument"
},
{
"bytes"
,
common
.
Hash
{
1
},
"abi: cannot use array as type slice as argument"
},
{
"string"
,
"hello world"
,
""
},
{
"string"
,
string
(
""
),
""
},
{
"string"
,
[]
byte
{},
"abi: cannot use slice as type string as argument"
},
{
"bytes32[]"
,
[][
32
]
byte
{{}},
""
},
{
"function"
,
[
24
]
byte
{},
""
},
{
"bytes20"
,
common
.
Hash160Address
{},
""
},
{
"address"
,
[
20
]
byte
{},
""
},
{
"address"
,
common
.
Hash160Address
{},
""
},
{
"bytes32[]]"
,
""
,
"invalid arg type in abi"
},
{
"invalidType"
,
""
,
"unsupported arg type: invalidType"
},
{
"invalidSlice[]"
,
""
,
"unsupported arg type: invalidSlice"
},
}
{
typ
,
err
:=
NewType
(
test
.
typ
)
if
err
!=
nil
&&
len
(
test
.
err
)
==
0
{
t
.
Fatal
(
"unexpected parse error:"
,
err
)
}
else
if
err
!=
nil
&&
len
(
test
.
err
)
!=
0
{
if
err
.
Error
()
!=
test
.
err
{
t
.
Errorf
(
"%d failed. Expected err: '%v' got err: '%v'"
,
i
,
test
.
err
,
err
)
}
continue
}
err
=
typeCheck
(
typ
,
reflect
.
ValueOf
(
test
.
input
))
if
err
!=
nil
&&
len
(
test
.
err
)
==
0
{
t
.
Errorf
(
"%d failed. Expected no err but got: %v"
,
i
,
err
)
continue
}
if
err
==
nil
&&
len
(
test
.
err
)
!=
0
{
t
.
Errorf
(
"%d failed. Expected err: %v but got none"
,
i
,
test
.
err
)
continue
}
if
err
!=
nil
&&
len
(
test
.
err
)
!=
0
&&
err
.
Error
()
!=
test
.
err
{
t
.
Errorf
(
"%d failed. Expected err: '%v' got err: '%v'"
,
i
,
test
.
err
,
err
)
}
}
}
plugin/dapp/evm/executor/abi/unpack.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"encoding/binary"
"fmt"
"math/big"
"reflect"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
)
var
(
maxUint256
=
big
.
NewInt
(
0
)
.
Add
(
big
.
NewInt
(
0
)
.
Exp
(
big
.
NewInt
(
2
),
big
.
NewInt
(
256
),
nil
),
big
.
NewInt
(
-
1
))
maxInt256
=
big
.
NewInt
(
0
)
.
Add
(
big
.
NewInt
(
0
)
.
Exp
(
big
.
NewInt
(
2
),
big
.
NewInt
(
255
),
nil
),
big
.
NewInt
(
-
1
))
)
// reads the integer based on its kind
func
readInteger
(
typ
byte
,
kind
reflect
.
Kind
,
b
[]
byte
)
interface
{}
{
switch
kind
{
case
reflect
.
Uint8
:
return
b
[
len
(
b
)
-
1
]
case
reflect
.
Uint16
:
return
binary
.
BigEndian
.
Uint16
(
b
[
len
(
b
)
-
2
:
])
case
reflect
.
Uint32
:
return
binary
.
BigEndian
.
Uint32
(
b
[
len
(
b
)
-
4
:
])
case
reflect
.
Uint64
:
return
binary
.
BigEndian
.
Uint64
(
b
[
len
(
b
)
-
8
:
])
case
reflect
.
Int8
:
return
int8
(
b
[
len
(
b
)
-
1
])
case
reflect
.
Int16
:
return
int16
(
binary
.
BigEndian
.
Uint16
(
b
[
len
(
b
)
-
2
:
]))
case
reflect
.
Int32
:
return
int32
(
binary
.
BigEndian
.
Uint32
(
b
[
len
(
b
)
-
4
:
]))
case
reflect
.
Int64
:
return
int64
(
binary
.
BigEndian
.
Uint64
(
b
[
len
(
b
)
-
8
:
]))
default
:
// the only case lefts for integer is int256/uint256.
// big.SetBytes can't tell if a number is negative, positive on itself.
// On EVM, if the returned number > max int256, it is negative.
ret
:=
new
(
big
.
Int
)
.
SetBytes
(
b
)
if
typ
==
UintTy
{
return
ret
}
if
ret
.
Cmp
(
maxInt256
)
>
0
{
ret
.
Add
(
maxUint256
,
big
.
NewInt
(
0
)
.
Neg
(
ret
))
ret
.
Add
(
ret
,
big
.
NewInt
(
1
))
ret
.
Neg
(
ret
)
}
return
ret
}
}
// reads a bool
func
readBool
(
word
[]
byte
)
(
bool
,
error
)
{
for
_
,
b
:=
range
word
[
:
31
]
{
if
b
!=
0
{
return
false
,
errBadBool
}
}
switch
word
[
31
]
{
case
0
:
return
false
,
nil
case
1
:
return
true
,
nil
default
:
return
false
,
errBadBool
}
}
// A function type is simply the address with the function selection signature at the end.
// This enforces that standard by always presenting it as a 24-array (address + sig = 24 bytes)
func
readFunctionType
(
t
Type
,
word
[]
byte
)
(
funcTy
[
24
]
byte
,
err
error
)
{
if
t
.
T
!=
FunctionTy
{
return
[
24
]
byte
{},
fmt
.
Errorf
(
"abi: invalid type in call to make function type byte array"
)
}
if
garbage
:=
binary
.
BigEndian
.
Uint64
(
word
[
24
:
32
]);
garbage
!=
0
{
err
=
fmt
.
Errorf
(
"abi: got improperly encoded function type, got %v"
,
word
)
}
else
{
copy
(
funcTy
[
:
],
word
[
0
:
24
])
}
return
}
// through reflection, creates a fixed array to be read from
func
readFixedBytes
(
t
Type
,
word
[]
byte
)
(
interface
{},
error
)
{
if
t
.
T
!=
FixedBytesTy
{
return
nil
,
fmt
.
Errorf
(
"abi: invalid type in call to make fixed byte array"
)
}
// convert
array
:=
reflect
.
New
(
t
.
Type
)
.
Elem
()
reflect
.
Copy
(
array
,
reflect
.
ValueOf
(
word
[
0
:
t
.
Size
]))
return
array
.
Interface
(),
nil
}
func
getFullElemSize
(
elem
*
Type
)
int
{
//all other should be counted as 32 (slices have pointers to respective elements)
size
:=
32
//arrays wrap it, each element being the same size
for
elem
.
T
==
ArrayTy
{
size
*=
elem
.
Size
elem
=
elem
.
Elem
}
return
size
}
// iteratively unpack elements
func
forEachUnpack
(
t
Type
,
output
[]
byte
,
start
,
size
int
)
(
interface
{},
error
)
{
if
size
<
0
{
return
nil
,
fmt
.
Errorf
(
"cannot marshal input to array, size is negative (%d)"
,
size
)
}
if
start
+
32
*
size
>
len
(
output
)
{
return
nil
,
fmt
.
Errorf
(
"abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)"
,
len
(
output
),
start
+
32
*
size
)
}
// this value will become our slice or our array, depending on the type
var
refSlice
reflect
.
Value
if
t
.
T
==
SliceTy
{
// declare our slice
refSlice
=
reflect
.
MakeSlice
(
t
.
Type
,
size
,
size
)
}
else
if
t
.
T
==
ArrayTy
{
// declare our array
refSlice
=
reflect
.
New
(
t
.
Type
)
.
Elem
()
}
else
{
return
nil
,
fmt
.
Errorf
(
"abi: invalid type in array/slice unpacking stage"
)
}
// Arrays have packed elements, resulting in longer unpack steps.
// Slices have just 32 bytes per element (pointing to the contents).
elemSize
:=
32
if
t
.
T
==
ArrayTy
{
elemSize
=
getFullElemSize
(
t
.
Elem
)
}
for
i
,
j
:=
start
,
0
;
j
<
size
;
i
,
j
=
i
+
elemSize
,
j
+
1
{
inter
,
err
:=
toGoType
(
i
,
*
t
.
Elem
,
output
)
if
err
!=
nil
{
return
nil
,
err
}
// append the item to our reflect slice
refSlice
.
Index
(
j
)
.
Set
(
reflect
.
ValueOf
(
inter
))
}
// return the interface
return
refSlice
.
Interface
(),
nil
}
// toGoType parses the output bytes and recursively assigns the value of these bytes
// into a go type with accordance with the ABI spec.
func
toGoType
(
index
int
,
t
Type
,
output
[]
byte
)
(
interface
{},
error
)
{
if
index
+
32
>
len
(
output
)
{
return
nil
,
fmt
.
Errorf
(
"abi: cannot marshal in to go type: length insufficient %d require %d"
,
len
(
output
),
index
+
32
)
}
var
(
returnOutput
[]
byte
begin
,
end
int
err
error
)
// if we require a length prefix, find the beginning word and size returned.
if
t
.
requiresLengthPrefix
()
{
begin
,
end
,
err
=
lengthPrefixPointsTo
(
index
,
output
)
if
err
!=
nil
{
return
nil
,
err
}
}
else
{
returnOutput
=
output
[
index
:
index
+
32
]
}
switch
t
.
T
{
case
SliceTy
:
return
forEachUnpack
(
t
,
output
,
begin
,
end
)
case
ArrayTy
:
return
forEachUnpack
(
t
,
output
,
index
,
t
.
Size
)
case
StringTy
:
// variable arrays are written at the end of the return bytes
return
string
(
output
[
begin
:
begin
+
end
]),
nil
case
IntTy
,
UintTy
:
return
readInteger
(
t
.
T
,
t
.
Kind
,
returnOutput
),
nil
case
BoolTy
:
return
readBool
(
returnOutput
)
case
AddressTy
:
return
common
.
BytesToHash160Address
(
returnOutput
),
nil
case
HashTy
:
return
common
.
BytesToHash
(
returnOutput
),
nil
case
BytesTy
:
return
output
[
begin
:
begin
+
end
],
nil
case
FixedBytesTy
:
return
readFixedBytes
(
t
,
returnOutput
)
case
FunctionTy
:
return
readFunctionType
(
t
,
returnOutput
)
default
:
return
nil
,
fmt
.
Errorf
(
"abi: unknown type %v"
,
t
.
T
)
}
}
// interprets a 32 byte slice as an offset and then determines which indice to look to decode the type.
func
lengthPrefixPointsTo
(
index
int
,
output
[]
byte
)
(
start
int
,
length
int
,
err
error
)
{
bigOffsetEnd
:=
big
.
NewInt
(
0
)
.
SetBytes
(
output
[
index
:
index
+
32
])
bigOffsetEnd
.
Add
(
bigOffsetEnd
,
common
.
Big32
)
outputLength
:=
big
.
NewInt
(
int64
(
len
(
output
)))
if
bigOffsetEnd
.
Cmp
(
outputLength
)
>
0
{
return
0
,
0
,
fmt
.
Errorf
(
"abi: cannot marshal in to go slice: offset %v would go over slice boundary (len=%v)"
,
bigOffsetEnd
,
outputLength
)
}
if
bigOffsetEnd
.
BitLen
()
>
63
{
return
0
,
0
,
fmt
.
Errorf
(
"abi offset larger than int64: %v"
,
bigOffsetEnd
)
}
offsetEnd
:=
int
(
bigOffsetEnd
.
Uint64
())
lengthBig
:=
big
.
NewInt
(
0
)
.
SetBytes
(
output
[
offsetEnd
-
32
:
offsetEnd
])
totalSize
:=
big
.
NewInt
(
0
)
totalSize
.
Add
(
totalSize
,
bigOffsetEnd
)
totalSize
.
Add
(
totalSize
,
lengthBig
)
if
totalSize
.
BitLen
()
>
63
{
return
0
,
0
,
fmt
.
Errorf
(
"abi length larger than int64: %v"
,
totalSize
)
}
if
totalSize
.
Cmp
(
outputLength
)
>
0
{
return
0
,
0
,
fmt
.
Errorf
(
"abi: cannot marshal in to go type: length insufficient %v require %v"
,
outputLength
,
totalSize
)
}
start
=
int
(
bigOffsetEnd
.
Uint64
())
length
=
int
(
lengthBig
.
Uint64
())
return
}
plugin/dapp/evm/executor/abi/unpack_test.go
0 → 100644
View file @
b2ebdcd4
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
abi
import
(
"bytes"
"encoding/hex"
"fmt"
"math/big"
"reflect"
"strconv"
"strings"
"testing"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/stretchr/testify/require"
)
type
unpackTest
struct
{
def
string
// ABI definition JSON
enc
string
// evm return data
want
interface
{}
// the expected output
err
string
// empty or error if expected
}
func
(
test
unpackTest
)
checkError
(
err
error
)
error
{
if
err
!=
nil
{
if
len
(
test
.
err
)
==
0
{
return
fmt
.
Errorf
(
"expected no err but got: %v"
,
err
)
}
else
if
err
.
Error
()
!=
test
.
err
{
return
fmt
.
Errorf
(
"expected err: '%v' got err: %q"
,
test
.
err
,
err
)
}
}
else
if
len
(
test
.
err
)
>
0
{
return
fmt
.
Errorf
(
"expected err: %v but got none"
,
test
.
err
)
}
return
nil
}
var
unpackTests
=
[]
unpackTest
{
{
def
:
`[{ "type": "bool" }]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000001"
,
want
:
true
,
},
{
def
:
`[{ "type": "bool" }]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000000"
,
want
:
false
,
},
{
def
:
`[{ "type": "bool" }]`
,
enc
:
"0000000000000000000000000000000000000000000000000001000000000001"
,
want
:
false
,
err
:
"abi: improperly encoded boolean value"
,
},
{
def
:
`[{ "type": "bool" }]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000003"
,
want
:
false
,
err
:
"abi: improperly encoded boolean value"
,
},
{
def
:
`[{"type": "uint32"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000001"
,
want
:
uint32
(
1
),
},
{
def
:
`[{"type": "uint32"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000001"
,
want
:
uint16
(
0
),
err
:
"abi: cannot unmarshal uint32 in to uint16"
,
},
{
def
:
`[{"type": "uint17"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000001"
,
want
:
uint16
(
0
),
err
:
"abi: cannot unmarshal *big.Int in to uint16"
,
},
{
def
:
`[{"type": "uint17"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000001"
,
want
:
big
.
NewInt
(
1
),
},
{
def
:
`[{"type": "int32"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000001"
,
want
:
int32
(
1
),
},
{
def
:
`[{"type": "int32"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000001"
,
want
:
int16
(
0
),
err
:
"abi: cannot unmarshal int32 in to int16"
,
},
{
def
:
`[{"type": "int17"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000001"
,
want
:
int16
(
0
),
err
:
"abi: cannot unmarshal *big.Int in to int16"
,
},
{
def
:
`[{"type": "int17"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000001"
,
want
:
big
.
NewInt
(
1
),
},
{
def
:
`[{"type": "int256"}]`
,
enc
:
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
,
want
:
big
.
NewInt
(
-
1
),
},
{
def
:
`[{"type": "address"}]`
,
enc
:
"0000000000000000000000000100000000000000000000000000000000000000"
,
want
:
common
.
Hash160Address
{
1
},
},
{
def
:
`[{"type": "bytes32"}]`
,
enc
:
"0100000000000000000000000000000000000000000000000000000000000000"
,
want
:
[
32
]
byte
{
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
},
},
{
def
:
`[{"type": "bytes"}]`
,
enc
:
"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000"
,
want
:
common
.
Hex2Bytes
(
"0100000000000000000000000000000000000000000000000000000000000000"
),
},
{
def
:
`[{"type": "bytes"}]`
,
enc
:
"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000"
,
want
:
[
32
]
byte
{},
err
:
"abi: cannot unmarshal []uint8 in to [32]uint8"
,
},
{
def
:
`[{"type": "bytes32"}]`
,
enc
:
"000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000000000000000000000000000000000000000"
,
want
:
[]
byte
(
nil
),
err
:
"abi: cannot unmarshal [32]uint8 in to []uint8"
,
},
{
def
:
`[{"type": "bytes32"}]`
,
enc
:
"0100000000000000000000000000000000000000000000000000000000000000"
,
want
:
[
32
]
byte
{
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
},
},
{
def
:
`[{"type": "function"}]`
,
enc
:
"0100000000000000000000000000000000000000000000000000000000000000"
,
want
:
[
24
]
byte
{
1
},
},
// slices
{
def
:
`[{"type": "uint8[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[]
uint8
{
1
,
2
},
},
{
def
:
`[{"type": "uint8[2]"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[
2
]
uint8
{
1
,
2
},
},
// multi dimensional, if these pass, all types that don't require length prefix should pass
{
def
:
`[{"type": "uint8[][]"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000E0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[][]
uint8
{{
1
,
2
},
{
1
,
2
}},
},
{
def
:
`[{"type": "uint8[2][2]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[
2
][
2
]
uint8
{{
1
,
2
},
{
1
,
2
}},
},
{
def
:
`[{"type": "uint8[][2]"}]`
,
enc
:
"000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001"
,
want
:
[
2
][]
uint8
{{
1
},
{
1
}},
},
{
def
:
`[{"type": "uint8[2][]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[][
2
]
uint8
{{
1
,
2
}},
},
{
def
:
`[{"type": "uint16[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[]
uint16
{
1
,
2
},
},
{
def
:
`[{"type": "uint16[2]"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[
2
]
uint16
{
1
,
2
},
},
{
def
:
`[{"type": "uint32[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[]
uint32
{
1
,
2
},
},
{
def
:
`[{"type": "uint32[2]"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[
2
]
uint32
{
1
,
2
},
},
{
def
:
`[{"type": "uint32[2][3][4]"}]`
,
enc
:
"000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000110000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001300000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000015000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000018"
,
want
:
[
4
][
3
][
2
]
uint32
{{{
1
,
2
},
{
3
,
4
},
{
5
,
6
}},
{{
7
,
8
},
{
9
,
10
},
{
11
,
12
}},
{{
13
,
14
},
{
15
,
16
},
{
17
,
18
}},
{{
19
,
20
},
{
21
,
22
},
{
23
,
24
}}},
},
{
def
:
`[{"type": "uint64[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[]
uint64
{
1
,
2
},
},
{
def
:
`[{"type": "uint64[2]"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[
2
]
uint64
{
1
,
2
},
},
{
def
:
`[{"type": "uint256[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
)},
},
{
def
:
`[{"type": "uint256[3]"}]`
,
enc
:
"000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003"
,
want
:
[
3
]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
),
big
.
NewInt
(
3
)},
},
{
def
:
`[{"type": "int8[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[]
int8
{
1
,
2
},
},
{
def
:
`[{"type": "int8[2]"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[
2
]
int8
{
1
,
2
},
},
{
def
:
`[{"type": "int16[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[]
int16
{
1
,
2
},
},
{
def
:
`[{"type": "int16[2]"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[
2
]
int16
{
1
,
2
},
},
{
def
:
`[{"type": "int32[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[]
int32
{
1
,
2
},
},
{
def
:
`[{"type": "int32[2]"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[
2
]
int32
{
1
,
2
},
},
{
def
:
`[{"type": "int64[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[]
int64
{
1
,
2
},
},
{
def
:
`[{"type": "int64[2]"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[
2
]
int64
{
1
,
2
},
},
{
def
:
`[{"type": "int256[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
[]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
)},
},
{
def
:
`[{"type": "int256[3]"}]`
,
enc
:
"000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003"
,
want
:
[
3
]
*
big
.
Int
{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
),
big
.
NewInt
(
3
)},
},
// struct outputs
{
def
:
`[{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
struct
{
Int1
*
big
.
Int
Int2
*
big
.
Int
}{
big
.
NewInt
(
1
),
big
.
NewInt
(
2
)},
},
{
def
:
`[{"name":"int","type":"int256"},{"name":"Int","type":"int256"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
struct
{
Int1
*
big
.
Int
Int2
*
big
.
Int
}{},
err
:
"abi: multiple outputs mapping to the same struct field 'Int'"
,
},
{
def
:
`[{"name":"int","type":"int256"},{"name":"_int","type":"int256"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
struct
{
Int1
*
big
.
Int
Int2
*
big
.
Int
}{},
err
:
"abi: multiple outputs mapping to the same struct field 'Int'"
,
},
{
def
:
`[{"name":"Int","type":"int256"},{"name":"_int","type":"int256"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
struct
{
Int1
*
big
.
Int
Int2
*
big
.
Int
}{},
err
:
"abi: multiple outputs mapping to the same struct field 'Int'"
,
},
{
def
:
`[{"name":"Int","type":"int256"},{"name":"_","type":"int256"}]`
,
enc
:
"00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002"
,
want
:
struct
{
Int1
*
big
.
Int
Int2
*
big
.
Int
}{},
err
:
"abi: purely underscored output cannot unpack to struct"
,
},
}
func
TestUnpack
(
t
*
testing
.
T
)
{
for
i
,
test
:=
range
unpackTests
{
t
.
Run
(
strconv
.
Itoa
(
i
),
func
(
t
*
testing
.
T
)
{
def
:=
fmt
.
Sprintf
(
`[{ "name" : "method", "outputs": %s}]`
,
test
.
def
)
abi
,
err
:=
JSON
(
strings
.
NewReader
(
def
))
if
err
!=
nil
{
t
.
Fatalf
(
"invalid ABI definition %s: %v"
,
def
,
err
)
}
encb
,
err
:=
hex
.
DecodeString
(
test
.
enc
)
if
err
!=
nil
{
t
.
Fatalf
(
"invalid hex: %s"
+
test
.
enc
)
}
outptr
:=
reflect
.
New
(
reflect
.
TypeOf
(
test
.
want
))
err
=
abi
.
Unpack
(
outptr
.
Interface
(),
"method"
,
encb
)
if
err
:=
test
.
checkError
(
err
);
err
!=
nil
{
t
.
Errorf
(
"test %d (%v) failed: %v"
,
i
,
test
.
def
,
err
)
return
}
out
:=
outptr
.
Elem
()
.
Interface
()
if
!
reflect
.
DeepEqual
(
test
.
want
,
out
)
{
t
.
Errorf
(
"test %d (%v) failed: expected %v, got %v"
,
i
,
test
.
def
,
test
.
want
,
out
)
}
})
}
}
type
methodMultiOutput
struct
{
Int
*
big
.
Int
String
string
}
func
methodMultiReturn
(
require
*
require
.
Assertions
)
(
ABI
,
[]
byte
,
methodMultiOutput
)
{
const
definition
=
`[
{ "name" : "multi", "constant" : false, "outputs": [ { "name": "Int", "type": "uint256" }, { "name": "String", "type": "string" } ] }]`
var
expected
=
methodMultiOutput
{
big
.
NewInt
(
1
),
"hello"
}
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
require
.
NoError
(
err
)
// using buff to make the code readable
buff
:=
new
(
bytes
.
Buffer
)
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000001"
))
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000040"
))
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000005"
))
buff
.
Write
(
common
.
RightPadBytes
([]
byte
(
expected
.
String
),
32
))
return
abi
,
buff
.
Bytes
(),
expected
}
func
TestMethodMultiReturn
(
t
*
testing
.
T
)
{
type
reversed
struct
{
String
string
Int
*
big
.
Int
}
abi
,
data
,
expected
:=
methodMultiReturn
(
require
.
New
(
t
))
bigint
:=
new
(
big
.
Int
)
var
testCases
=
[]
struct
{
dest
interface
{}
expected
interface
{}
error
string
name
string
}{{
&
methodMultiOutput
{},
&
expected
,
""
,
"Can unpack into structure"
,
},
{
&
reversed
{},
&
reversed
{
expected
.
String
,
expected
.
Int
},
""
,
"Can unpack into reversed structure"
,
},
{
&
[]
interface
{}{
&
bigint
,
new
(
string
)},
&
[]
interface
{}{
&
expected
.
Int
,
&
expected
.
String
},
""
,
"Can unpack into a slice"
,
},
{
&
[
2
]
interface
{}{
&
bigint
,
new
(
string
)},
&
[
2
]
interface
{}{
&
expected
.
Int
,
&
expected
.
String
},
""
,
"Can unpack into an array"
,
},
{
&
[]
interface
{}{
new
(
int
),
new
(
int
)},
&
[]
interface
{}{
&
expected
.
Int
,
&
expected
.
String
},
"abi: cannot unmarshal *big.Int in to int"
,
"Can not unpack into a slice with wrong types"
,
},
{
&
[]
interface
{}{
new
(
int
)},
&
[]
interface
{}{},
"abi: insufficient number of elements in the list/array for unpack, want 2, got 1"
,
"Can not unpack into a slice with wrong types"
,
}}
for
_
,
tc
:=
range
testCases
{
tc
:=
tc
t
.
Run
(
tc
.
name
,
func
(
t
*
testing
.
T
)
{
require
:=
require
.
New
(
t
)
err
:=
abi
.
Unpack
(
tc
.
dest
,
"multi"
,
data
)
if
tc
.
error
==
""
{
require
.
Nil
(
err
,
"Should be able to unpack method outputs."
)
require
.
Equal
(
tc
.
expected
,
tc
.
dest
)
}
else
{
require
.
EqualError
(
err
,
tc
.
error
)
}
})
}
}
func
TestMultiReturnWithArray
(
t
*
testing
.
T
)
{
const
definition
=
`[{"name" : "multi", "outputs": [{"type": "uint64[3]"}, {"type": "uint64"}]}]`
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
buff
:=
new
(
bytes
.
Buffer
)
buff
.
Write
(
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000090000000000000000000000000000000000000000000000000000000000000009"
))
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000008"
))
ret1
,
ret1Exp
:=
new
([
3
]
uint64
),
[
3
]
uint64
{
9
,
9
,
9
}
ret2
,
ret2Exp
:=
new
(
uint64
),
uint64
(
8
)
if
err
:=
abi
.
Unpack
(
&
[]
interface
{}{
ret1
,
ret2
},
"multi"
,
buff
.
Bytes
());
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
!
reflect
.
DeepEqual
(
*
ret1
,
ret1Exp
)
{
t
.
Error
(
"array result"
,
*
ret1
,
"!= Expected"
,
ret1Exp
)
}
if
*
ret2
!=
ret2Exp
{
t
.
Error
(
"int result"
,
*
ret2
,
"!= Expected"
,
ret2Exp
)
}
}
func
TestMultiReturnWithDeeplyNestedArray
(
t
*
testing
.
T
)
{
// Similar to TestMultiReturnWithArray, but with a special case in mind:
// values of nested static arrays count towards the size as well, and any element following
// after such nested array argument should be read with the correct offset,
// so that it does not read content from the previous array argument.
const
definition
=
`[{"name" : "multi", "outputs": [{"type": "uint64[3][2][4]"}, {"type": "uint64"}]}]`
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
buff
:=
new
(
bytes
.
Buffer
)
// construct the test array, each 3 char element is joined with 61 '0' chars,
// to from the ((3 + 61) * 0.5) = 32 byte elements in the array.
buff
.
Write
(
common
.
Hex2Bytes
(
strings
.
Join
([]
string
{
""
,
//empty, to apply the 61-char separator to the first element as well.
"111"
,
"112"
,
"113"
,
"121"
,
"122"
,
"123"
,
"211"
,
"212"
,
"213"
,
"221"
,
"222"
,
"223"
,
"311"
,
"312"
,
"313"
,
"321"
,
"322"
,
"323"
,
"411"
,
"412"
,
"413"
,
"421"
,
"422"
,
"423"
,
},
"0000000000000000000000000000000000000000000000000000000000000"
)))
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000009876"
))
ret1
,
ret1Exp
:=
new
([
4
][
2
][
3
]
uint64
),
[
4
][
2
][
3
]
uint64
{
{{
0x111
,
0x112
,
0x113
},
{
0x121
,
0x122
,
0x123
}},
{{
0x211
,
0x212
,
0x213
},
{
0x221
,
0x222
,
0x223
}},
{{
0x311
,
0x312
,
0x313
},
{
0x321
,
0x322
,
0x323
}},
{{
0x411
,
0x412
,
0x413
},
{
0x421
,
0x422
,
0x423
}},
}
ret2
,
ret2Exp
:=
new
(
uint64
),
uint64
(
0x9876
)
if
err
:=
abi
.
Unpack
(
&
[]
interface
{}{
ret1
,
ret2
},
"multi"
,
buff
.
Bytes
());
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
!
reflect
.
DeepEqual
(
*
ret1
,
ret1Exp
)
{
t
.
Error
(
"array result"
,
*
ret1
,
"!= Expected"
,
ret1Exp
)
}
if
*
ret2
!=
ret2Exp
{
t
.
Error
(
"int result"
,
*
ret2
,
"!= Expected"
,
ret2Exp
)
}
}
func
TestUnmarshal
(
t
*
testing
.
T
)
{
const
definition
=
`[
{ "name" : "int", "constant" : false, "outputs": [ { "type": "uint256" } ] },
{ "name" : "bool", "constant" : false, "outputs": [ { "type": "bool" } ] },
{ "name" : "bytes", "constant" : false, "outputs": [ { "type": "bytes" } ] },
{ "name" : "fixed", "constant" : false, "outputs": [ { "type": "bytes32" } ] },
{ "name" : "multi", "constant" : false, "outputs": [ { "type": "bytes" }, { "type": "bytes" } ] },
{ "name" : "intArraySingle", "constant" : false, "outputs": [ { "type": "uint256[3]" } ] },
{ "name" : "addressSliceSingle", "constant" : false, "outputs": [ { "type": "address[]" } ] },
{ "name" : "addressSliceDouble", "constant" : false, "outputs": [ { "name": "a", "type": "address[]" }, { "name": "b", "type": "address[]" } ] },
{ "name" : "mixedBytes", "constant" : true, "outputs": [ { "name": "a", "type": "bytes" }, { "name": "b", "type": "bytes32" } ] }]`
abi
,
err
:=
JSON
(
strings
.
NewReader
(
definition
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
buff
:=
new
(
bytes
.
Buffer
)
// marshall mixed bytes (mixedBytes)
p0
,
p0Exp
:=
[]
byte
{},
common
.
Hex2Bytes
(
"01020000000000000000"
)
p1
,
p1Exp
:=
[
32
]
byte
{},
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000ddeeff"
)
mixedBytes
:=
[]
interface
{}{
&
p0
,
&
p1
}
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000040"
))
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000ddeeff"
))
buff
.
Write
(
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000000a"
))
buff
.
Write
(
common
.
Hex2Bytes
(
"0102000000000000000000000000000000000000000000000000000000000000"
))
err
=
abi
.
Unpack
(
&
mixedBytes
,
"mixedBytes"
,
buff
.
Bytes
())
if
err
!=
nil
{
t
.
Error
(
err
)
}
else
{
if
!
bytes
.
Equal
(
p0
,
p0Exp
)
{
t
.
Errorf
(
"unexpected value unpacked: want %x, got %x"
,
p0Exp
,
p0
)
}
if
!
bytes
.
Equal
(
p1
[
:
],
p1Exp
)
{
t
.
Errorf
(
"unexpected value unpacked: want %x, got %x"
,
p1Exp
,
p1
)
}
}
// marshal int
var
Int
*
big
.
Int
err
=
abi
.
Unpack
(
&
Int
,
"int"
,
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000001"
))
if
err
!=
nil
{
t
.
Error
(
err
)
}
if
Int
==
nil
||
Int
.
Cmp
(
big
.
NewInt
(
1
))
!=
0
{
t
.
Error
(
"expected Int to be 1 got"
,
Int
)
}
// marshal bool
var
Bool
bool
err
=
abi
.
Unpack
(
&
Bool
,
"bool"
,
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000001"
))
if
err
!=
nil
{
t
.
Error
(
err
)
}
if
!
Bool
{
t
.
Error
(
"expected Bool to be true"
)
}
// marshal dynamic bytes max length 32
buff
.
Reset
()
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000020"
))
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000020"
))
bytesOut
:=
common
.
RightPadBytes
([]
byte
(
"hello"
),
32
)
buff
.
Write
(
bytesOut
)
var
Bytes
[]
byte
err
=
abi
.
Unpack
(
&
Bytes
,
"bytes"
,
buff
.
Bytes
())
if
err
!=
nil
{
t
.
Error
(
err
)
}
if
!
bytes
.
Equal
(
Bytes
,
bytesOut
)
{
t
.
Errorf
(
"expected %x got %x"
,
bytesOut
,
Bytes
)
}
// marshall dynamic bytes max length 64
buff
.
Reset
()
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000020"
))
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000040"
))
bytesOut
=
common
.
RightPadBytes
([]
byte
(
"hello"
),
64
)
buff
.
Write
(
bytesOut
)
err
=
abi
.
Unpack
(
&
Bytes
,
"bytes"
,
buff
.
Bytes
())
if
err
!=
nil
{
t
.
Error
(
err
)
}
if
!
bytes
.
Equal
(
Bytes
,
bytesOut
)
{
t
.
Errorf
(
"expected %x got %x"
,
bytesOut
,
Bytes
)
}
// marshall dynamic bytes max length 64
buff
.
Reset
()
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000020"
))
buff
.
Write
(
common
.
Hex2Bytes
(
"000000000000000000000000000000000000000000000000000000000000003f"
))
bytesOut
=
common
.
RightPadBytes
([]
byte
(
"hello"
),
64
)
buff
.
Write
(
bytesOut
)
err
=
abi
.
Unpack
(
&
Bytes
,
"bytes"
,
buff
.
Bytes
())
if
err
!=
nil
{
t
.
Error
(
err
)
}
if
!
bytes
.
Equal
(
Bytes
,
bytesOut
[
:
len
(
bytesOut
)
-
1
])
{
t
.
Errorf
(
"expected %x got %x"
,
bytesOut
[
:
len
(
bytesOut
)
-
1
],
Bytes
)
}
// marshal dynamic bytes output empty
err
=
abi
.
Unpack
(
&
Bytes
,
"bytes"
,
nil
)
if
err
==
nil
{
t
.
Error
(
"expected error"
)
}
// marshal dynamic bytes length 5
buff
.
Reset
()
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000020"
))
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000005"
))
buff
.
Write
(
common
.
RightPadBytes
([]
byte
(
"hello"
),
32
))
err
=
abi
.
Unpack
(
&
Bytes
,
"bytes"
,
buff
.
Bytes
())
if
err
!=
nil
{
t
.
Error
(
err
)
}
if
!
bytes
.
Equal
(
Bytes
,
[]
byte
(
"hello"
))
{
t
.
Errorf
(
"expected %x got %x"
,
bytesOut
,
Bytes
)
}
// marshal dynamic bytes length 5
buff
.
Reset
()
buff
.
Write
(
common
.
RightPadBytes
([]
byte
(
"hello"
),
32
))
var
hash
common
.
Hash
err
=
abi
.
Unpack
(
&
hash
,
"fixed"
,
buff
.
Bytes
())
if
err
!=
nil
{
t
.
Error
(
err
)
}
helloHash
:=
common
.
BytesToHash
(
common
.
RightPadBytes
([]
byte
(
"hello"
),
32
))
if
hash
!=
helloHash
{
t
.
Errorf
(
"Expected %x to equal %x"
,
hash
,
helloHash
)
}
// marshal error
buff
.
Reset
()
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000020"
))
err
=
abi
.
Unpack
(
&
Bytes
,
"bytes"
,
buff
.
Bytes
())
if
err
==
nil
{
t
.
Error
(
"expected error"
)
}
err
=
abi
.
Unpack
(
&
Bytes
,
"multi"
,
make
([]
byte
,
64
))
if
err
==
nil
{
t
.
Error
(
"expected error"
)
}
buff
.
Reset
()
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000001"
))
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
))
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000003"
))
// marshal int array
var
intArray
[
3
]
*
big
.
Int
err
=
abi
.
Unpack
(
&
intArray
,
"intArraySingle"
,
buff
.
Bytes
())
if
err
!=
nil
{
t
.
Error
(
err
)
}
var
testAgainstIntArray
[
3
]
*
big
.
Int
testAgainstIntArray
[
0
]
=
big
.
NewInt
(
1
)
testAgainstIntArray
[
1
]
=
big
.
NewInt
(
2
)
testAgainstIntArray
[
2
]
=
big
.
NewInt
(
3
)
for
i
,
Int
:=
range
intArray
{
if
Int
.
Cmp
(
testAgainstIntArray
[
i
])
!=
0
{
t
.
Errorf
(
"expected %v, got %v"
,
testAgainstIntArray
[
i
],
Int
)
}
}
// marshal address slice
buff
.
Reset
()
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000020"
))
// offset
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000001"
))
// size
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000100000000000000000000000000000000000000"
))
var
outAddr
[]
common
.
Hash160Address
err
=
abi
.
Unpack
(
&
outAddr
,
"addressSliceSingle"
,
buff
.
Bytes
())
if
err
!=
nil
{
t
.
Fatal
(
"didn't expect error:"
,
err
)
}
if
len
(
outAddr
)
!=
1
{
t
.
Fatal
(
"expected 1 item, got"
,
len
(
outAddr
))
}
if
outAddr
[
0
]
!=
(
common
.
Hash160Address
{
1
})
{
t
.
Errorf
(
"expected %x, got %x"
,
common
.
Hash160Address
{
1
},
outAddr
[
0
])
}
// marshal multiple address slice
buff
.
Reset
()
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000040"
))
// offset
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000080"
))
// offset
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000001"
))
// size
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000100000000000000000000000000000000000000"
))
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000002"
))
// size
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000200000000000000000000000000000000000000"
))
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000300000000000000000000000000000000000000"
))
var
outAddrStruct
struct
{
A
[]
common
.
Hash160Address
B
[]
common
.
Hash160Address
}
err
=
abi
.
Unpack
(
&
outAddrStruct
,
"addressSliceDouble"
,
buff
.
Bytes
())
if
err
!=
nil
{
t
.
Fatal
(
"didn't expect error:"
,
err
)
}
if
len
(
outAddrStruct
.
A
)
!=
1
{
t
.
Fatal
(
"expected 1 item, got"
,
len
(
outAddrStruct
.
A
))
}
if
outAddrStruct
.
A
[
0
]
!=
(
common
.
Hash160Address
{
1
})
{
t
.
Errorf
(
"expected %x, got %x"
,
common
.
Hash160Address
{
1
},
outAddrStruct
.
A
[
0
])
}
if
len
(
outAddrStruct
.
B
)
!=
2
{
t
.
Fatal
(
"expected 1 item, got"
,
len
(
outAddrStruct
.
B
))
}
if
outAddrStruct
.
B
[
0
]
!=
(
common
.
Hash160Address
{
2
})
{
t
.
Errorf
(
"expected %x, got %x"
,
common
.
Hash160Address
{
2
},
outAddrStruct
.
B
[
0
])
}
if
outAddrStruct
.
B
[
1
]
!=
(
common
.
Hash160Address
{
3
})
{
t
.
Errorf
(
"expected %x, got %x"
,
common
.
Hash160Address
{
3
},
outAddrStruct
.
B
[
1
])
}
// marshal invalid address slice
buff
.
Reset
()
buff
.
Write
(
common
.
Hex2Bytes
(
"0000000000000000000000000000000000000000000000000000000000000100"
))
err
=
abi
.
Unpack
(
&
outAddr
,
"addressSliceSingle"
,
buff
.
Bytes
())
if
err
==
nil
{
t
.
Fatal
(
"expected error:"
,
err
)
}
}
func
TestOOMMaliciousInput
(
t
*
testing
.
T
)
{
oomTests
:=
[]
unpackTest
{
{
def
:
`[{"type": "uint8[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020"
+
// offset
"0000000000000000000000000000000000000000000000000000000000000003"
+
// num elems
"0000000000000000000000000000000000000000000000000000000000000001"
+
// elem 1
"0000000000000000000000000000000000000000000000000000000000000002"
,
// elem 2
},
{
// Length larger than 64 bits
def
:
`[{"type": "uint8[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020"
+
// offset
"00ffffffffffffffffffffffffffffffffffffffffffffff0000000000000002"
+
// num elems
"0000000000000000000000000000000000000000000000000000000000000001"
+
// elem 1
"0000000000000000000000000000000000000000000000000000000000000002"
,
// elem 2
},
{
// Offset very large (over 64 bits)
def
:
`[{"type": "uint8[]"}]`
,
enc
:
"00ffffffffffffffffffffffffffffffffffffffffffffff0000000000000020"
+
// offset
"0000000000000000000000000000000000000000000000000000000000000002"
+
// num elems
"0000000000000000000000000000000000000000000000000000000000000001"
+
// elem 1
"0000000000000000000000000000000000000000000000000000000000000002"
,
// elem 2
},
{
// Offset very large (below 64 bits)
def
:
`[{"type": "uint8[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000007ffffffffff00020"
+
// offset
"0000000000000000000000000000000000000000000000000000000000000002"
+
// num elems
"0000000000000000000000000000000000000000000000000000000000000001"
+
// elem 1
"0000000000000000000000000000000000000000000000000000000000000002"
,
// elem 2
},
{
// Offset negative (as 64 bit)
def
:
`[{"type": "uint8[]"}]`
,
enc
:
"000000000000000000000000000000000000000000000000f000000000000020"
+
// offset
"0000000000000000000000000000000000000000000000000000000000000002"
+
// num elems
"0000000000000000000000000000000000000000000000000000000000000001"
+
// elem 1
"0000000000000000000000000000000000000000000000000000000000000002"
,
// elem 2
},
{
// Negative length
def
:
`[{"type": "uint8[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020"
+
// offset
"000000000000000000000000000000000000000000000000f000000000000002"
+
// num elems
"0000000000000000000000000000000000000000000000000000000000000001"
+
// elem 1
"0000000000000000000000000000000000000000000000000000000000000002"
,
// elem 2
},
{
// Very large length
def
:
`[{"type": "uint8[]"}]`
,
enc
:
"0000000000000000000000000000000000000000000000000000000000000020"
+
// offset
"0000000000000000000000000000000000000000000000007fffffffff000002"
+
// num elems
"0000000000000000000000000000000000000000000000000000000000000001"
+
// elem 1
"0000000000000000000000000000000000000000000000000000000000000002"
,
// elem 2
},
}
for
i
,
test
:=
range
oomTests
{
def
:=
fmt
.
Sprintf
(
`[{ "name" : "method", "outputs": %s}]`
,
test
.
def
)
abi
,
err
:=
JSON
(
strings
.
NewReader
(
def
))
if
err
!=
nil
{
t
.
Fatalf
(
"invalid ABI definition %s: %v"
,
def
,
err
)
}
encb
,
err
:=
hex
.
DecodeString
(
test
.
enc
)
if
err
!=
nil
{
t
.
Fatalf
(
"invalid hex: %s"
+
test
.
enc
)
}
_
,
err
=
abi
.
Methods
[
"method"
]
.
Outputs
.
UnpackValues
(
encb
)
if
err
==
nil
{
t
.
Fatalf
(
"Expected error on malicious input, test %d"
,
i
)
}
}
}
plugin/dapp/evm/executor/evm.go
View file @
b2ebdcd4
...
...
@@ -38,7 +38,7 @@ func init() {
// Init 初始化本合约对象
func
Init
(
name
string
,
sub
[]
byte
)
{
driverName
=
name
drivers
.
Register
(
driverName
,
newEVMDriver
,
types
.
GetDappFork
(
driverName
,
"Enable"
))
drivers
.
Register
(
driverName
,
newEVMDriver
,
types
.
GetDappFork
(
driverName
,
evmtypes
.
EVMEnable
))
EvmAddress
=
address
.
ExecAddress
(
types
.
ExecName
(
name
))
// 初始化硬分叉数据
state
.
InitForkData
()
...
...
plugin/dapp/evm/executor/exec.go
View file @
b2ebdcd4
...
...
@@ -11,6 +11,7 @@ import (
log
"github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types"
"github.com/33cn/plugin/plugin/dapp/evm/executor/abi"
"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"
...
...
@@ -26,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
)
...
...
@@ -40,28 +46,46 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
contractAddr
common
.
Address
snapshot
int
execName
string
methodName
string
)
// 为了方便计费,即使合约为新生成,也将地址的初始化放到外面操作
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
())
// 如果携带ABI数据,则对数据合法性进行检查
if
len
(
msg
.
ABI
())
>
0
&&
types
.
IsDappFork
(
evm
.
GetHeight
(),
"evm"
,
evmtypes
.
ForkEVMABI
)
{
_
,
err
=
abi
.
JSON
(
strings
.
NewReader
(
msg
.
ABI
()))
if
err
!=
nil
{
return
receipt
,
err
}
}
ret
,
snapshot
,
leftOverGas
,
vmerr
=
env
.
Create
(
runtime
.
AccountRef
(
msg
.
From
()),
contractAddr
,
msg
.
Data
(),
context
.
GasLimit
,
execName
,
msg
.
Alias
(),
msg
.
ABI
())
}
else
{
ret
,
snapshot
,
leftOverGas
,
vmerr
=
env
.
Call
(
runtime
.
AccountRef
(
msg
.
From
()),
*
msg
.
To
(),
msg
.
Data
(),
context
.
GasLimit
,
msg
.
Value
())
inData
:=
msg
.
Data
()
// 在这里进行ABI和十六进制的调用参数转换
if
len
(
msg
.
ABI
())
>
0
&&
types
.
IsDappFork
(
evm
.
GetHeight
(),
"evm"
,
evmtypes
.
ForkEVMABI
)
{
funcName
,
packData
,
err
:=
abi
.
Pack
(
msg
.
ABI
(),
evm
.
mStateDB
.
GetAbi
(
msg
.
To
()
.
String
()),
readOnly
)
if
err
!=
nil
{
return
receipt
,
err
}
inData
=
packData
methodName
=
funcName
}
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
()))
...
...
@@ -76,42 +100,52 @@ 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
())
// 从状态机中获取数据变更和变更日志
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"
,
evmtypes
.
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
())
...
)
if
types
.
IsDappFork
(
evm
.
GetHeight
(),
"evm"
,
"ForkEVMKVHash"
)
{
if
types
.
IsDappFork
(
evm
.
GetHeight
(),
"evm"
,
evmtypes
.
ForkEVMKVHash
)
{
// 将执行时生成的合约状态数据变更信息也计算哈希并保存
hashKV
:=
evm
.
calcKVHash
(
contractAddr
,
logs
)
if
hashKV
!=
nil
{
data
=
append
(
data
,
hashKV
)
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
{
...
...
@@ -119,9 +153,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
}
...
...
@@ -137,22 +172,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
)
}
...
...
@@ -161,13 +191,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
()
)
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
{
...
...
plugin/dapp/evm/executor/exec_del_local.go
View file @
b2ebdcd4
...
...
@@ -19,7 +19,7 @@ func (evm *EVMExecutor) ExecDelLocal(tx *types.Transaction, receipt *types.Recei
return
set
,
nil
}
if
types
.
IsDappFork
(
evm
.
GetHeight
(),
"evm"
,
"ForkEVMState"
)
{
if
types
.
IsDappFork
(
evm
.
GetHeight
(),
"evm"
,
evmtypes
.
ForkEVMState
)
{
// 需要将Exec中生成的合约状态变更信息从localdb中恢复
for
_
,
logItem
:=
range
receipt
.
Logs
{
if
evmtypes
.
TyLogEVMStateChangeItem
==
logItem
.
Ty
{
...
...
plugin/dapp/evm/executor/exec_local.go
View file @
b2ebdcd4
...
...
@@ -20,7 +20,7 @@ func (evm *EVMExecutor) ExecLocal(tx *types.Transaction, receipt *types.ReceiptD
if
receipt
.
GetTy
()
!=
types
.
ExecOk
{
return
set
,
nil
}
if
types
.
IsDappFork
(
evm
.
GetHeight
(),
"evm"
,
"ForkEVMState"
)
{
if
types
.
IsDappFork
(
evm
.
GetHeight
(),
"evm"
,
evmtypes
.
ForkEVMState
)
{
// 需要将Exec中生成的合约状态变更信息写入localdb
for
_
,
logItem
:=
range
receipt
.
Logs
{
if
evmtypes
.
TyLogEVMStateChangeItem
==
logItem
.
Ty
{
...
...
plugin/dapp/evm/executor/query.go
View file @
b2ebdcd4
...
...
@@ -9,11 +9,11 @@ import (
"math/big"
"strings"
"errors"
"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"
)
...
...
@@ -56,7 +56,6 @@ func (evm *EVMExecutor) Query_EstimateGas(in *evmtypes.EstimateEVMGasReq) (types
evm
.
CheckInit
()
var
(
caller
common
.
Address
to
*
common
.
Address
)
// 如果未指定调用地址,则直接使用一个虚拟的地址发起调用
...
...
@@ -69,35 +68,42 @@ 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"
)
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
)
if
isCreate
{
to
:=
common
.
StringToAddress
(
in
.
To
)
if
to
==
nil
{
to
=
common
.
StringToAddress
(
EvmAddress
)
}
msg
:=
common
.
NewMessage
(
caller
,
to
,
0
,
in
.
Amount
,
evmtypes
.
MaxGasLimit
,
1
,
in
.
Code
,
"estimateGas"
,
in
.
Abi
)
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
())
receipt
,
err
:=
evm
.
innerExec
(
msg
,
txHash
,
1
,
evmtypes
.
MaxGasLimit
,
false
)
if
err
!=
nil
{
return
nil
,
err
}
if
receipt
.
Ty
==
types
.
ExecOk
{
callData
:=
getCallReceipt
(
receipt
.
GetLogs
())
if
callData
!=
nil
{
result
:=
&
evmtypes
.
EstimateEVMGasResp
{}
result
.
Gas
=
evmtypes
.
MaxGasLimit
-
leftOverGas
return
result
,
vmerr
result
.
Gas
=
callData
.
UsedGas
return
result
,
nil
}
}
return
nil
,
errors
.
New
(
"contract call error"
)
}
// 从日志中查找调用结果
func
getCallReceipt
(
logs
[]
*
types
.
ReceiptLog
)
*
evmtypes
.
ReceiptEVMContract
{
if
len
(
logs
)
==
0
{
return
nil
}
for
_
,
v
:=
range
logs
{
if
v
.
Ty
==
evmtypes
.
TyLogCallContract
{
var
res
evmtypes
.
ReceiptEVMContract
types
.
Decode
(
v
.
Log
,
&
res
)
return
&
res
}
}
return
nil
}
// Query_EvmDebug 此方法用来估算合约消耗的Gas,不能修改原有执行器的状态数据
...
...
@@ -113,3 +119,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
=
common
.
Bytes2Hex
(
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 @
b2ebdcd4
...
...
@@ -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 @
b2ebdcd4
...
...
@@ -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 @
b2ebdcd4
...
...
@@ -7,10 +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"
evmtypes
"github.com/33cn/plugin/plugin/dapp/evm/types"
)
// Address 封装地址结构体,并提供各种常用操作封装
...
...
@@ -20,6 +22,9 @@ type Address struct {
addr
*
address
.
Address
}
// Hash160Address EVM中使用的地址格式
type
Hash160Address
[
Hash160Length
]
byte
// String 字符串结构
func
(
a
Address
)
String
()
string
{
return
a
.
addr
.
String
()
}
...
...
@@ -34,9 +39,60 @@ func (a Address) Big() *big.Int {
return
ret
}
// Hash 计算地址哈希
func
(
a
Address
)
Hash
()
Hash
{
return
ToHash
(
a
.
Bytes
())
}
// ToHash160 返回EVM类型地址
func
(
a
Address
)
ToHash160
()
Hash160Address
{
var
h
Hash160Address
h
.
SetBytes
(
a
.
Bytes
())
return
h
}
// SetBytes sets the address to the value of b.
// If b is larger than len(a) it will panic.
func
(
h
*
Hash160Address
)
SetBytes
(
b
[]
byte
)
{
if
len
(
b
)
>
len
(
h
)
{
b
=
b
[
len
(
b
)
-
Hash160Length
:
]
}
copy
(
h
[
Hash160Length
-
len
(
b
)
:
],
b
)
}
// String implements fmt.Stringer.
func
(
h
Hash160Address
)
String
()
string
{
return
h
.
Hex
()
}
// Hex returns an EIP55-compliant hex string representation of the address.
func
(
h
Hash160Address
)
Hex
()
string
{
unchecksummed
:=
hex
.
EncodeToString
(
h
[
:
])
sha
:=
sha3
.
NewLegacyKeccak256
()
sha
.
Write
([]
byte
(
unchecksummed
))
hash
:=
sha
.
Sum
(
nil
)
result
:=
[]
byte
(
unchecksummed
)
for
i
:=
0
;
i
<
len
(
result
);
i
++
{
hashByte
:=
hash
[
i
/
2
]
if
i
%
2
==
0
{
hashByte
=
hashByte
>>
4
}
else
{
hashByte
&=
0xf
}
if
result
[
i
]
>
'9'
&&
hashByte
>
7
{
result
[
i
]
-=
32
}
}
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
(
evmtypes
.
EvmPrefix
)
+
BytesToHash
(
txHash
)
.
Hex
())
execAddr
:=
address
.
GetExecAddress
(
types
.
ExecName
(
"user.evm."
)
+
BytesToHash
(
txHash
)
.
Hex
())
return
Address
{
addr
:
execAddr
}
}
...
...
@@ -46,9 +102,6 @@ func ExecAddress(execName string) Address {
return
Address
{
addr
:
execAddr
}
}
// Hash 计算地址哈希
func
(
a
Address
)
Hash
()
Hash
{
return
ToHash
(
a
.
Bytes
())
}
// BytesToAddress 字节向地址转换
func
BytesToAddress
(
b
[]
byte
)
Address
{
a
:=
new
(
address
.
Address
)
...
...
@@ -57,6 +110,13 @@ func BytesToAddress(b []byte) Address {
return
Address
{
addr
:
a
}
}
// BytesToHash160Address 字节向地址转换
func
BytesToHash160Address
(
b
[]
byte
)
Hash160Address
{
var
h
Hash160Address
h
.
SetBytes
(
b
)
return
h
}
// StringToAddress 字符串转换为地址
func
StringToAddress
(
s
string
)
*
Address
{
addr
,
err
:=
address
.
NewAddrFromString
(
s
)
...
...
@@ -87,3 +147,7 @@ func BigToAddress(b *big.Int) Address {
// EmptyAddress 返回空地址
func
EmptyAddress
()
Address
{
return
BytesToAddress
([]
byte
{
0
})
}
// HexToAddress returns Address with byte values of s.
// If s is larger than len(h), s will be cropped from the left.
func
HexToAddress
(
s
string
)
Hash160Address
{
return
BytesToHash160Address
(
FromHex
(
s
))
}
plugin/dapp/evm/executor/vm/common/bytes.go
View file @
b2ebdcd4
...
...
@@ -6,7 +6,9 @@ package common
import
(
"encoding/hex"
"math/big"
"sort"
"strings"
)
// RightPadBytes 右填充字节数组
...
...
@@ -33,6 +35,17 @@ func LeftPadBytes(slice []byte, l int) []byte {
return
padded
}
// PaddedBigBytes encodes a big integer as a big-endian byte slice. The length
// of the slice is at least n bytes.
func
PaddedBigBytes
(
bigint
*
big
.
Int
,
n
int
)
[]
byte
{
if
bigint
.
BitLen
()
/
8
>=
n
{
return
bigint
.
Bytes
()
}
ret
:=
make
([]
byte
,
n
)
ReadBits
(
bigint
,
ret
)
return
ret
}
// FromHex 十六进制的字符串转换为字节数组
func
FromHex
(
s
string
)
[]
byte
{
if
len
(
s
)
>
1
{
...
...
@@ -52,6 +65,14 @@ func Hex2Bytes(str string) []byte {
return
h
}
// HexToBytes 十六进制字符串转换为字节数组
func
HexToBytes
(
str
string
)
([]
byte
,
error
)
{
if
len
(
str
)
>
1
&&
(
strings
.
HasPrefix
(
str
,
"0x"
)
||
strings
.
HasPrefix
(
str
,
"0X"
))
{
str
=
str
[
2
:
]
}
return
hex
.
DecodeString
(
str
)
}
// Bytes2Hex 将字节数组转换为16进制的字符串表示
func
Bytes2Hex
(
b
[]
byte
)
string
{
enc
:=
make
([]
byte
,
len
(
b
)
*
2
+
2
)
...
...
plugin/dapp/evm/executor/vm/common/crypto/crypto.go
View file @
b2ebdcd4
...
...
@@ -68,3 +68,14 @@ func Keccak256(data ...[]byte) []byte {
}
return
d
.
Sum
(
nil
)
}
// 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
()
for
_
,
b
:=
range
data
{
d
.
Write
(
b
)
}
d
.
Sum
(
h
[
:
0
])
return
h
}
plugin/dapp/evm/executor/vm/common/hash.go
View file @
b2ebdcd4
...
...
@@ -13,6 +13,9 @@ import (
const
(
// HashLength 哈希长度
HashLength
=
32
// Hash160Length Hash160格式的地址长度
Hash160Length
=
20
)
// Hash 重定义哈希类型
...
...
plugin/dapp/evm/executor/vm/common/message.go
View file @
b2ebdcd4
...
...
@@ -15,10 +15,11 @@ type Message struct {
gasLimit
uint64
gasPrice
uint32
data
[]
byte
abi
string
}
// NewMessage 新建消息结构
func
NewMessage
(
from
Address
,
to
*
Address
,
nonce
int64
,
amount
uint64
,
gasLimit
uint64
,
gasPrice
uint32
,
data
[]
byte
,
alias
string
)
*
Message
{
func
NewMessage
(
from
Address
,
to
*
Address
,
nonce
int64
,
amount
uint64
,
gasLimit
uint64
,
gasPrice
uint32
,
data
[]
byte
,
alias
,
abi
string
)
*
Message
{
return
&
Message
{
from
:
from
,
to
:
to
,
...
...
@@ -28,6 +29,7 @@ func NewMessage(from Address, to *Address, nonce int64, amount uint64, gasLimit
gasPrice
:
gasPrice
,
data
:
data
,
alias
:
alias
,
abi
:
abi
,
}
}
...
...
@@ -54,3 +56,6 @@ func (m Message) GasLimit() uint64 { return m.gasLimit }
// Alias 合约别名
func
(
m
Message
)
Alias
()
string
{
return
m
.
alias
}
// ABI 合约ABI
func
(
m
Message
)
ABI
()
string
{
return
m
.
abi
}
plugin/dapp/evm/executor/vm/runtime/evm.go
View file @
b2ebdcd4
...
...
@@ -16,6 +16,7 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/model"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/params"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/state"
evmtypes
"github.com/33cn/plugin/plugin/dapp/evm/types"
)
type
(
...
...
@@ -222,7 +223,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
}
// 从ForkV20EVMState开始,状态数据存储发生变更,需要做数据迁移
if
types
.
IsDappFork
(
evm
.
BlockNumber
.
Int64
(),
"evm"
,
"ForkEVMState"
)
{
if
types
.
IsDappFork
(
evm
.
BlockNumber
.
Int64
(),
"evm"
,
evmtypes
.
ForkEVMState
)
{
evm
.
StateDB
.
TransferStateData
(
addr
.
String
())
}
...
...
@@ -356,7 +357,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 +387,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"
,
evmtypes
.
ForkEVMABI
)
{
evm
.
StateDB
.
SetAbi
(
contractAddr
.
String
(),
abi
)
}
}
else
{
// 如果Gas不足,返回这个错误,让外部程序处理
err
=
model
.
ErrCodeStoreOutOfGas
...
...
plugin/dapp/evm/executor/vm/runtime/instructions.go
View file @
b2ebdcd4
...
...
@@ -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 @
b2ebdcd4
...
...
@@ -50,7 +50,7 @@ func NewContractAccount(addr string, db *MemoryStateDB) *ContractAccount {
// 获取数据分为两层,一层是从当前的缓存中获取,如果获取不到,再从localdb中获取
func
(
ca
*
ContractAccount
)
GetState
(
key
common
.
Hash
)
common
.
Hash
{
// 从ForkV19开始,状态数据使用单独的KEY存储
if
types
.
IsDappFork
(
ca
.
mdb
.
blockHeight
,
"evm"
,
"ForkEVMState"
)
{
if
types
.
IsDappFork
(
ca
.
mdb
.
blockHeight
,
"evm"
,
evmtypes
.
ForkEVMState
)
{
if
val
,
ok
:=
ca
.
stateCache
[
key
.
Hex
()];
ok
{
return
val
}
...
...
@@ -76,7 +76,7 @@ func (ca *ContractAccount) SetState(key, value common.Hash) {
key
:
key
,
prevalue
:
ca
.
GetState
(
key
),
})
if
types
.
IsDappFork
(
ca
.
mdb
.
blockHeight
,
"evm"
,
"ForkEVMState"
)
{
if
types
.
IsDappFork
(
ca
.
mdb
.
blockHeight
,
"evm"
,
evmtypes
.
ForkEVMState
)
{
ca
.
stateCache
[
key
.
Hex
()]
=
value
//需要设置到localdb中,以免同一个区块中同一个合约多次调用时,状态数据丢失
keyStr
:=
getStateItemKey
(
ca
.
Addr
,
key
.
Hex
())
...
...
@@ -107,7 +107,7 @@ func (ca *ContractAccount) TransferState() {
func
(
ca
*
ContractAccount
)
updateStorageHash
()
{
// 从ForkV20开始,状态数据使用单独KEY存储
if
types
.
IsDappFork
(
ca
.
mdb
.
blockHeight
,
"evm"
,
"ForkEVMState"
)
{
if
types
.
IsDappFork
(
ca
.
mdb
.
blockHeight
,
"evm"
,
evmtypes
.
ForkEVMState
)
{
return
}
var
state
=
&
evmtypes
.
EVMContractState
{
Suicided
:
ca
.
State
.
Suicided
,
Nonce
:
ca
.
State
.
Nonce
}
...
...
@@ -181,6 +181,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"
,
evmtypes
.
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
{
...
...
plugin/dapp/evm/executor/vm/state/interface.go
View file @
b2ebdcd4
...
...
@@ -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 @
b2ebdcd4
...
...
@@ -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
{
...
...
@@ -252,7 +275,7 @@ func (ch storageChange) getData(mdb *MemoryStateDB) []*types.KeyValue {
}
func
(
ch
storageChange
)
getLog
(
mdb
*
MemoryStateDB
)
[]
*
types
.
ReceiptLog
{
if
types
.
IsDappFork
(
mdb
.
blockHeight
,
"evm"
,
"ForkEVMState"
)
{
if
types
.
IsDappFork
(
mdb
.
blockHeight
,
"evm"
,
evmtypes
.
ForkEVMState
)
{
acc
:=
mdb
.
accounts
[
ch
.
account
]
if
acc
!=
nil
{
currentVal
:=
acc
.
GetState
(
ch
.
key
)
...
...
plugin/dapp/evm/executor/vm/state/statedb.go
View file @
b2ebdcd4
...
...
@@ -14,6 +14,7 @@ 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"
evmtypes
"github.com/33cn/plugin/plugin/dapp/evm/types"
)
// MemoryStateDB 内存状态数据库,保存在区块操作时内部的数据变更操作
...
...
@@ -193,6 +194,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
{
...
...
@@ -245,7 +264,7 @@ func (mdb *MemoryStateDB) SetState(addr string, key common.Hash, value common.Ha
if
acc
!=
nil
{
acc
.
SetState
(
key
,
value
)
// 新的分叉中状态数据变更不需要单独进行标识
if
!
types
.
IsDappFork
(
mdb
.
blockHeight
,
"evm"
,
"ForkEVMState"
)
{
if
!
types
.
IsDappFork
(
mdb
.
blockHeight
,
"evm"
,
evmtypes
.
ForkEVMState
)
{
mdb
.
stateDirty
[
addr
]
=
true
}
}
...
...
@@ -686,3 +705,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 @
b2ebdcd4
...
...
@@ -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
;
...
...
@@ -117,3 +124,26 @@ 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
;
string
rawData
=
4
;
string
jsonData
=
5
;
}
\ No newline at end of file
plugin/dapp/evm/types/evm.go
View file @
b2ebdcd4
...
...
@@ -12,6 +12,7 @@ import (
"github.com/33cn/chain33/common/address"
log
"github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types"
"github.com/golang/protobuf/proto"
)
var
(
...
...
@@ -27,9 +28,14 @@ func init() {
types
.
AllowUserExec
=
append
(
types
.
AllowUserExec
,
ExecerEvm
)
// init executor type
types
.
RegistorExecutor
(
ExecutorName
,
NewType
())
types
.
RegisterDappFork
(
ExecutorName
,
"ForkEVMState"
,
650000
)
types
.
RegisterDappFork
(
ExecutorName
,
"ForkEVMKVHash"
,
1000000
)
types
.
RegisterDappFork
(
ExecutorName
,
"Enable"
,
500000
)
types
.
RegisterDappFork
(
ExecutorName
,
EVMEnable
,
500000
)
// EVM合约中的数据分散存储,支持大数据量
types
.
RegisterDappFork
(
ExecutorName
,
ForkEVMState
,
650000
)
// EVM合约状态数据生成哈希,保存在主链的StateDB中
types
.
RegisterDappFork
(
ExecutorName
,
ForkEVMKVHash
,
1000000
)
// EVM合约支持ABI绑定和调用
types
.
RegisterDappFork
(
ExecutorName
,
ForkEVMABI
,
1250000
)
}
// EvmType EVM类型定义
...
...
@@ -92,7 +98,7 @@ func (evm EvmType) CreateTx(action string, message json.RawMessage) (*types.Tran
elog
.
Error
(
"CreateTx"
,
"Error"
,
err
)
return
nil
,
types
.
ErrInvalidParam
}
return
create
RawEvmCreateCall
Tx
(
&
param
)
return
create
Evm
Tx
(
&
param
)
}
return
nil
,
types
.
ErrNotSupport
}
...
...
@@ -102,28 +108,44 @@ func (evm *EvmType) GetLogMap() map[int64]*types.LogInfo {
return
logInfo
}
func
create
RawEvmCreateCallTx
(
par
m
*
CreateCallTx
)
(
*
types
.
Transaction
,
error
)
{
if
parm
==
nil
{
elog
.
Error
(
"create
RawEvmCreateCallTx"
,
"parm"
,
par
m
)
func
create
EvmTx
(
para
m
*
CreateCallTx
)
(
*
types
.
Transaction
,
error
)
{
if
par
a
m
==
nil
{
elog
.
Error
(
"create
EvmTx"
,
"param"
,
para
m
)
return
nil
,
types
.
ErrInvalidParam
}
bCode
,
err
:=
common
.
FromHex
(
parm
.
Code
)
// 调用格式判断规则:
// 十六进制格式默认使用原方式调用,其它格式,使用ABI方式调用
// 为了方便区分,在ABI格式前加0x00000000
action
:=
&
EVMContractAction
{
Amount
:
param
.
Amount
,
GasLimit
:
param
.
GasLimit
,
GasPrice
:
param
.
GasPrice
,
Note
:
param
.
Note
,
Alias
:
param
.
Alias
,
}
// 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
(
"createRawEvmCreateCallTx"
,
"parm.Code"
,
par
m
.
Code
)
elog
.
Error
(
"create evm Tx error, code is invalid"
,
"param.Code"
,
para
m
.
Code
)
return
nil
,
err
}
action
.
Code
=
bCode
}
action
:=
&
EVMContractAction
{
Amount
:
parm
.
Amount
,
Code
:
bCode
,
GasLimit
:
parm
.
GasLimit
,
GasPrice
:
parm
.
GasPrice
,
Note
:
parm
.
Note
,
Alias
:
parm
.
Alias
,
if
param
.
IsCreate
{
return
createRawTx
(
action
,
""
,
param
.
Fee
)
}
return
createRawTx
(
action
,
param
.
Name
,
param
.
Fee
)
}
func
createRawTx
(
action
proto
.
Message
,
name
string
,
fee
int64
)
(
*
types
.
Transaction
,
error
)
{
tx
:=
&
types
.
Transaction
{}
if
parm
.
IsCreate
{
if
len
(
name
)
==
0
{
tx
=
&
types
.
Transaction
{
Execer
:
[]
byte
(
types
.
ExecName
(
ExecutorName
)),
Payload
:
types
.
Encode
(
action
),
...
...
@@ -131,17 +153,19 @@ func createRawEvmCreateCallTx(parm *CreateCallTx) (*types.Transaction, error) {
}
}
else
{
tx
=
&
types
.
Transaction
{
Execer
:
[]
byte
(
types
.
ExecName
(
parm
.
N
ame
)),
Execer
:
[]
byte
(
types
.
ExecName
(
n
ame
)),
Payload
:
types
.
Encode
(
action
),
To
:
address
.
ExecAddress
(
types
.
ExecName
(
parm
.
N
ame
)),
To
:
address
.
ExecAddress
(
types
.
ExecName
(
n
ame
)),
}
}
tx
,
err
=
types
.
FormatTx
(
string
(
tx
.
Execer
),
tx
)
tx
,
err
:
=
types
.
FormatTx
(
string
(
tx
.
Execer
),
tx
)
if
err
!=
nil
{
return
nil
,
err
}
if
tx
.
Fee
<
parm
.
Fee
{
tx
.
Fee
+=
parm
.
Fee
if
tx
.
Fee
<
fee
{
tx
.
Fee
=
fee
}
return
tx
,
nil
}
plugin/dapp/evm/types/evmcontract.pb.go
View file @
b2ebdcd4
...
...
@@ -85,6 +85,8 @@ type EVMContractData struct {
Addr
string
`protobuf:"bytes,4,opt,name=addr,proto3" json:"addr,omitempty"`
Code
[]
byte
`protobuf:"bytes,5,opt,name=code,proto3" json:"code,omitempty"`
CodeHash
[]
byte
`protobuf:"bytes,6,opt,name=codeHash,proto3" json:"codeHash,omitempty"`
// 绑定ABI数据 ForkEVMABI
Abi
string
`protobuf:"bytes,7,opt,name=abi,proto3" json:"abi,omitempty"`
XXX_NoUnkeyedLiteral
struct
{}
`json:"-"`
XXX_unrecognized
[]
byte
`json:"-"`
XXX_sizecache
int32
`json:"-"`
...
...
@@ -157,6 +159,13 @@ func (m *EVMContractData) GetCodeHash() []byte {
return
nil
}
func
(
m
*
EVMContractData
)
GetAbi
()
string
{
if
m
!=
nil
{
return
m
.
Abi
}
return
""
}
// 存放合约变化数据
type
EVMContractState
struct
{
Nonce
uint64
`protobuf:"varint,1,opt,name=nonce,proto3" json:"nonce,omitempty"`
...
...
@@ -235,6 +244,8 @@ type EVMContractAction struct {
Alias
string
`protobuf:"bytes,5,opt,name=alias,proto3" json:"alias,omitempty"`
// 交易备注
Note
string
`protobuf:"bytes,6,opt,name=note,proto3" json:"note,omitempty"`
// 创建或调用合约时携带的ABI数据 ForkEVMABI
Abi
string
`protobuf:"bytes,7,opt,name=abi,proto3" json:"abi,omitempty"`
XXX_NoUnkeyedLiteral
struct
{}
`json:"-"`
XXX_unrecognized
[]
byte
`json:"-"`
XXX_sizecache
int32
`json:"-"`
...
...
@@ -307,6 +318,13 @@ func (m *EVMContractAction) GetNote() string {
return
""
}
func
(
m
*
EVMContractAction
)
GetAbi
()
string
{
if
m
!=
nil
{
return
m
.
Abi
}
return
""
}
// 合约创建/调用日志
type
ReceiptEVMContract
struct
{
Caller
string
`protobuf:"bytes,1,opt,name=caller,proto3" json:"caller,omitempty"`
...
...
@@ -315,6 +333,8 @@ type ReceiptEVMContract struct {
UsedGas
uint64
`protobuf:"varint,4,opt,name=usedGas,proto3" json:"usedGas,omitempty"`
// 创建合约返回的代码
Ret
[]
byte
`protobuf:"bytes,5,opt,name=ret,proto3" json:"ret,omitempty"`
// json格式化后的返回值
JsonRet
string
`protobuf:"bytes,6,opt,name=jsonRet,proto3" json:"jsonRet,omitempty"`
XXX_NoUnkeyedLiteral
struct
{}
`json:"-"`
XXX_unrecognized
[]
byte
`json:"-"`
XXX_sizecache
int32
`json:"-"`
...
...
@@ -380,6 +400,13 @@ func (m *ReceiptEVMContract) GetRet() []byte {
return
nil
}
func
(
m
*
ReceiptEVMContract
)
GetJsonRet
()
string
{
if
m
!=
nil
{
return
m
.
JsonRet
}
return
""
}
// 用于保存EVM只能合约中的状态数据变更
type
EVMStateChangeItem
struct
{
Key
string
`protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
...
...
@@ -761,6 +788,7 @@ type EstimateEVMGasReq struct {
Code
[]
byte
`protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"`
Caller
string
`protobuf:"bytes,3,opt,name=caller,proto3" json:"caller,omitempty"`
Amount
uint64
`protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"`
Abi
string
`protobuf:"bytes,5,opt,name=abi,proto3" json:"abi,omitempty"`
XXX_NoUnkeyedLiteral
struct
{}
`json:"-"`
XXX_unrecognized
[]
byte
`json:"-"`
XXX_sizecache
int32
`json:"-"`
...
...
@@ -819,6 +847,13 @@ func (m *EstimateEVMGasReq) GetAmount() uint64 {
return
0
}
func
(
m
*
EstimateEVMGasReq
)
GetAbi
()
string
{
if
m
!=
nil
{
return
m
.
Abi
}
return
""
}
type
EstimateEVMGasResp
struct
{
Gas
uint64
`protobuf:"varint,1,opt,name=gas,proto3" json:"gas,omitempty"`
XXX_NoUnkeyedLiteral
struct
{}
`json:"-"`
...
...
@@ -937,6 +972,218 @@ func (m *EvmDebugResp) GetDebugStatus() string {
return
""
}
type
EvmQueryAbiReq
struct
{
Address
string
`protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
XXX_NoUnkeyedLiteral
struct
{}
`json:"-"`
XXX_unrecognized
[]
byte
`json:"-"`
XXX_sizecache
int32
`json:"-"`
}
func
(
m
*
EvmQueryAbiReq
)
Reset
()
{
*
m
=
EvmQueryAbiReq
{}
}
func
(
m
*
EvmQueryAbiReq
)
String
()
string
{
return
proto
.
CompactTextString
(
m
)
}
func
(
*
EvmQueryAbiReq
)
ProtoMessage
()
{}
func
(
*
EvmQueryAbiReq
)
Descriptor
()
([]
byte
,
[]
int
)
{
return
fileDescriptor_74353de561acd7c6
,
[]
int
{
15
}
}
func
(
m
*
EvmQueryAbiReq
)
XXX_Unmarshal
(
b
[]
byte
)
error
{
return
xxx_messageInfo_EvmQueryAbiReq
.
Unmarshal
(
m
,
b
)
}
func
(
m
*
EvmQueryAbiReq
)
XXX_Marshal
(
b
[]
byte
,
deterministic
bool
)
([]
byte
,
error
)
{
return
xxx_messageInfo_EvmQueryAbiReq
.
Marshal
(
b
,
m
,
deterministic
)
}
func
(
m
*
EvmQueryAbiReq
)
XXX_Merge
(
src
proto
.
Message
)
{
xxx_messageInfo_EvmQueryAbiReq
.
Merge
(
m
,
src
)
}
func
(
m
*
EvmQueryAbiReq
)
XXX_Size
()
int
{
return
xxx_messageInfo_EvmQueryAbiReq
.
Size
(
m
)
}
func
(
m
*
EvmQueryAbiReq
)
XXX_DiscardUnknown
()
{
xxx_messageInfo_EvmQueryAbiReq
.
DiscardUnknown
(
m
)
}
var
xxx_messageInfo_EvmQueryAbiReq
proto
.
InternalMessageInfo
func
(
m
*
EvmQueryAbiReq
)
GetAddress
()
string
{
if
m
!=
nil
{
return
m
.
Address
}
return
""
}
type
EvmQueryAbiResp
struct
{
Address
string
`protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
Abi
string
`protobuf:"bytes,2,opt,name=abi,proto3" json:"abi,omitempty"`
XXX_NoUnkeyedLiteral
struct
{}
`json:"-"`
XXX_unrecognized
[]
byte
`json:"-"`
XXX_sizecache
int32
`json:"-"`
}
func
(
m
*
EvmQueryAbiResp
)
Reset
()
{
*
m
=
EvmQueryAbiResp
{}
}
func
(
m
*
EvmQueryAbiResp
)
String
()
string
{
return
proto
.
CompactTextString
(
m
)
}
func
(
*
EvmQueryAbiResp
)
ProtoMessage
()
{}
func
(
*
EvmQueryAbiResp
)
Descriptor
()
([]
byte
,
[]
int
)
{
return
fileDescriptor_74353de561acd7c6
,
[]
int
{
16
}
}
func
(
m
*
EvmQueryAbiResp
)
XXX_Unmarshal
(
b
[]
byte
)
error
{
return
xxx_messageInfo_EvmQueryAbiResp
.
Unmarshal
(
m
,
b
)
}
func
(
m
*
EvmQueryAbiResp
)
XXX_Marshal
(
b
[]
byte
,
deterministic
bool
)
([]
byte
,
error
)
{
return
xxx_messageInfo_EvmQueryAbiResp
.
Marshal
(
b
,
m
,
deterministic
)
}
func
(
m
*
EvmQueryAbiResp
)
XXX_Merge
(
src
proto
.
Message
)
{
xxx_messageInfo_EvmQueryAbiResp
.
Merge
(
m
,
src
)
}
func
(
m
*
EvmQueryAbiResp
)
XXX_Size
()
int
{
return
xxx_messageInfo_EvmQueryAbiResp
.
Size
(
m
)
}
func
(
m
*
EvmQueryAbiResp
)
XXX_DiscardUnknown
()
{
xxx_messageInfo_EvmQueryAbiResp
.
DiscardUnknown
(
m
)
}
var
xxx_messageInfo_EvmQueryAbiResp
proto
.
InternalMessageInfo
func
(
m
*
EvmQueryAbiResp
)
GetAddress
()
string
{
if
m
!=
nil
{
return
m
.
Address
}
return
""
}
func
(
m
*
EvmQueryAbiResp
)
GetAbi
()
string
{
if
m
!=
nil
{
return
m
.
Abi
}
return
""
}
type
EvmQueryReq
struct
{
Address
string
`protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
Input
string
`protobuf:"bytes,2,opt,name=input,proto3" json:"input,omitempty"`
Caller
string
`protobuf:"bytes,3,opt,name=caller,proto3" json:"caller,omitempty"`
XXX_NoUnkeyedLiteral
struct
{}
`json:"-"`
XXX_unrecognized
[]
byte
`json:"-"`
XXX_sizecache
int32
`json:"-"`
}
func
(
m
*
EvmQueryReq
)
Reset
()
{
*
m
=
EvmQueryReq
{}
}
func
(
m
*
EvmQueryReq
)
String
()
string
{
return
proto
.
CompactTextString
(
m
)
}
func
(
*
EvmQueryReq
)
ProtoMessage
()
{}
func
(
*
EvmQueryReq
)
Descriptor
()
([]
byte
,
[]
int
)
{
return
fileDescriptor_74353de561acd7c6
,
[]
int
{
17
}
}
func
(
m
*
EvmQueryReq
)
XXX_Unmarshal
(
b
[]
byte
)
error
{
return
xxx_messageInfo_EvmQueryReq
.
Unmarshal
(
m
,
b
)
}
func
(
m
*
EvmQueryReq
)
XXX_Marshal
(
b
[]
byte
,
deterministic
bool
)
([]
byte
,
error
)
{
return
xxx_messageInfo_EvmQueryReq
.
Marshal
(
b
,
m
,
deterministic
)
}
func
(
m
*
EvmQueryReq
)
XXX_Merge
(
src
proto
.
Message
)
{
xxx_messageInfo_EvmQueryReq
.
Merge
(
m
,
src
)
}
func
(
m
*
EvmQueryReq
)
XXX_Size
()
int
{
return
xxx_messageInfo_EvmQueryReq
.
Size
(
m
)
}
func
(
m
*
EvmQueryReq
)
XXX_DiscardUnknown
()
{
xxx_messageInfo_EvmQueryReq
.
DiscardUnknown
(
m
)
}
var
xxx_messageInfo_EvmQueryReq
proto
.
InternalMessageInfo
func
(
m
*
EvmQueryReq
)
GetAddress
()
string
{
if
m
!=
nil
{
return
m
.
Address
}
return
""
}
func
(
m
*
EvmQueryReq
)
GetInput
()
string
{
if
m
!=
nil
{
return
m
.
Input
}
return
""
}
func
(
m
*
EvmQueryReq
)
GetCaller
()
string
{
if
m
!=
nil
{
return
m
.
Caller
}
return
""
}
type
EvmQueryResp
struct
{
Address
string
`protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
Input
string
`protobuf:"bytes,2,opt,name=input,proto3" json:"input,omitempty"`
Caller
string
`protobuf:"bytes,3,opt,name=caller,proto3" json:"caller,omitempty"`
RawData
string
`protobuf:"bytes,4,opt,name=rawData,proto3" json:"rawData,omitempty"`
JsonData
string
`protobuf:"bytes,5,opt,name=jsonData,proto3" json:"jsonData,omitempty"`
XXX_NoUnkeyedLiteral
struct
{}
`json:"-"`
XXX_unrecognized
[]
byte
`json:"-"`
XXX_sizecache
int32
`json:"-"`
}
func
(
m
*
EvmQueryResp
)
Reset
()
{
*
m
=
EvmQueryResp
{}
}
func
(
m
*
EvmQueryResp
)
String
()
string
{
return
proto
.
CompactTextString
(
m
)
}
func
(
*
EvmQueryResp
)
ProtoMessage
()
{}
func
(
*
EvmQueryResp
)
Descriptor
()
([]
byte
,
[]
int
)
{
return
fileDescriptor_74353de561acd7c6
,
[]
int
{
18
}
}
func
(
m
*
EvmQueryResp
)
XXX_Unmarshal
(
b
[]
byte
)
error
{
return
xxx_messageInfo_EvmQueryResp
.
Unmarshal
(
m
,
b
)
}
func
(
m
*
EvmQueryResp
)
XXX_Marshal
(
b
[]
byte
,
deterministic
bool
)
([]
byte
,
error
)
{
return
xxx_messageInfo_EvmQueryResp
.
Marshal
(
b
,
m
,
deterministic
)
}
func
(
m
*
EvmQueryResp
)
XXX_Merge
(
src
proto
.
Message
)
{
xxx_messageInfo_EvmQueryResp
.
Merge
(
m
,
src
)
}
func
(
m
*
EvmQueryResp
)
XXX_Size
()
int
{
return
xxx_messageInfo_EvmQueryResp
.
Size
(
m
)
}
func
(
m
*
EvmQueryResp
)
XXX_DiscardUnknown
()
{
xxx_messageInfo_EvmQueryResp
.
DiscardUnknown
(
m
)
}
var
xxx_messageInfo_EvmQueryResp
proto
.
InternalMessageInfo
func
(
m
*
EvmQueryResp
)
GetAddress
()
string
{
if
m
!=
nil
{
return
m
.
Address
}
return
""
}
func
(
m
*
EvmQueryResp
)
GetInput
()
string
{
if
m
!=
nil
{
return
m
.
Input
}
return
""
}
func
(
m
*
EvmQueryResp
)
GetCaller
()
string
{
if
m
!=
nil
{
return
m
.
Caller
}
return
""
}
func
(
m
*
EvmQueryResp
)
GetRawData
()
string
{
if
m
!=
nil
{
return
m
.
RawData
}
return
""
}
func
(
m
*
EvmQueryResp
)
GetJsonData
()
string
{
if
m
!=
nil
{
return
m
.
JsonData
}
return
""
}
func
init
()
{
proto
.
RegisterType
((
*
EVMContractObject
)(
nil
),
"types.EVMContractObject"
)
proto
.
RegisterType
((
*
EVMContractData
)(
nil
),
"types.EVMContractData"
)
...
...
@@ -955,55 +1202,67 @@ func init() {
proto
.
RegisterType
((
*
EstimateEVMGasResp
)(
nil
),
"types.EstimateEVMGasResp"
)
proto
.
RegisterType
((
*
EvmDebugReq
)(
nil
),
"types.EvmDebugReq"
)
proto
.
RegisterType
((
*
EvmDebugResp
)(
nil
),
"types.EvmDebugResp"
)
proto
.
RegisterType
((
*
EvmQueryAbiReq
)(
nil
),
"types.EvmQueryAbiReq"
)
proto
.
RegisterType
((
*
EvmQueryAbiResp
)(
nil
),
"types.EvmQueryAbiResp"
)
proto
.
RegisterType
((
*
EvmQueryReq
)(
nil
),
"types.EvmQueryReq"
)
proto
.
RegisterType
((
*
EvmQueryResp
)(
nil
),
"types.EvmQueryResp"
)
}
func
init
()
{
proto
.
RegisterFile
(
"evmcontract.proto"
,
fileDescriptor_74353de561acd7c6
)
}
var
fileDescriptor_74353de561acd7c6
=
[]
byte
{
// 716 bytes of a gzipped FileDescriptorProto
0x1f
,
0x8b
,
0x08
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x02
,
0xff
,
0xcc
,
0x55
,
0x41
,
0x6f
,
0xd3
,
0x4a
,
0x10
,
0x96
,
0x63
,
0x27
,
0x8d
,
0x27
,
0x79
,
0xaf
,
0xed
,
0xbe
,
0xf7
,
0xfa
,
0xac
,
0x8a
,
0x43
,
0xb4
,
0xa2
,
0x10
,
0x21
,
0x11
,
0xa1
,
0x72
,
0x41
,
0x3d
,
0x20
,
0x55
,
0xa9
,
0x55
,
0x90
,
0x08
,
0xa0
,
0xad
,
0x94
,
0xfb
,
0xd6
,
0x5e
,
0x52
,
0xd3
,
0xd8
,
0x6b
,
0xbc
,
0xeb
,
0x4a
,
0xbd
,
0xf2
,
0x1b
,
0xb8
,
0x20
,
0x71
,
0x00
,
0xf1
,
0xcf
,
0x38
,
0xf1
,
0x33
,
0xd0
,
0xee
,
0x3a
,
0xce
,
0xda
,
0x4d
,
0x6f
,
0x15
,
0xe2
,
0x94
,
0xf9
,
0x66
,
0x67
,
0x3d
,
0xdf
,
0xcc
,
0x7c
,
0xb3
,
0x81
,
0x5d
,
0x76
,
0x95
,
0x46
,
0x3c
,
0x93
,
0x05
,
0x8d
,
0xe4
,
0x24
,
0x2f
,
0xb8
,
0xe4
,
0xa8
,
0x2b
,
0xaf
,
0x73
,
0x26
,
0xf0
,
0x47
,
0x07
,
0x76
,
0xc3
,
0xf9
,
0x6c
,
0x5a
,
0x1d
,
0xbe
,
0x39
,
0x7f
,
0xcf
,
0x22
,
0x89
,
0x10
,
0x78
,
0x34
,
0x8e
,
0x8b
,
0xc0
,
0x19
,
0x39
,
0x63
,
0x9f
,
0x68
,
0x1b
,
0x3d
,
0x02
,
0x2f
,
0xa6
,
0x92
,
0x06
,
0x9d
,
0x91
,
0x33
,
0x1e
,
0x1c
,
0xee
,
0x4d
,
0xf4
,
0xfd
,
0x89
,
0x75
,
0xf7
,
0x84
,
0x4a
,
0x4a
,
0x74
,
0x0c
,
0x7a
,
0x0c
,
0x5d
,
0x21
,
0xa9
,
0x64
,
0x81
,
0xab
,
0x83
,
0xff
,
0xbf
,
0x19
,
0x7c
,
0xa6
,
0x8e
,
0x89
,
0x89
,
0xc2
,
0x9f
,
0x1d
,
0xd8
,
0x6e
,
0x7d
,
0x08
,
0x05
,
0xb0
,
0x15
,
0x15
,
0x8c
,
0x4a
,
0xbe
,
0x62
,
0xb1
,
0x82
,
0x8a
,
0x5c
,
0x46
,
0x53
,
0xa6
,
0x89
,
0xf8
,
0x44
,
0xdb
,
0xe8
,
0x5f
,
0xe8
,
0xd2
,
0x65
,
0x42
,
0x85
,
0x4e
,
0xe8
,
0x13
,
0x03
,
0xea
,
0x32
,
0x3c
,
0xab
,
0x0c
,
0x04
,
0x5e
,
0xc4
,
0x63
,
0x16
,
0x74
,
0x47
,
0xce
,
0x78
,
0x48
,
0xb4
,
0x8d
,
0xf6
,
0xa1
,
0xaf
,
0x7e
,
0x5f
,
0x50
,
0x71
,
0x11
,
0xf4
,
0xb4
,
0xbf
,
0xc6
,
0xf8
,
0x87
,
0x03
,
0x3b
,
0x6d
,
0xde
,
0x2a
,
0x5d
,
0xc6
,
0xb3
,
0x88
,
0x69
,
0x6a
,
0x1e
,
0x31
,
0x40
,
0x7d
,
0x46
,
0x94
,
0x49
,
0x94
,
0xc4
,
0x2c
,
0xd6
,
0xe4
,
0xfa
,
0xa4
,
0xc6
,
0x68
,
0x04
,
0x03
,
0x21
,
0x79
,
0x41
,
0x17
,
0x26
,
0x8b
,
0xab
,
0xb3
,
0xd8
,
0x2e
,
0xf4
,
0x1c
,
0xb6
,
0x2a
,
0x18
,
0x78
,
0x23
,
0x77
,
0x3c
,
0x38
,
0xbc
,
0x7f
,
0x4b
,
0xd7
,
0x26
,
0x67
,
0x26
,
0x2c
,
0xcc
,
0x64
,
0x71
,
0x4d
,
0x56
,
0x97
,
0xf6
,
0x8f
,
0x60
,
0x68
,
0x1f
,
0xa0
,
0x1d
,
0x70
,
0x2f
,
0xd9
,
0x75
,
0xd5
,
0x3c
,
0x65
,
0x2a
,
0xd6
,
0x57
,
0x74
,
0x59
,
0x9a
,
0xce
,
0x0d
,
0x89
,
0x01
,
0x47
,
0x9d
,
0x67
,
0x0e
,
0xfe
,
0xd6
,
0x54
,
0xc1
,
0x71
,
0x24
,
0x13
,
0x9e
,
0xa1
,
0x3d
,
0xe8
,
0xd1
,
0x94
,
0x97
,
0x99
,
0xac
,
0xca
,
0xac
,
0x90
,
0xaa
,
0x73
,
0x41
,
0xc5
,
0xab
,
0x24
,
0x4d
,
0xa4
,
0xfe
,
0x94
,
0x47
,
0x6a
,
0x5c
,
0x9d
,
0xbd
,
0x2d
,
0x92
,
0xc8
,
0x0c
,
0xff
,
0x2f
,
0x52
,
0xe3
,
0xba
,
0xf5
,
0x9e
,
0xd5
,
0xfa
,
0x7a
,
0x70
,
0xdd
,
0xd6
,
0xe0
,
0x32
,
0x2e
,
0x99
,
0x1e
,
0x86
,
0x1a
,
0x31
,
0x97
,
0x0c
,
0x7f
,
0x75
,
0x00
,
0x11
,
0x16
,
0xb1
,
0x24
,
0x97
,
0x16
,
0x55
,
0x45
,
0x32
,
0xa2
,
0xcb
,
0x25
,
0x5b
,
0xc9
,
0xa4
,
0x42
,
0x08
,
0xc3
,
0x70
,
0xa5
,
0xf8
,
0xd7
,
0x6b
,
0xb5
,
0x34
,
0x7c
,
0x76
,
0xcc
,
0xb1
,
0xd2
,
0x89
,
0xdb
,
0x8c
,
0x51
,
0x3e
,
0xa5
,
0xc3
,
0x52
,
0xb0
,
0xf8
,
0x94
,
0x0a
,
0xcd
,
0xdb
,
0x23
,
0x2b
,
0xa8
,
0x1a
,
0x5c
,
0x30
,
0x59
,
0x09
,
0x49
,
0x99
,
0xf8
,
0x1d
,
0xa0
,
0x70
,
0x3e
,
0xd3
,
0x43
,
0x9a
,
0x5e
,
0xd0
,
0x6c
,
0xc1
,
0x5e
,
0x4a
,
0x96
,
0x6e
,
0x18
,
0xc4
,
0x3e
,
0xf4
,
0xf3
,
0x82
,
0xcd
,
0xad
,
0x59
,
0xd4
,
0x58
,
0x73
,
0x2a
,
0x8b
,
0x82
,
0x65
,
0xd2
,
0x9c
,
0x1b
,
0xa5
,
0x34
,
0x7c
,
0xf8
,
0x8b
,
0xa3
,
0x13
,
0xd9
,
0xfb
,
0x32
,
0x4d
,
0xe3
,
0xdf
,
0xb2
,
0x32
,
0xfe
,
0x2d
,
0x2b
,
0xe3
,
0x5b
,
0x2b
,
0xf3
,
0xd3
,
0x81
,
0x7f
,
0xda
,
0xa2
,
0x55
,
0xfc
,
0xee
,
0x64
,
0x6b
,
0xfc
,
0xe6
,
0xd6
,
0x1c
,
0xb7
,
0xb7
,
0xe6
,
0xe1
,
0x2d
,
0x5b
,
0x33
,
0x4d
,
0xe3
,
0xbb
,
0x59
,
0x1c
,
0xdf
,
0x5e
,
0x9c
,
0xef
,
0x0e
,
0xfc
,
0x77
,
0x53
,
0x94
,
0xaa
,
0xd8
,
0x3f
,
0x42
,
0x97
,
0xbe
,
0xd1
,
0xe5
,
0x01
,
0x6c
,
0x4f
,
0x2f
,
0x58
,
0x74
,
0x19
,
0xce
,
0x67
,
0xea
,
0x2e
,
0x61
,
0x1f
,
0x36
,
0xbd
,
0xf0
,
0xf8
,
0x93
,
0x03
,
0x3b
,
0xcd
,
0x38
,
0x91
,
0x9b
,
0x41
,
0x9b
,
0xbc
,
0x3a
,
0xb8
,
0x4f
,
0x6a
,
0x7c
,
0x83
,
0x67
,
0x67
,
0x03
,
0xcf
,
0x76
,
0xbd
,
0xee
,
0x86
,
0x7a
,
0xef
,
0x81
,
0xaf
,
0xd5
,
0xa7
,
0x03
,
0x8c
,
0xf2
,
0xd6
,
0x0e
,
0xbc
,
0x80
,
0xdd
,
0x50
,
0xc8
,
0x24
,
0xa5
,
0x92
,
0x85
,
0xf3
,
0xd9
,
0x29
,
0x15
,
0x8a
,
0xff
,
0xdf
,
0xd0
,
0x91
,
0xbc
,
0x62
,
0xdf
,
0x91
,
0xbc
,
0xd6
,
0x68
,
0xc7
,
0x7a
,
0x5b
,
0xd6
,
0x23
,
0x70
,
0x1b
,
0x23
,
0x58
,
0xbf
,
0x6b
,
0x9e
,
0xfd
,
0xae
,
0xe1
,
0x07
,
0x80
,
0xda
,
0x89
,
0x44
,
0xae
,
0xda
,
0xb9
,
0xa0
,
0xa2
,
0xd2
,
0xac
,
0x32
,
0xf1
,
0x01
,
0x0c
,
0xc2
,
0xab
,
0xf4
,
0x84
,
0x9d
,
0x97
,
0x0b
,
0x45
,
0x65
,
0x0f
,
0x7a
,
0x3c
,
0x57
,
0xa2
,
0xd3
,
0x31
,
0x5d
,
0x52
,
0x21
,
0xfc
,
0x04
,
0x86
,
0xeb
,
0x30
,
0x91
,
0x2b
,
0x31
,
0xc7
,
0x0a
,
0x28
,
0x39
,
0x96
,
0xa2
,
0xe2
,
0x6e
,
0xbb
,
0xce
,
0x7b
,
0xfa
,
0xaf
,
0xf9
,
0xe9
,
0xaf
,
0x00
,
0x00
,
0x00
,
0xff
,
0xff
,
0xc4
,
0x9f
,
0x0e
,
0xf7
,
0xaf
,
0x07
,
0x00
,
0x00
,
// 833 bytes of a gzipped FileDescriptorProto
0x1f
,
0x8b
,
0x08
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x02
,
0xff
,
0xcc
,
0x56
,
0x4b
,
0x6f
,
0x2b
,
0x35
,
0x18
,
0xd5
,
0x24
,
0x93
,
0xc7
,
0x7c
,
0x09
,
0xb7
,
0xad
,
0x81
,
0x32
,
0xaa
,
0x58
,
0x44
,
0x16
,
0x17
,
0xa2
,
0x2b
,
0x11
,
0xa1
,
0xcb
,
0x06
,
0x5d
,
0x09
,
0xa4
,
0x28
,
0x77
,
0x54
,
0x90
,
0x08
,
0x0f
,
0x57
,
0x64
,
0xef
,
0xcc
,
0x98
,
0x74
,
0xda
,
0xcc
,
0x83
,
0xb1
,
0x27
,
0x28
,
0x5b
,
0xd6
,
0x2c
,
0x59
,
0xb2
,
0x63
,
0xc9
,
0x92
,
0x1d
,
0x3f
,
0x87
,
0x15
,
0x3f
,
0x03
,
0x7d
,
0x1e
,
0xcf
,
0x2b
,
0x4d
,
0x2a
,
0x21
,
0x55
,
0x88
,
0x55
,
0x7d
,
0xec
,
0x63
,
0xfb
,
0x9c
,
0xf9
,
0xce
,
0xe7
,
0x06
,
0x2e
,
0xc4
,
0x2e
,
0xf2
,
0x93
,
0x58
,
0x65
,
0xdc
,
0x57
,
0xb3
,
0x34
,
0x4b
,
0x54
,
0x42
,
0x7a
,
0x6a
,
0x9f
,
0x0a
,
0x49
,
0x7f
,
0xb2
,
0xe0
,
0xc2
,
0x5b
,
0x2d
,
0x17
,
0x66
,
0xf1
,
0xeb
,
0xf5
,
0x9d
,
0xf0
,
0x15
,
0x21
,
0x60
,
0xf3
,
0x20
,
0xc8
,
0x5c
,
0x6b
,
0x62
,
0x4d
,
0x1d
,
0xa6
,
0xc7
,
0xe4
,
0x05
,
0xd8
,
0x01
,
0x57
,
0xdc
,
0xed
,
0x4c
,
0xac
,
0xe9
,
0xe8
,
0xe5
,
0xe5
,
0x4c
,
0xef
,
0x9f
,
0x35
,
0xf6
,
0xbe
,
0xe6
,
0x8a
,
0x33
,
0xcd
,
0x21
,
0x1f
,
0x42
,
0x4f
,
0x2a
,
0xae
,
0x84
,
0xdb
,
0xd5
,
0xe4
,
0x77
,
0x1e
,
0x92
,
0x6f
,
0x70
,
0x99
,
0x15
,
0x2c
,
0xfa
,
0xbb
,
0x05
,
0x67
,
0x07
,
0x07
,
0x11
,
0x17
,
0x06
,
0x7e
,
0x26
,
0xb8
,
0x4a
,
0x4a
,
0x15
,
0x25
,
0x44
,
0x71
,
0x31
,
0x8f
,
0x84
,
0x16
,
0xe2
,
0x30
,
0x3d
,
0x26
,
0x6f
,
0x41
,
0x8f
,
0x6f
,
0x43
,
0x2e
,
0xf5
,
0x85
,
0x0e
,
0x2b
,
0x40
,
0x65
,
0xc3
,
0x6e
,
0xd8
,
0x20
,
0x60
,
0xfb
,
0x49
,
0x20
,
0xdc
,
0xde
,
0xc4
,
0x9a
,
0x8e
,
0x99
,
0x1e
,
0x93
,
0x2b
,
0x18
,
0xe2
,
0xdf
,
0xcf
,
0xb9
,
0xbc
,
0x75
,
0xfb
,
0x7a
,
0xbe
,
0xc2
,
0xe4
,
0x1c
,
0xba
,
0x7c
,
0x1d
,
0xba
,
0x03
,
0x7d
,
0x04
,
0x0e
,
0xe9
,
0x5f
,
0x16
,
0x9c
,
0x1f
,
0x3a
,
0x41
,
0x01
,
0x71
,
0x12
,
0xfb
,
0x42
,
0x8b
,
0xb5
,
0x59
,
0x01
,
0xf0
,
0x60
,
0x99
,
0x87
,
0x7e
,
0x18
,
0x88
,
0x40
,
0xcb
,
0x1d
,
0xb2
,
0x0a
,
0x93
,
0x09
,
0x8c
,
0xa4
,
0x4a
,
0x32
,
0xbe
,
0x29
,
0xee
,
0xed
,
0xea
,
0x7b
,
0x9b
,
0x53
,
0xe4
,
0x33
,
0x18
,
0x18
,
0xe8
,
0xda
,
0x93
,
0xee
,
0x74
,
0xf4
,
0xf2
,
0xbd
,
0x13
,
0xdf
,
0x71
,
0x76
,
0x53
,
0xd0
,
0xbc
,
0x58
,
0x65
,
0x7b
,
0x56
,
0x6e
,
0xba
,
0x7a
,
0x05
,
0xe3
,
0xe6
,
0x02
,
0x5a
,
0xb9
,
0x17
,
0x7b
,
0xf3
,
0x39
,
0x71
,
0x88
,
0xaa
,
0x77
,
0x7c
,
0x9b
,
0x17
,
0xdf
,
0x72
,
0xcc
,
0x0a
,
0xf0
,
0xaa
,
0xf3
,
0x89
,
0x45
,
0xff
,
0x68
,
0xe7
,
0x62
,
0xee
,
0xab
,
0x30
,
0x89
,
0xc9
,
0x25
,
0xf4
,
0x79
,
0x94
,
0xe4
,
0xb1
,
0x32
,
0x36
,
0x0d
,
0x42
,
0x9f
,
0x1b
,
0x2e
,
0xbf
,
0x0c
,
0xa3
,
0x50
,
0xe9
,
0xa3
,
0x6c
,
0x56
,
0x61
,
0xb3
,
0xf6
,
0x4d
,
0x16
,
0xfa
,
0x45
,
0x1c
,
0xde
,
0x60
,
0x15
,
0xae
,
0x8a
,
0x61
,
0x37
,
0x8a
,
0x51
,
0x95
,
0xb2
,
0x77
,
0x50
,
0xca
,
0x38
,
0x51
,
0x42
,
0x97
,
0x07
,
0x8b
,
0x9e
,
0x28
,
0x71
,
0xa4
,
0x34
,
0x7f
,
0x5a
,
0x40
,
0x98
,
0xf0
,
0x45
,
0x98
,
0xaa
,
0x86
,
0x78
,
0x94
,
0xed
,
0xf3
,
0xed
,
0x56
,
0x94
,
0x51
,
0x32
,
0x88
,
0x50
,
0x18
,
0x97
,
0x5d
,
0xf1
,
0x55
,
0x9d
,
0xa8
,
0xd6
,
0x5c
,
0x93
,
0x33
,
0xc7
,
0x2c
,
0x75
,
0xdb
,
0x1c
,
0x9c
,
0xc3
,
0xac
,
0xe6
,
0x52
,
0x04
,
0xd7
,
0x5c
,
0x6a
,
0x27
,
0x36
,
0x2b
,
0x21
,
0x4a
,
0xcc
,
0x84
,
0x32
,
0x61
,
0xc3
,
0x21
,
0x72
,
0xef
,
0x64
,
0x12
,
0x33
,
0xa1
,
0x8c
,
0x97
,
0x12
,
0xd2
,
0xef
,
0x81
,
0x78
,
0xab
,
0xa5
,
0x2e
,
0xe8
,
0xe2
,
0x96
,
0xc7
,
0x1b
,
0xf1
,
0x85
,
0x12
,
0xd1
,
0x91
,
0xa2
,
0x5d
,
0xc1
,
0x30
,
0xcd
,
0xc4
,
0xaa
,
0x51
,
0xb7
,
0x0a
,
0x6b
,
0xb5
,
0x79
,
0x96
,
0x89
,
0x58
,
0x15
,
0xeb
,
0x45
,
0xaa
,
0x5a
,
0x73
,
0xf4
,
0x57
,
0x4b
,
0x5f
,
0xd4
,
0xec
,
0xb6
,
0x45
,
0x14
,
0xfc
,
0x27
,
0x0d
,
0xe7
,
0x9c
,
0x68
,
0x38
,
0xa7
,
0x6e
,
0x38
,
0xfa
,
0xb7
,
0x05
,
0x6f
,
0x1e
,
0x06
,
0x1c
,
0xf5
,
0x3d
,
0x49
,
0x87
,
0x39
,
0xed
,
0x0e
,
0x9b
,
0x1f
,
0x76
,
0xd8
,
0x07
,
0x27
,
0x3a
,
0x6c
,
0x11
,
0x05
,
0x4f
,
0xd3
,
0x64
,
0x4e
,
0xb3
,
0xc9
,
0x7e
,
0xb3
,
0xe0
,
0xed
,
0x87
,
0x71
,
0x45
,
0xb3
,
0xff
,
0x8b
,
0xc4
,
0x3a
,
0x3a
,
0xb1
,
0xf4
,
0x39
,
0x9c
,
0x2d
,
0x6e
,
0x85
,
0x7f
,
0xef
,
0xad
,
0x96
,
0xb8
,
0x97
,
0x89
,
0x1f
,
0x8e
,
0xfd
,
0x7f
,
0xa0
,
0xbf
,
0x58
,
0x70
,
0xde
,
0xe6
,
0xc9
,
0xb4
,
0x28
,
0x74
,
0x71
,
0xaf
,
0x26
,
0x0f
,
0x59
,
0x85
,
0x1f
,
0xe8
,
0xec
,
0x1c
,
0xd1
,
0x79
,
0xe8
,
0xb7
,
0x7b
,
0xc4
,
0xef
,
0xbb
,
0xe0
,
0xe8
,
0xf4
,
0x69
,
0x42
,
0x91
,
0xbc
,
0x7a
,
0x82
,
0xee
,
0xe1
,
0xc2
,
0x93
,
0x2a
,
0x8c
,
0xb8
,
0x12
,
0xde
,
0x6a
,
0x79
,
0xcd
,
0x25
,
0xea
,
0x7f
,
0x06
,
0x1d
,
0x95
,
0x18
,
0xf5
,
0x1d
,
0x95
,
0x54
,
0x19
,
0xed
,
0x34
,
0xde
,
0xa1
,
0xba
,
0x04
,
0xdd
,
0x56
,
0x09
,
0xea
,
0x37
,
0xd0
,
0x6e
,
0xbd
,
0x81
,
0xe6
,
0x35
,
0xea
,
0xd5
,
0xaf
,
0xd1
,
0xfb
,
0x40
,
0x0e
,
0xaf
,
0x96
,
0x29
,
0xf2
,
0x36
,
0x5c
,
0x9a
,
0x14
,
0xe3
,
0x90
,
0x3e
,
0x87
,
0x91
,
0xb7
,
0x8b
,
0x5e
,
0x8b
,
0x75
,
0xbe
,
0x41
,
0x71
,
0x97
,
0xd0
,
0x4f
,
0x52
,
0x8c
,
0xa1
,
0xe6
,
0xf4
,
0x98
,
0x41
,
0xf4
,
0x23
,
0x18
,
0xd7
,
0x34
,
0x99
,
0x62
,
0xbc
,
0x03
,
0x04
,
0x18
,
0xd0
,
0x5c
,
0x1a
,
0x37
,
0xcd
,
0x29
,
0xfa
,
0x02
,
0x9e
,
0x79
,
0xbb
,
0xe8
,
0xdb
,
0x5c
,
0x64
,
0xfb
,
0xf9
,
0x3a
,
0xc4
,
0xb3
,
0x5d
,
0x18
,
0x60
,
0xb1
,
0x84
,
0x2c
,
0xf9
,
0x25
,
0xa4
,
0x9f
,
0xc2
,
0x59
,
0x8b
,
0x2b
,
0xd3
,
0xd3
,
0xe4
,
0xd2
,
0x6b
,
0xa7
,
0xf6
,
0xfa
,
0x9d
,
0xf6
,
0xa0
,
0xb7
,
0x3f
,
0x7a
,
0x0f
,
0x76
,
0x43
,
0x18
,
0xa7
,
0xb9
,
0x2a
,
0xbb
,
0x41
,
0x83
,
0x53
,
0x1f
,
0x9b
,
0xfe
,
0x6c
,
0x69
,
0xd3
,
0xe6
,
0xdc
,
0x47
,
0x35
,
0xfd
,
0xab
,
0x83
,
0xf1
,
0x9c
,
0x8c
,
0xff
,
0x88
,
0x6f
,
0x9f
,
0x89
,
0x4c
,
0x09
,
0x31
,
0xb2
,
0xf8
,
0x22
,
0xeb
,
0xa5
,
0xa2
,
0x98
,
0x15
,
0x5e
,
0xf7
,
0xf5
,
0x6f
,
0xa7
,
0x8f
,
0xff
,
0x09
,
0x00
,
0x00
,
0xff
,
0xff
,
0x22
,
0x7b
,
0xc5
,
0xdf
,
0x50
,
0x09
,
0x00
,
0x00
,
}
plugin/dapp/evm/types/tx.go
View file @
b2ebdcd4
...
...
@@ -24,4 +24,6 @@ type CreateCallTx struct {
Name
string
`json:"name"`
// IsCreate 是否创建合约
IsCreate
bool
`json:"isCreate"`
// Abi 创建合约或调用合约时附带的ABI数据
Abi
string
`json:"abi"`
}
plugin/dapp/evm/types/types.go
View file @
b2ebdcd4
...
...
@@ -29,6 +29,17 @@ const (
MaxGasLimit
=
10000000
)
const
(
// EVMEnable 启用EVM
EVMEnable
=
"Enable"
// ForkEVMState EVM合约中的数据分散存储,支持大数据量
ForkEVMState
=
"ForkEVMState"
// ForkEVMKVHash EVM合约状态数据生成哈希,保存在主链的StateDB中
ForkEVMKVHash
=
"ForkEVMKVHash"
// ForkEVMABI EVM合约支持ABI绑定和调用
ForkEVMABI
=
"ForkEVMABI"
)
var
(
// EvmPrefix 本执行器前缀
EvmPrefix
=
"user.evm."
...
...
vendor/github.com/golang-collections/collections/LICENSE
0 → 100644
View file @
b2ebdcd4
Copyright (c) 2012 Caleb Doxsey
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
vendor/github.com/golang-collections/collections/stack/stack.go
0 → 100644
View file @
b2ebdcd4
package
stack
type
(
Stack
struct
{
top
*
node
length
int
}
node
struct
{
value
interface
{}
prev
*
node
}
)
// Create a new stack
func
New
()
*
Stack
{
return
&
Stack
{
nil
,
0
}
}
// Return the number of items in the stack
func
(
this
*
Stack
)
Len
()
int
{
return
this
.
length
}
// View the top item on the stack
func
(
this
*
Stack
)
Peek
()
interface
{}
{
if
this
.
length
==
0
{
return
nil
}
return
this
.
top
.
value
}
// Pop the top item of the stack and return it
func
(
this
*
Stack
)
Pop
()
interface
{}
{
if
this
.
length
==
0
{
return
nil
}
n
:=
this
.
top
this
.
top
=
n
.
prev
this
.
length
--
return
n
.
value
}
// Push a value onto the top of the stack
func
(
this
*
Stack
)
Push
(
value
interface
{})
{
n
:=
&
node
{
value
,
this
.
top
}
this
.
top
=
n
this
.
length
++
}
\ No newline at end of file
vendor/vendor.json
View file @
b2ebdcd4
...
...
@@ -119,6 +119,12 @@
"revisionTime"
:
"2018-11-04T16:40:17Z"
},
{
"checksumSHA1"
:
"06pu4WTqbWBAHCJhCLZaI1droeM="
,
"path"
:
"github.com/golang-collections/collections/stack"
,
"revision"
:
"604e922904d35e97f98a774db7881f049cd8d970"
,
"revisionTime"
:
"2013-07-29T18:54:59Z"
},
{
"checksumSHA1"
:
"BP2buXHHOKxI5eYS2xELVng2kf4="
,
"path"
:
"github.com/golang/protobuf/jsonpb"
,
"revision"
:
"951a149f90371fb8858c6c979d03bb2583611052"
,
...
...
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