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
f5f906dd
Unverified
Commit
f5f906dd
authored
Jul 01, 2021
by
Martin Holst Swende
Committed by
GitHub
Jul 01, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
eth/tracers: improve tracing performance (#23016)
Improves the performance of debug.traceTransaction
parent
bbbeb7d8
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
105 additions
and
34 deletions
+105
-34
gen_structlog.go
core/vm/gen_structlog.go
+5
-14
logger.go
core/vm/logger.go
+20
-12
logger_json.go
core/vm/logger_json.go
+1
-7
tracers_test.go
eth/tracers/tracers_test.go
+78
-0
api.go
internal/ethapi/api.go
+1
-1
No files found.
core/vm/gen_structlog.go
View file @
f5f906dd
...
...
@@ -4,11 +4,11 @@ package vm
import
(
"encoding/json"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/holiman/uint256"
)
var
_
=
(
*
structLogMarshaling
)(
nil
)
...
...
@@ -22,8 +22,7 @@ func (s StructLog) MarshalJSON() ([]byte, error) {
GasCost
math
.
HexOrDecimal64
`json:"gasCost"`
Memory
hexutil
.
Bytes
`json:"memory"`
MemorySize
int
`json:"memSize"`
Stack
[]
*
math
.
HexOrDecimal256
`json:"stack"`
ReturnStack
[]
math
.
HexOrDecimal64
`json:"returnStack"`
Stack
[]
uint256
.
Int
`json:"stack"`
ReturnData
hexutil
.
Bytes
`json:"returnData"`
Storage
map
[
common
.
Hash
]
common
.
Hash
`json:"-"`
Depth
int
`json:"depth"`
...
...
@@ -39,12 +38,7 @@ func (s StructLog) MarshalJSON() ([]byte, error) {
enc
.
GasCost
=
math
.
HexOrDecimal64
(
s
.
GasCost
)
enc
.
Memory
=
s
.
Memory
enc
.
MemorySize
=
s
.
MemorySize
if
s
.
Stack
!=
nil
{
enc
.
Stack
=
make
([]
*
math
.
HexOrDecimal256
,
len
(
s
.
Stack
))
for
k
,
v
:=
range
s
.
Stack
{
enc
.
Stack
[
k
]
=
(
*
math
.
HexOrDecimal256
)(
v
)
}
}
enc
.
Stack
=
s
.
Stack
enc
.
ReturnData
=
s
.
ReturnData
enc
.
Storage
=
s
.
Storage
enc
.
Depth
=
s
.
Depth
...
...
@@ -64,7 +58,7 @@ func (s *StructLog) UnmarshalJSON(input []byte) error {
GasCost
*
math
.
HexOrDecimal64
`json:"gasCost"`
Memory
*
hexutil
.
Bytes
`json:"memory"`
MemorySize
*
int
`json:"memSize"`
Stack
[]
*
math
.
HexOrDecimal256
`json:"stack"`
Stack
[]
uint256
.
Int
`json:"stack"`
ReturnData
*
hexutil
.
Bytes
`json:"returnData"`
Storage
map
[
common
.
Hash
]
common
.
Hash
`json:"-"`
Depth
*
int
`json:"depth"`
...
...
@@ -94,10 +88,7 @@ func (s *StructLog) UnmarshalJSON(input []byte) error {
s
.
MemorySize
=
*
dec
.
MemorySize
}
if
dec
.
Stack
!=
nil
{
s
.
Stack
=
make
([]
*
big
.
Int
,
len
(
dec
.
Stack
))
for
k
,
v
:=
range
dec
.
Stack
{
s
.
Stack
[
k
]
=
(
*
big
.
Int
)(
v
)
}
s
.
Stack
=
dec
.
Stack
}
if
dec
.
ReturnData
!=
nil
{
s
.
ReturnData
=
*
dec
.
ReturnData
...
...
core/vm/logger.go
View file @
f5f906dd
...
...
@@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
)
// Storage represents a contract's storage.
...
...
@@ -66,7 +67,7 @@ type StructLog struct {
GasCost
uint64
`json:"gasCost"`
Memory
[]
byte
`json:"memory"`
MemorySize
int
`json:"memSize"`
Stack
[]
*
big
.
Int
`json:"stack"`
Stack
[]
uint256
.
Int
`json:"stack"`
ReturnData
[]
byte
`json:"returnData"`
Storage
map
[
common
.
Hash
]
common
.
Hash
`json:"-"`
Depth
int
`json:"depth"`
...
...
@@ -76,7 +77,6 @@ type StructLog struct {
// overrides for gencodec
type
structLogMarshaling
struct
{
Stack
[]
*
math
.
HexOrDecimal256
Gas
math
.
HexOrDecimal64
GasCost
math
.
HexOrDecimal64
Memory
hexutil
.
Bytes
...
...
@@ -135,6 +135,14 @@ func NewStructLogger(cfg *LogConfig) *StructLogger {
return
logger
}
// Reset clears the data held by the logger.
func
(
l
*
StructLogger
)
Reset
()
{
l
.
storage
=
make
(
map
[
common
.
Address
]
Storage
)
l
.
output
=
make
([]
byte
,
0
)
l
.
logs
=
l
.
logs
[
:
0
]
l
.
err
=
nil
}
// CaptureStart implements the Tracer interface to initialize the tracing operation.
func
(
l
*
StructLogger
)
CaptureStart
(
env
*
EVM
,
from
common
.
Address
,
to
common
.
Address
,
create
bool
,
input
[]
byte
,
gas
uint64
,
value
*
big
.
Int
)
{
}
...
...
@@ -157,16 +165,16 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
copy
(
mem
,
memory
.
Data
())
}
// Copy a snapshot of the current stack state to a new buffer
var
stck
[]
*
big
.
Int
var
stck
[]
uint256
.
Int
if
!
l
.
cfg
.
DisableStack
{
stck
=
make
([]
*
big
.
Int
,
len
(
stack
.
Data
()))
stck
=
make
([]
uint256
.
Int
,
len
(
stack
.
Data
()))
for
i
,
item
:=
range
stack
.
Data
()
{
stck
[
i
]
=
new
(
big
.
Int
)
.
Set
(
item
.
ToBig
())
stck
[
i
]
=
item
}
}
// Copy a snapshot of the current storage to a new container
var
storage
Storage
if
!
l
.
cfg
.
DisableStorage
{
if
!
l
.
cfg
.
DisableStorage
&&
(
op
==
SLOAD
||
op
==
SSTORE
)
{
// initialise new changed values storage container for this contract
// if not present.
if
l
.
storage
[
contract
.
Address
()]
==
nil
{
...
...
@@ -179,17 +187,17 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
value
=
env
.
StateDB
.
GetState
(
contract
.
Address
(),
address
)
)
l
.
storage
[
contract
.
Address
()][
address
]
=
value
}
storage
=
l
.
storage
[
contract
.
Address
()]
.
Copy
()
}
else
if
op
==
SSTORE
&&
stack
.
len
()
>=
2
{
// capture SSTORE opcodes and record the written entry in the local storage.
if
op
==
SSTORE
&&
stack
.
len
()
>=
2
{
var
(
value
=
common
.
Hash
(
stack
.
data
[
stack
.
len
()
-
2
]
.
Bytes32
())
address
=
common
.
Hash
(
stack
.
data
[
stack
.
len
()
-
1
]
.
Bytes32
())
)
l
.
storage
[
contract
.
Address
()][
address
]
=
value
}
storage
=
l
.
storage
[
contract
.
Address
()]
.
Copy
()
}
}
var
rdata
[]
byte
if
!
l
.
cfg
.
DisableReturnData
{
rdata
=
make
([]
byte
,
len
(
rData
))
...
...
@@ -238,7 +246,7 @@ func WriteTrace(writer io.Writer, logs []StructLog) {
if
len
(
log
.
Stack
)
>
0
{
fmt
.
Fprintln
(
writer
,
"Stack:"
)
for
i
:=
len
(
log
.
Stack
)
-
1
;
i
>=
0
;
i
--
{
fmt
.
Fprintf
(
writer
,
"%08d %
x
\n
"
,
len
(
log
.
Stack
)
-
i
-
1
,
math
.
PaddedBigBytes
(
log
.
Stack
[
i
],
32
))
fmt
.
Fprintf
(
writer
,
"%08d %
s
\n
"
,
len
(
log
.
Stack
)
-
i
-
1
,
log
.
Stack
[
i
]
.
Hex
(
))
}
}
if
len
(
log
.
Memory
)
>
0
{
...
...
@@ -314,7 +322,7 @@ func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64
// format stack
var
a
[]
string
for
_
,
elem
:=
range
stack
.
data
{
a
=
append
(
a
,
fmt
.
Sprintf
(
"%v"
,
elem
.
String
()
))
a
=
append
(
a
,
elem
.
Hex
(
))
}
b
:=
fmt
.
Sprintf
(
"[%v]"
,
strings
.
Join
(
a
,
","
))
fmt
.
Fprintf
(
t
.
out
,
"%10v |"
,
b
)
...
...
core/vm/logger_json.go
View file @
f5f906dd
...
...
@@ -57,7 +57,6 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint
Gas
:
gas
,
GasCost
:
cost
,
MemorySize
:
memory
.
Len
(),
Storage
:
nil
,
Depth
:
depth
,
RefundCounter
:
env
.
StateDB
.
GetRefund
(),
Err
:
err
,
...
...
@@ -66,12 +65,7 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint
log
.
Memory
=
memory
.
Data
()
}
if
!
l
.
cfg
.
DisableStack
{
//TODO(@holiman) improve this
logstack
:=
make
([]
*
big
.
Int
,
len
(
stack
.
Data
()))
for
i
,
item
:=
range
stack
.
Data
()
{
logstack
[
i
]
=
item
.
ToBig
()
}
log
.
Stack
=
logstack
log
.
Stack
=
stack
.
data
}
if
!
l
.
cfg
.
DisableReturnData
{
log
.
ReturnData
=
rData
...
...
eth/tracers/tracers_test.go
View file @
f5f906dd
...
...
@@ -300,3 +300,81 @@ func jsonEqual(x, y interface{}) bool {
}
return
reflect
.
DeepEqual
(
xTrace
,
yTrace
)
}
func
BenchmarkTransactionTrace
(
b
*
testing
.
B
)
{
key
,
_
:=
crypto
.
HexToECDSA
(
"b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
)
from
:=
crypto
.
PubkeyToAddress
(
key
.
PublicKey
)
gas
:=
uint64
(
1000000
)
// 1M gas
to
:=
common
.
HexToAddress
(
"0x00000000000000000000000000000000deadbeef"
)
signer
:=
types
.
LatestSignerForChainID
(
big
.
NewInt
(
1337
))
tx
,
err
:=
types
.
SignNewTx
(
key
,
signer
,
&
types
.
LegacyTx
{
Nonce
:
1
,
GasPrice
:
big
.
NewInt
(
500
),
Gas
:
gas
,
To
:
&
to
,
})
if
err
!=
nil
{
b
.
Fatal
(
err
)
}
txContext
:=
vm
.
TxContext
{
Origin
:
from
,
GasPrice
:
tx
.
GasPrice
(),
}
context
:=
vm
.
BlockContext
{
CanTransfer
:
core
.
CanTransfer
,
Transfer
:
core
.
Transfer
,
Coinbase
:
common
.
Address
{},
BlockNumber
:
new
(
big
.
Int
)
.
SetUint64
(
uint64
(
5
)),
Time
:
new
(
big
.
Int
)
.
SetUint64
(
uint64
(
5
)),
Difficulty
:
big
.
NewInt
(
0xffffffff
),
GasLimit
:
gas
,
}
alloc
:=
core
.
GenesisAlloc
{}
// The code pushes 'deadbeef' into memory, then the other params, and calls CREATE2, then returns
// the address
loop
:=
[]
byte
{
byte
(
vm
.
JUMPDEST
),
// [ count ]
byte
(
vm
.
PUSH1
),
0
,
// jumpdestination
byte
(
vm
.
JUMP
),
}
alloc
[
common
.
HexToAddress
(
"0x00000000000000000000000000000000deadbeef"
)]
=
core
.
GenesisAccount
{
Nonce
:
1
,
Code
:
loop
,
Balance
:
big
.
NewInt
(
1
),
}
alloc
[
from
]
=
core
.
GenesisAccount
{
Nonce
:
1
,
Code
:
[]
byte
{},
Balance
:
big
.
NewInt
(
500000000000000
),
}
_
,
statedb
:=
tests
.
MakePreState
(
rawdb
.
NewMemoryDatabase
(),
alloc
,
false
)
// Create the tracer, the EVM environment and run it
tracer
:=
vm
.
NewStructLogger
(
&
vm
.
LogConfig
{
Debug
:
false
,
//DisableStorage: true,
//DisableMemory: true,
//DisableReturnData: true,
})
evm
:=
vm
.
NewEVM
(
context
,
txContext
,
statedb
,
params
.
AllEthashProtocolChanges
,
vm
.
Config
{
Debug
:
true
,
Tracer
:
tracer
})
msg
,
err
:=
tx
.
AsMessage
(
signer
,
nil
)
if
err
!=
nil
{
b
.
Fatalf
(
"failed to prepare transaction for tracing: %v"
,
err
)
}
b
.
ResetTimer
()
b
.
ReportAllocs
()
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
snap
:=
statedb
.
Snapshot
()
st
:=
core
.
NewStateTransition
(
evm
,
msg
,
new
(
core
.
GasPool
)
.
AddGas
(
tx
.
Gas
()))
_
,
err
=
st
.
TransitionDb
()
if
err
!=
nil
{
b
.
Fatal
(
err
)
}
statedb
.
RevertToSnapshot
(
snap
)
if
have
,
want
:=
len
(
tracer
.
StructLogs
()),
244752
;
have
!=
want
{
b
.
Fatalf
(
"trace wrong, want %d steps, have %d"
,
want
,
have
)
}
tracer
.
Reset
()
}
}
internal/ethapi/api.go
View file @
f5f906dd
...
...
@@ -1117,7 +1117,7 @@ func FormatLogs(logs []vm.StructLog) []StructLogRes {
if
trace
.
Stack
!=
nil
{
stack
:=
make
([]
string
,
len
(
trace
.
Stack
))
for
i
,
stackValue
:=
range
trace
.
Stack
{
stack
[
i
]
=
fmt
.
Sprintf
(
"%x"
,
math
.
PaddedBigBytes
(
stackValue
,
32
)
)
stack
[
i
]
=
stackValue
.
Hex
(
)
}
formatted
[
index
]
.
Stack
=
&
stack
}
...
...
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