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
a8fd0de0
Commit
a8fd0de0
authored
Feb 03, 2016
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2156 from ppratscher/add_replay_tx
core/vm, rpc/api: added debug_replayTransaction RPC call
parents
2e2f093e
15780ead
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
147 additions
and
1 deletion
+147
-1
common.go
core/vm/common.go
+2
-0
vm.go
core/vm/vm.go
+1
-1
api.go
eth/api.go
+139
-0
javascript.go
rpc/javascript.go
+5
-0
No files found.
core/vm/common.go
View file @
a8fd0de0
...
@@ -28,6 +28,8 @@ import (
...
@@ -28,6 +28,8 @@ import (
// Global Debug flag indicating Debug VM (full logging)
// Global Debug flag indicating Debug VM (full logging)
var
Debug
bool
var
Debug
bool
var
GenerateStructLogs
bool
=
false
// Type is the VM type accepted by **NewVm**
// Type is the VM type accepted by **NewVm**
type
Type
byte
type
Type
byte
...
...
core/vm/vm.go
View file @
a8fd0de0
...
@@ -367,7 +367,7 @@ func (self *Vm) RunPrecompiled(p *PrecompiledAccount, input []byte, contract *Co
...
@@ -367,7 +367,7 @@ func (self *Vm) RunPrecompiled(p *PrecompiledAccount, input []byte, contract *Co
// log emits a log event to the environment for each opcode encountered. This is not to be confused with the
// log emits a log event to the environment for each opcode encountered. This is not to be confused with the
// LOG* opcode.
// LOG* opcode.
func
(
self
*
Vm
)
log
(
pc
uint64
,
op
OpCode
,
gas
,
cost
*
big
.
Int
,
memory
*
Memory
,
stack
*
stack
,
contract
*
Contract
,
err
error
)
{
func
(
self
*
Vm
)
log
(
pc
uint64
,
op
OpCode
,
gas
,
cost
*
big
.
Int
,
memory
*
Memory
,
stack
*
stack
,
contract
*
Contract
,
err
error
)
{
if
Debug
{
if
Debug
||
GenerateStructLogs
{
mem
:=
make
([]
byte
,
len
(
memory
.
Data
()))
mem
:=
make
([]
byte
,
len
(
memory
.
Data
()))
copy
(
mem
,
memory
.
Data
())
copy
(
mem
,
memory
.
Data
())
...
...
eth/api.go
View file @
a8fd0de0
...
@@ -1501,6 +1501,145 @@ func (api *PrivateDebugAPI) SetHead(number uint64) {
...
@@ -1501,6 +1501,145 @@ func (api *PrivateDebugAPI) SetHead(number uint64) {
api
.
eth
.
BlockChain
()
.
SetHead
(
number
)
api
.
eth
.
BlockChain
()
.
SetHead
(
number
)
}
}
// StructLogRes stores a structured log emitted by the evm while replaying a
// transaction in debug mode
type
structLogRes
struct
{
Pc
uint64
`json:"pc"`
Op
string
`json:"op"`
Gas
*
big
.
Int
`json:"gas"`
GasCost
*
big
.
Int
`json:"gasCost"`
Error
error
`json:"error"`
Stack
[]
string
`json:"stack"`
Memory
map
[
string
]
string
`json:"memory"`
Storage
map
[
string
]
string
`json:"storage"`
}
// TransactionExecutionRes groups all structured logs emitted by the evm
// while replaying a transaction in debug mode as well as the amount of
// gas used and the return value
type
TransactionExecutionResult
struct
{
Gas
*
big
.
Int
`json:"gas"`
ReturnValue
string
`json:"returnValue"`
StructLogs
[]
structLogRes
`json:"structLogs"`
}
func
(
s
*
PrivateDebugAPI
)
doReplayTransaction
(
txHash
common
.
Hash
)
([]
vm
.
StructLog
,
[]
byte
,
*
big
.
Int
,
error
)
{
// Retrieve the tx from the chain
tx
,
_
,
blockIndex
,
_
:=
core
.
GetTransaction
(
s
.
eth
.
ChainDb
(),
txHash
)
if
tx
==
nil
{
return
nil
,
nil
,
nil
,
fmt
.
Errorf
(
"Transaction not found"
)
}
block
:=
s
.
eth
.
BlockChain
()
.
GetBlockByNumber
(
blockIndex
-
1
)
if
block
==
nil
{
return
nil
,
nil
,
nil
,
fmt
.
Errorf
(
"Unable to retrieve prior block"
)
}
// Create the state database
stateDb
,
err
:=
state
.
New
(
block
.
Root
(),
s
.
eth
.
ChainDb
())
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
txFrom
,
err
:=
tx
.
From
()
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
fmt
.
Errorf
(
"Unable to create transaction sender"
)
}
from
:=
stateDb
.
GetOrNewStateObject
(
txFrom
)
msg
:=
callmsg
{
from
:
from
,
to
:
tx
.
To
(),
gas
:
tx
.
Gas
(),
gasPrice
:
tx
.
GasPrice
(),
value
:
tx
.
Value
(),
data
:
tx
.
Data
(),
}
vmenv
:=
core
.
NewEnv
(
stateDb
,
s
.
eth
.
BlockChain
(),
msg
,
block
.
Header
())
gp
:=
new
(
core
.
GasPool
)
.
AddGas
(
block
.
GasLimit
())
vm
.
GenerateStructLogs
=
true
defer
func
()
{
vm
.
GenerateStructLogs
=
false
}()
ret
,
gas
,
err
:=
core
.
ApplyMessage
(
vmenv
,
msg
,
gp
)
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
fmt
.
Errorf
(
"Error executing transaction %v"
,
err
)
}
return
vmenv
.
StructLogs
(),
ret
,
gas
,
nil
}
// Executes a transaction and returns the structured logs of the evm
// gathered during the execution
func
(
s
*
PrivateDebugAPI
)
ReplayTransaction
(
txHash
common
.
Hash
,
stackDepth
int
,
memorySize
int
,
storageSize
int
)
(
*
TransactionExecutionResult
,
error
)
{
structLogs
,
ret
,
gas
,
err
:=
s
.
doReplayTransaction
(
txHash
)
if
err
!=
nil
{
return
nil
,
err
}
res
:=
TransactionExecutionResult
{
Gas
:
gas
,
ReturnValue
:
fmt
.
Sprintf
(
"%x"
,
ret
),
StructLogs
:
make
([]
structLogRes
,
len
(
structLogs
)),
}
for
index
,
trace
:=
range
structLogs
{
stackLength
:=
len
(
trace
.
Stack
)
// Return full stack by default
if
stackDepth
!=
-
1
&&
stackDepth
<
stackLength
{
stackLength
=
stackDepth
}
res
.
StructLogs
[
index
]
=
structLogRes
{
Pc
:
trace
.
Pc
,
Op
:
trace
.
Op
.
String
(),
Gas
:
trace
.
Gas
,
GasCost
:
trace
.
GasCost
,
Error
:
trace
.
Err
,
Stack
:
make
([]
string
,
stackLength
),
Memory
:
make
(
map
[
string
]
string
),
Storage
:
make
(
map
[
string
]
string
),
}
for
i
:=
0
;
i
<
stackLength
;
i
++
{
res
.
StructLogs
[
index
]
.
Stack
[
i
]
=
fmt
.
Sprintf
(
"%x"
,
common
.
LeftPadBytes
(
trace
.
Stack
[
i
]
.
Bytes
(),
32
))
}
addr
:=
0
memorySizeLocal
:=
memorySize
// Return full memory by default
if
memorySize
==
-
1
{
memorySizeLocal
=
len
(
trace
.
Memory
)
}
for
i
:=
0
;
i
+
16
<=
len
(
trace
.
Memory
)
&&
addr
<
memorySizeLocal
;
i
+=
16
{
res
.
StructLogs
[
index
]
.
Memory
[
fmt
.
Sprintf
(
"%04d"
,
addr
*
16
)]
=
fmt
.
Sprintf
(
"%x"
,
trace
.
Memory
[
i
:
i
+
16
])
addr
++
}
storageLength
:=
len
(
trace
.
Stack
)
if
storageSize
!=
-
1
&&
storageSize
<
storageLength
{
storageLength
=
storageSize
}
i
:=
0
for
storageIndex
,
storageValue
:=
range
trace
.
Storage
{
if
i
>=
storageLength
{
break
}
res
.
StructLogs
[
index
]
.
Storage
[
fmt
.
Sprintf
(
"%x"
,
storageIndex
)]
=
fmt
.
Sprintf
(
"%x"
,
storageValue
)
i
++
}
}
return
&
res
,
nil
}
// PublicNetAPI offers network related RPC methods
// PublicNetAPI offers network related RPC methods
type
PublicNetAPI
struct
{
type
PublicNetAPI
struct
{
net
*
p2p
.
Server
net
*
p2p
.
Server
...
...
rpc/javascript.go
View file @
a8fd0de0
...
@@ -407,6 +407,11 @@ web3._extend({
...
@@ -407,6 +407,11 @@ web3._extend({
call: 'debug_writeMemProfile',
call: 'debug_writeMemProfile',
params: 1
params: 1
}),
}),
new web3._extend.Method({
name: 'replayTransaction',
call: 'debug_replayTransaction',
params: 4
})
],
],
properties:
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