Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
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
张蕾
Geth-Modification
Commits
2f997209
Commit
2f997209
authored
Aug 22, 2016
by
Nick Johnson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core/vm, eth: Add support for javascript trace functions
parent
d8cec35b
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
551 additions
and
18 deletions
+551
-18
jit_test.go
core/vm/jit_test.go
+4
-7
logger_test.go
core/vm/logger_test.go
+2
-2
api.go
eth/api.go
+57
-8
tracer.go
internal/ethapi/tracer.go
+300
-0
tracer_test.go
internal/ethapi/tracer_test.go
+186
-0
web3ext.go
internal/web3ext/web3ext.go
+2
-1
No files found.
core/vm/jit_test.go
View file @
2f997209
...
...
@@ -85,7 +85,7 @@ func TestCompiling(t *testing.T) {
func
TestResetInput
(
t
*
testing
.
T
)
{
var
sender
account
env
:=
NewEnv
(
false
,
true
)
env
:=
NewEnv
(
&
Config
{
EnableJit
:
true
,
ForceJit
:
true
}
)
contract
:=
NewContract
(
sender
,
sender
,
big
.
NewInt
(
100
),
big
.
NewInt
(
10000
),
big
.
NewInt
(
0
))
contract
.
CodeAddr
=
&
common
.
Address
{}
...
...
@@ -144,7 +144,7 @@ func runVmBench(test vmBench, b *testing.B) {
if
test
.
precompile
&&
!
test
.
forcejit
{
NewProgram
(
test
.
code
)
}
env
:=
NewEnv
(
test
.
nojit
,
test
.
forcejit
)
env
:=
NewEnv
(
&
Config
{
EnableJit
:
!
test
.
nojit
,
ForceJit
:
test
.
forcejit
}
)
b
.
ResetTimer
()
...
...
@@ -166,12 +166,9 @@ type Env struct {
evm
*
EVM
}
func
NewEnv
(
noJit
,
forceJit
bool
)
*
Env
{
func
NewEnv
(
config
*
Config
)
*
Env
{
env
:=
&
Env
{
gasLimit
:
big
.
NewInt
(
10000
),
depth
:
0
}
env
.
evm
=
New
(
env
,
Config
{
EnableJit
:
!
noJit
,
ForceJit
:
forceJit
,
})
env
.
evm
=
New
(
env
,
*
config
)
return
env
}
...
...
core/vm/logger_test.go
View file @
2f997209
...
...
@@ -47,7 +47,7 @@ type dummyEnv struct {
func
newDummyEnv
(
ref
*
dummyContractRef
)
*
dummyEnv
{
return
&
dummyEnv
{
Env
:
NewEnv
(
true
,
false
),
Env
:
NewEnv
(
&
Config
{
EnableJit
:
false
,
ForceJit
:
false
}
),
ref
:
ref
,
}
}
...
...
@@ -57,7 +57,7 @@ func (d dummyEnv) GetAccount(common.Address) Account {
func
TestStoreCapture
(
t
*
testing
.
T
)
{
var
(
env
=
NewEnv
(
true
,
false
)
env
=
NewEnv
(
&
Config
{
EnableJit
:
false
,
ForceJit
:
false
}
)
logger
=
NewStructLogger
(
nil
)
mem
=
NewMemory
()
stack
=
newstack
()
...
...
eth/api.go
View file @
2f997209
...
...
@@ -25,6 +25,7 @@ import (
"math/big"
"os"
"runtime"
"time"
"github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/common"
...
...
@@ -38,8 +39,11 @@ import (
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"golang.org/x/net/context"
)
const
defaultTraceTimeout
=
5
*
time
.
Second
// PublicEthereumAPI provides an API to access Ethereum full node-related
// information.
type
PublicEthereumAPI
struct
{
...
...
@@ -317,6 +321,13 @@ type BlockTraceResult struct {
Error
string
`json:"error"`
}
// TraceArgs holds extra parameters to trace functions
type
TraceArgs
struct
{
*
vm
.
LogConfig
Tracer
*
string
Timeout
*
string
}
// TraceBlock processes the given block's RLP but does not import the block in to
// the chain.
func
(
api
*
PrivateDebugAPI
)
TraceBlock
(
blockRlp
[]
byte
,
config
*
vm
.
LogConfig
)
BlockTraceResult
{
...
...
@@ -439,10 +450,42 @@ func formatError(err error) string {
return
err
.
Error
()
}
type
timeoutError
struct
{}
func
(
t
*
timeoutError
)
Error
()
string
{
return
"Execution time exceeded"
}
// TraceTransaction returns the structured logs created during the execution of EVM
// and returns them as a JSON object.
func
(
api
*
PrivateDebugAPI
)
TraceTransaction
(
txHash
common
.
Hash
,
logConfig
*
vm
.
LogConfig
)
(
*
ethapi
.
ExecutionResult
,
error
)
{
logger
:=
vm
.
NewStructLogger
(
logConfig
)
func
(
api
*
PrivateDebugAPI
)
TraceTransaction
(
ctx
context
.
Context
,
txHash
common
.
Hash
,
config
*
TraceArgs
)
(
interface
{},
error
)
{
var
tracer
vm
.
Tracer
if
config
!=
nil
&&
config
.
Tracer
!=
nil
{
timeout
:=
defaultTraceTimeout
if
config
.
Timeout
!=
nil
{
var
err
error
if
timeout
,
err
=
time
.
ParseDuration
(
*
config
.
Timeout
);
err
!=
nil
{
return
nil
,
err
}
}
var
err
error
if
tracer
,
err
=
ethapi
.
NewJavascriptTracer
(
*
config
.
Tracer
);
err
!=
nil
{
return
nil
,
err
}
// Handle timeouts and RPC cancellations
deadlineCtx
,
cancel
:=
context
.
WithTimeout
(
ctx
,
timeout
)
go
func
()
{
<-
deadlineCtx
.
Done
()
tracer
.
(
*
ethapi
.
JavascriptTracer
)
.
Stop
(
&
timeoutError
{})
}()
defer
cancel
()
}
else
if
config
==
nil
{
tracer
=
vm
.
NewStructLogger
(
nil
)
}
else
{
tracer
=
vm
.
NewStructLogger
(
config
.
LogConfig
)
}
// Retrieve the tx from the chain and the containing block
tx
,
blockHash
,
_
,
txIndex
:=
core
.
GetTransaction
(
api
.
eth
.
ChainDb
(),
txHash
)
...
...
@@ -488,16 +531,22 @@ func (api *PrivateDebugAPI) TraceTransaction(txHash common.Hash, logConfig *vm.L
continue
}
// Otherwise trace the transaction and return
vmenv
:=
core
.
NewEnv
(
stateDb
,
api
.
config
,
api
.
eth
.
BlockChain
(),
msg
,
block
.
Header
(),
vm
.
Config
{
Debug
:
true
,
Tracer
:
logg
er
})
vmenv
:=
core
.
NewEnv
(
stateDb
,
api
.
config
,
api
.
eth
.
BlockChain
(),
msg
,
block
.
Header
(),
vm
.
Config
{
Debug
:
true
,
Tracer
:
trac
er
})
ret
,
gas
,
err
:=
core
.
ApplyMessage
(
vmenv
,
msg
,
new
(
core
.
GasPool
)
.
AddGas
(
tx
.
Gas
()))
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"tracing failed: %v"
,
err
)
}
return
&
ethapi
.
ExecutionResult
{
Gas
:
gas
,
ReturnValue
:
fmt
.
Sprintf
(
"%x"
,
ret
),
StructLogs
:
ethapi
.
FormatLogs
(
logger
.
StructLogs
()),
},
nil
switch
tracer
:=
tracer
.
(
type
)
{
case
*
vm
.
StructLogger
:
return
&
ethapi
.
ExecutionResult
{
Gas
:
gas
,
ReturnValue
:
fmt
.
Sprintf
(
"%x"
,
ret
),
StructLogs
:
ethapi
.
FormatLogs
(
tracer
.
StructLogs
()),
},
nil
case
*
ethapi
.
JavascriptTracer
:
return
tracer
.
GetResult
()
}
}
return
nil
,
errors
.
New
(
"database inconsistency"
)
}
internal/ethapi/tracer.go
0 → 100644
View file @
2f997209
// 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
ethapi
import
(
"errors"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/robertkrimen/otto"
)
// fakeBig is used to provide an interface to Javascript for 'big.NewInt'
type
fakeBig
struct
{}
// NewInt creates a new big.Int with the specified int64 value.
func
(
fb
*
fakeBig
)
NewInt
(
x
int64
)
*
big
.
Int
{
return
big
.
NewInt
(
x
)
}
// OpCodeWrapper provides a JavaScript-friendly wrapper around OpCode, to convince Otto to treat it
// as an object, instead of a number.
type
opCodeWrapper
struct
{
op
vm
.
OpCode
}
// toNumber returns the ID of this opcode as an integer
func
(
ocw
*
opCodeWrapper
)
toNumber
()
int
{
return
int
(
ocw
.
op
)
}
// toString returns the string representation of the opcode
func
(
ocw
*
opCodeWrapper
)
toString
()
string
{
return
ocw
.
op
.
String
()
}
// isPush returns true if the op is a Push
func
(
ocw
*
opCodeWrapper
)
isPush
()
bool
{
return
ocw
.
op
.
IsPush
()
}
// toValue returns an otto.Value for the opCodeWrapper
func
(
ocw
*
opCodeWrapper
)
toValue
(
vm
*
otto
.
Otto
)
otto
.
Value
{
value
,
_
:=
vm
.
ToValue
(
ocw
)
obj
:=
value
.
Object
()
obj
.
Set
(
"toNumber"
,
ocw
.
toNumber
)
obj
.
Set
(
"toString"
,
ocw
.
toString
)
obj
.
Set
(
"isPush"
,
ocw
.
isPush
)
return
value
}
// memoryWrapper provides a JS wrapper around vm.Memory
type
memoryWrapper
struct
{
memory
*
vm
.
Memory
}
// slice returns the requested range of memory as a byte slice
func
(
mw
*
memoryWrapper
)
slice
(
begin
,
end
int64
)
[]
byte
{
return
mw
.
memory
.
Get
(
begin
,
end
-
begin
)
}
// getUint returns the 32 bytes at the specified address interpreted
// as an unsigned integer
func
(
mw
*
memoryWrapper
)
getUint
(
addr
int64
)
*
big
.
Int
{
ret
:=
big
.
NewInt
(
0
)
ret
.
SetBytes
(
mw
.
memory
.
GetPtr
(
addr
,
32
))
return
ret
}
// toValue returns an otto.Value for the memoryWrapper
func
(
mw
*
memoryWrapper
)
toValue
(
vm
*
otto
.
Otto
)
otto
.
Value
{
value
,
_
:=
vm
.
ToValue
(
mw
)
obj
:=
value
.
Object
()
obj
.
Set
(
"slice"
,
mw
.
slice
)
obj
.
Set
(
"getUint"
,
mw
.
getUint
)
return
value
}
// stackWrapper provides a JS wrapper around vm.Stack
type
stackWrapper
struct
{
stack
*
vm
.
Stack
}
// peek returns the nth-from-the-top element of the stack.
func
(
sw
*
stackWrapper
)
peek
(
idx
int
)
*
big
.
Int
{
return
sw
.
stack
.
Data
()[
len
(
sw
.
stack
.
Data
())
-
idx
-
1
]
}
// length returns the length of the stack
func
(
sw
*
stackWrapper
)
length
()
int
{
return
len
(
sw
.
stack
.
Data
())
}
// toValue returns an otto.Value for the stackWrapper
func
(
sw
*
stackWrapper
)
toValue
(
vm
*
otto
.
Otto
)
otto
.
Value
{
value
,
_
:=
vm
.
ToValue
(
sw
)
obj
:=
value
.
Object
()
obj
.
Set
(
"peek"
,
sw
.
peek
)
obj
.
Set
(
"length"
,
sw
.
length
)
return
value
}
// dbWrapper provides a JS wrapper around vm.Database
type
dbWrapper
struct
{
db
vm
.
Database
}
// getBalance retrieves an account's balance
func
(
dw
*
dbWrapper
)
getBalance
(
addr
common
.
Address
)
*
big
.
Int
{
return
dw
.
db
.
GetBalance
(
addr
)
}
// getNonce retrieves an account's nonce
func
(
dw
*
dbWrapper
)
getNonce
(
addr
common
.
Address
)
uint64
{
return
dw
.
db
.
GetNonce
(
addr
)
}
// getCode retrieves an account's code
func
(
dw
*
dbWrapper
)
getCode
(
addr
common
.
Address
)
[]
byte
{
return
dw
.
db
.
GetCode
(
addr
)
}
// getState retrieves an account's state data for the given hash
func
(
dw
*
dbWrapper
)
getState
(
addr
common
.
Address
,
hash
common
.
Hash
)
common
.
Hash
{
return
dw
.
db
.
GetState
(
addr
,
hash
)
}
// exists returns true iff the account exists
func
(
dw
*
dbWrapper
)
exists
(
addr
common
.
Address
)
bool
{
return
dw
.
db
.
Exist
(
addr
)
}
// toValue returns an otto.Value for the dbWrapper
func
(
dw
*
dbWrapper
)
toValue
(
vm
*
otto
.
Otto
)
otto
.
Value
{
value
,
_
:=
vm
.
ToValue
(
dw
)
obj
:=
value
.
Object
()
obj
.
Set
(
"getBalance"
,
dw
.
getBalance
)
obj
.
Set
(
"getNonce"
,
dw
.
getNonce
)
obj
.
Set
(
"getCode"
,
dw
.
getCode
)
obj
.
Set
(
"getState"
,
dw
.
getState
)
obj
.
Set
(
"exists"
,
dw
.
exists
)
return
value
}
// JavascriptTracer provides an implementation of Tracer that evaluates a
// Javascript function for each VM execution step.
type
JavascriptTracer
struct
{
vm
*
otto
.
Otto
// Javascript VM instance
traceobj
*
otto
.
Object
// User-supplied object to call
log
map
[
string
]
interface
{}
// (Reusable) map for the `log` arg to `step`
logvalue
otto
.
Value
// JS view of `log`
opcode
*
opCodeWrapper
// Wrapper around the opcode
opcodevalue
otto
.
Value
// JS view of 'opcode'
memory
*
memoryWrapper
// Wrapper around the VM memory
memvalue
otto
.
Value
// JS view of `memory`
stack
*
stackWrapper
// Wrapper around the VM stack
stackvalue
otto
.
Value
// JS view of `stack`
db
*
dbWrapper
// Wrapper around the VM environment
dbvalue
otto
.
Value
// JS view of `db`
err
error
// Error, if one has occurred
}
// NewJavascriptTracer instantiates a new JavascriptTracer instance.
// code specifies a Javascript snippet, which must evaluate to an expression
// returning an object with 'step' and 'result' functions.
func
NewJavascriptTracer
(
code
string
)
(
*
JavascriptTracer
,
error
)
{
vm
:=
otto
.
New
()
vm
.
Interrupt
=
make
(
chan
func
(),
1
)
// Set up builtins for this environment
vm
.
Set
(
"big"
,
&
fakeBig
{})
jstracer
,
err
:=
vm
.
Object
(
"("
+
code
+
")"
)
if
err
!=
nil
{
return
nil
,
err
}
// Check the required functions exist
step
,
err
:=
jstracer
.
Get
(
"step"
)
if
err
!=
nil
{
return
nil
,
err
}
if
!
step
.
IsFunction
()
{
return
nil
,
fmt
.
Errorf
(
"Trace object must expose a function step()"
)
}
result
,
err
:=
jstracer
.
Get
(
"result"
)
if
err
!=
nil
{
return
nil
,
err
}
if
!
result
.
IsFunction
()
{
return
nil
,
fmt
.
Errorf
(
"Trace object must expose a function result()"
)
}
// Create the persistent log object
log
:=
make
(
map
[
string
]
interface
{})
logvalue
,
_
:=
vm
.
ToValue
(
log
)
// Create persistent wrappers for memory and stack
opcode
:=
&
opCodeWrapper
{}
mem
:=
&
memoryWrapper
{}
stack
:=
&
stackWrapper
{}
db
:=
&
dbWrapper
{}
return
&
JavascriptTracer
{
vm
:
vm
,
traceobj
:
jstracer
,
log
:
log
,
logvalue
:
logvalue
,
opcode
:
opcode
,
opcodevalue
:
opcode
.
toValue
(
vm
),
memory
:
mem
,
memvalue
:
mem
.
toValue
(
vm
),
stack
:
stack
,
stackvalue
:
stack
.
toValue
(
vm
),
db
:
db
,
dbvalue
:
db
.
toValue
(
vm
),
err
:
nil
,
},
nil
}
// Stop terminates execution of any JavaScript
func
(
jst
*
JavascriptTracer
)
Stop
(
err
error
)
{
jst
.
vm
.
Interrupt
<-
func
()
{
panic
(
err
)
}
}
// callSafely executes a method on a JS object, catching any panics and
// returning them as error objects.
func
(
jst
*
JavascriptTracer
)
callSafely
(
method
string
,
argumentList
...
interface
{})
(
ret
interface
{},
err
error
)
{
defer
func
()
{
if
caught
:=
recover
();
caught
!=
nil
{
switch
caught
:=
caught
.
(
type
)
{
case
error
:
err
=
caught
case
string
:
err
=
errors
.
New
(
caught
)
case
fmt
.
Stringer
:
err
=
errors
.
New
(
caught
.
String
())
default
:
panic
(
caught
)
}
}
}()
value
,
err
:=
jst
.
traceobj
.
Call
(
method
,
argumentList
...
)
ret
,
_
=
value
.
Export
()
return
ret
,
err
}
// CaptureState implements the Tracer interface to trace a single step of VM execution
func
(
jst
*
JavascriptTracer
)
CaptureState
(
env
vm
.
Environment
,
pc
uint64
,
op
vm
.
OpCode
,
gas
,
cost
*
big
.
Int
,
memory
*
vm
.
Memory
,
stack
*
vm
.
Stack
,
contract
*
vm
.
Contract
,
depth
int
,
err
error
)
{
if
jst
.
err
==
nil
{
jst
.
opcode
.
op
=
op
jst
.
memory
.
memory
=
memory
jst
.
stack
.
stack
=
stack
jst
.
db
.
db
=
env
.
Db
()
jst
.
log
[
"pc"
]
=
pc
jst
.
log
[
"op"
]
=
jst
.
opcodevalue
jst
.
log
[
"gas"
]
=
gas
.
Int64
()
jst
.
log
[
"gasPrice"
]
=
cost
.
Int64
()
jst
.
log
[
"memory"
]
=
jst
.
memvalue
jst
.
log
[
"stack"
]
=
jst
.
stackvalue
jst
.
log
[
"depth"
]
=
depth
jst
.
log
[
"account"
]
=
contract
.
Address
()
jst
.
log
[
"err"
]
=
err
_
,
err
:=
jst
.
callSafely
(
"step"
,
jst
.
logvalue
,
jst
.
dbvalue
)
if
err
!=
nil
{
jst
.
err
=
err
}
}
}
// GetResult calls the Javascript 'result' function and returns its value, or any accumulated error
func
(
jst
*
JavascriptTracer
)
GetResult
()
(
result
interface
{},
err
error
)
{
if
jst
.
err
!=
nil
{
return
nil
,
jst
.
err
}
return
jst
.
callSafely
(
"result"
)
}
internal/ethapi/tracer_test.go
0 → 100644
View file @
2f997209
// 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
ethapi
import
(
"errors"
"math/big"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
)
type
ruleSet
struct
{}
func
(
self
*
ruleSet
)
IsHomestead
(
*
big
.
Int
)
bool
{
return
true
}
type
Env
struct
{
gasLimit
*
big
.
Int
depth
int
evm
*
vm
.
EVM
}
func
NewEnv
(
config
*
vm
.
Config
)
*
Env
{
env
:=
&
Env
{
gasLimit
:
big
.
NewInt
(
10000
),
depth
:
0
}
env
.
evm
=
vm
.
New
(
env
,
*
config
)
return
env
}
func
(
self
*
Env
)
RuleSet
()
vm
.
RuleSet
{
return
&
ruleSet
{}
}
func
(
self
*
Env
)
Vm
()
vm
.
Vm
{
return
self
.
evm
}
func
(
self
*
Env
)
Origin
()
common
.
Address
{
return
common
.
Address
{}
}
func
(
self
*
Env
)
BlockNumber
()
*
big
.
Int
{
return
big
.
NewInt
(
0
)
}
//func (self *Env) PrevHash() []byte { return self.parent }
func
(
self
*
Env
)
Coinbase
()
common
.
Address
{
return
common
.
Address
{}
}
func
(
self
*
Env
)
MakeSnapshot
()
vm
.
Database
{
return
nil
}
func
(
self
*
Env
)
SetSnapshot
(
vm
.
Database
)
{}
func
(
self
*
Env
)
Time
()
*
big
.
Int
{
return
big
.
NewInt
(
time
.
Now
()
.
Unix
())
}
func
(
self
*
Env
)
Difficulty
()
*
big
.
Int
{
return
big
.
NewInt
(
0
)
}
func
(
self
*
Env
)
Db
()
vm
.
Database
{
return
nil
}
func
(
self
*
Env
)
GasLimit
()
*
big
.
Int
{
return
self
.
gasLimit
}
func
(
self
*
Env
)
VmType
()
vm
.
Type
{
return
vm
.
StdVmTy
}
func
(
self
*
Env
)
GetHash
(
n
uint64
)
common
.
Hash
{
return
common
.
BytesToHash
(
crypto
.
Keccak256
([]
byte
(
big
.
NewInt
(
int64
(
n
))
.
String
())))
}
func
(
self
*
Env
)
AddLog
(
log
*
vm
.
Log
)
{
}
func
(
self
*
Env
)
Depth
()
int
{
return
self
.
depth
}
func
(
self
*
Env
)
SetDepth
(
i
int
)
{
self
.
depth
=
i
}
func
(
self
*
Env
)
CanTransfer
(
from
common
.
Address
,
balance
*
big
.
Int
)
bool
{
return
true
}
func
(
self
*
Env
)
Transfer
(
from
,
to
vm
.
Account
,
amount
*
big
.
Int
)
{}
func
(
self
*
Env
)
Call
(
caller
vm
.
ContractRef
,
addr
common
.
Address
,
data
[]
byte
,
gas
,
price
,
value
*
big
.
Int
)
([]
byte
,
error
)
{
return
nil
,
nil
}
func
(
self
*
Env
)
CallCode
(
caller
vm
.
ContractRef
,
addr
common
.
Address
,
data
[]
byte
,
gas
,
price
,
value
*
big
.
Int
)
([]
byte
,
error
)
{
return
nil
,
nil
}
func
(
self
*
Env
)
Create
(
caller
vm
.
ContractRef
,
data
[]
byte
,
gas
,
price
,
value
*
big
.
Int
)
([]
byte
,
common
.
Address
,
error
)
{
return
nil
,
common
.
Address
{},
nil
}
func
(
self
*
Env
)
DelegateCall
(
me
vm
.
ContractRef
,
addr
common
.
Address
,
data
[]
byte
,
gas
,
price
*
big
.
Int
)
([]
byte
,
error
)
{
return
nil
,
nil
}
type
account
struct
{}
func
(
account
)
SubBalance
(
amount
*
big
.
Int
)
{}
func
(
account
)
AddBalance
(
amount
*
big
.
Int
)
{}
func
(
account
)
SetAddress
(
common
.
Address
)
{}
func
(
account
)
Value
()
*
big
.
Int
{
return
nil
}
func
(
account
)
SetBalance
(
*
big
.
Int
)
{}
func
(
account
)
SetNonce
(
uint64
)
{}
func
(
account
)
Balance
()
*
big
.
Int
{
return
nil
}
func
(
account
)
Address
()
common
.
Address
{
return
common
.
Address
{}
}
func
(
account
)
ReturnGas
(
*
big
.
Int
,
*
big
.
Int
)
{}
func
(
account
)
SetCode
([]
byte
)
{}
func
(
account
)
ForEachStorage
(
cb
func
(
key
,
value
common
.
Hash
)
bool
)
{}
func
runTrace
(
tracer
*
JavascriptTracer
)
(
interface
{},
error
)
{
env
:=
NewEnv
(
&
vm
.
Config
{
Debug
:
true
,
Tracer
:
tracer
})
contract
:=
vm
.
NewContract
(
account
{},
account
{},
big
.
NewInt
(
0
),
env
.
GasLimit
(),
big
.
NewInt
(
1
))
contract
.
Code
=
[]
byte
{
byte
(
vm
.
PUSH1
),
0x1
,
byte
(
vm
.
PUSH1
),
0x1
,
0x0
}
_
,
err
:=
env
.
Vm
()
.
Run
(
contract
,
[]
byte
{})
if
err
!=
nil
{
return
nil
,
err
}
return
tracer
.
GetResult
()
}
func
TestTracing
(
t
*
testing
.
T
)
{
tracer
,
err
:=
NewJavascriptTracer
(
"{count: 0, step: function() { this.count += 1; }, result: function() { return this.count; }}"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
ret
,
err
:=
runTrace
(
tracer
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
value
,
ok
:=
ret
.
(
float64
)
if
!
ok
{
t
.
Errorf
(
"Expected return value to be float64, was %T"
,
ret
)
}
if
value
!=
3
{
t
.
Errorf
(
"Expected return value to be 3, got %v"
,
value
)
}
}
func
TestStack
(
t
*
testing
.
T
)
{
tracer
,
err
:=
NewJavascriptTracer
(
"{depths: [], step: function(log) { this.depths.push(log.stack.length()); }, result: function() { return this.depths; }}"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
ret
,
err
:=
runTrace
(
tracer
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
value
,
ok
:=
ret
.
([]
int
)
if
!
ok
{
t
.
Errorf
(
"Expected return value to be []int, was %T"
,
ret
)
}
if
len
(
value
)
!=
3
||
value
[
0
]
!=
0
||
value
[
1
]
!=
1
||
value
[
2
]
!=
2
{
t
.
Errorf
(
"Expected return value to be [0 1 2], got %v"
,
value
)
}
}
func
TestHalt
(
t
*
testing
.
T
)
{
timeout
:=
errors
.
New
(
"stahp"
)
tracer
,
err
:=
NewJavascriptTracer
(
"{step: function() { while(1); }, result: function() { return null; }}"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
go
func
()
{
time
.
Sleep
(
1
*
time
.
Second
)
tracer
.
Stop
(
timeout
)
}()
if
_
,
err
=
runTrace
(
tracer
);
err
!=
timeout
{
t
.
Errorf
(
"Expected timeout error, got %v"
,
err
)
}
}
func
TestHaltBetweenSteps
(
t
*
testing
.
T
)
{
tracer
,
err
:=
NewJavascriptTracer
(
"{step: function() {}, result: function() { return null; }}"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
env
:=
NewEnv
(
&
vm
.
Config
{
Debug
:
true
,
Tracer
:
tracer
})
contract
:=
vm
.
NewContract
(
&
account
{},
&
account
{},
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
big
.
NewInt
(
0
))
tracer
.
CaptureState
(
env
,
0
,
0
,
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
nil
,
nil
,
contract
,
0
,
nil
)
timeout
:=
errors
.
New
(
"stahp"
)
tracer
.
Stop
(
timeout
)
tracer
.
CaptureState
(
env
,
0
,
0
,
big
.
NewInt
(
0
),
big
.
NewInt
(
0
),
nil
,
nil
,
contract
,
0
,
nil
)
if
_
,
err
:=
tracer
.
GetResult
();
err
!=
timeout
{
t
.
Errorf
(
"Expected timeout error, got %v"
,
err
)
}
}
internal/web3ext/web3ext.go
View file @
2f997209
...
...
@@ -284,7 +284,8 @@ web3._extend({
new web3._extend.Method({
name: 'traceTransaction',
call: 'debug_traceTransaction',
params: 1
params: 2,
inputFormatter: [null, null]
})
],
properties: []
...
...
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