Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade trace to decrease GC pressure. #92

Merged
merged 10 commits into from
May 18, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 52 additions & 11 deletions core/types/l2trace.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package types

import (
"runtime"
"sync"

"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/common/hexutil"
)
Expand Down Expand Up @@ -30,17 +33,17 @@ type ExecutionResult struct {
// 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 uint64 `json:"gas"`
GasCost uint64 `json:"gasCost"`
Depth int `json:"depth"`
Error string `json:"error,omitempty"`
Stack *[]string `json:"stack,omitempty"`
Memory *[]string `json:"memory,omitempty"`
Storage *map[string]string `json:"storage,omitempty"`
RefundCounter uint64 `json:"refund,omitempty"`
ExtraData *ExtraData `json:"extraData,omitempty"`
Pc uint64 `json:"pc"`
Op string `json:"op"`
Gas uint64 `json:"gas"`
GasCost uint64 `json:"gasCost"`
Depth int `json:"depth"`
Error string `json:"error,omitempty"`
Stack []string `json:"stack,omitempty"`
Memory []string `json:"memory,omitempty"`
Storage map[string]string `json:"storage,omitempty"`
RefundCounter uint64 `json:"refund,omitempty"`
ExtraData *ExtraData `json:"extraData,omitempty"`
}

type ExtraData struct {
Expand All @@ -55,6 +58,18 @@ type ExtraData struct {
ProofList []*AccountProofWrapper `json:"proofList,omitempty"`
}

var (
proofPool = sync.Pool{
New: func() interface{} {
return &AccountProofWrapper{
Storage: &StorageProofWrapper{
Proof: make([]string, 0),
},
}
},
}
)

type AccountProofWrapper struct {
Address common.Address `json:"address"`
Nonce uint64 `json:"nonce"`
Expand All @@ -64,6 +79,26 @@ type AccountProofWrapper struct {
Storage *StorageProofWrapper `json:"storage,omitempty"` // StorageProofWrapper can be empty if irrelated to storage operation
}

func NewAccountProofWrapper(addr common.Address, nonce uint64, balance *hexutil.Big, codeHash common.Hash) *AccountProofWrapper {
proof := proofPool.Get().(*AccountProofWrapper)
proof.Address, proof.Nonce, proof.Balance, proof.CodeHash = addr, nonce, balance, codeHash
runtime.SetFinalizer(proof, func(proof *AccountProofWrapper) {
proof.clean()
})
return proof
}

func (a *AccountProofWrapper) clean() {
a.Balance = nil
a.Nonce = 0
if a.Proof != nil {
a.Proof = a.Proof[:0]
}
if a.Storage != nil {
a.Storage.clean()
}
}

// while key & value can also be retrieved from StructLogRes.Storage,
// we still stored in here for roller's processing convenience.
type StorageProofWrapper struct {
Expand All @@ -72,6 +107,12 @@ type StorageProofWrapper struct {
Proof []string `json:"proof,omitempty"`
}

func (s *StorageProofWrapper) clean() {
if s.Proof != nil {
s.Proof = s.Proof[:0]
}
}

// NewExtraData create, init and return ExtraData
func NewExtraData() *ExtraData {
return &ExtraData{
Expand Down
44 changes: 32 additions & 12 deletions core/vm/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -441,39 +441,59 @@ func (t *mdLogger) CaptureEnter(typ OpCode, from common.Address, to common.Addre

func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {}

var (
formatPool = sync.Pool{
New: func() interface{} {
return make([]types.StructLogRes, 0, 128)
},
}
)

// FormatLogs formats EVM returned structured logs for json output
func FormatLogs(logs []StructLog) []types.StructLogRes {
formatted := make([]types.StructLogRes, len(logs))
formatted := formatPool.Get().([]types.StructLogRes)
runtime.SetFinalizer(&formatted, func(format *[]types.StructLogRes) {
for _, res := range *format {
res.ExtraData = nil
res.Storage = nil
res.Stack = res.Stack[:0]
res.Memory = res.Memory[:0]
}
formatPool.Put(*format)
})

for index, trace := range logs {
formatted[index] = types.StructLogRes{
formatted = append(formatted, types.StructLogRes{
Pc: trace.Pc,
Op: trace.Op.String(),
Gas: trace.Gas,
GasCost: trace.GasCost,
Depth: trace.Depth,
RefundCounter: trace.RefundCounter,
Error: trace.ErrorString(),
}
})
if len(trace.Stack) != 0 {
stack := make([]string, len(trace.Stack))
for i, stackValue := range trace.Stack {
stack[i] = stackValue.Hex()
if formatted[index].Stack == nil {
formatted[index].Stack = make([]string, 0, len(trace.Stack))
}
for _, stackValue := range trace.Stack {
formatted[index].Stack = append(formatted[index].Stack, stackValue.Hex())
}
formatted[index].Stack = &stack
}
if trace.Memory.Len() != 0 {
memory := make([]string, 0, (trace.Memory.Len()+31)/32)
if formatted[index].Memory == nil {
formatted[index].Memory = make([]string, 0, (trace.Memory.Len()+31)/32)
}
for i := 0; i+32 <= trace.Memory.Len(); i += 32 {
memory = append(memory, fmt.Sprintf("%x", trace.Memory.Bytes()[i:i+32]))
formatted[index].Memory = append(formatted[index].Memory, common.Bytes2Hex(trace.Memory.Bytes()[i:i+32]))
}
formatted[index].Memory = &memory
}
if len(trace.Storage) != 0 {
storage := make(map[string]string)
for i, storageValue := range trace.Storage {
storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue)
storage[i.Hex()] = storageValue.Hex()
}
formatted[index].Storage = &storage
formatted[index].Storage = storage
}
if trace.ExtraData != nil {
formatted[index].ExtraData = trace.ExtraData.SealExtraData()
Expand Down
48 changes: 24 additions & 24 deletions core/vm/logger_trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,15 @@ func getWrappedProofForAddr(l *StructLogger, address common.Address) (*types.Acc
if err != nil {
return nil, err
}

return &types.AccountProofWrapper{
Address: address,
Nonce: l.env.StateDB.GetNonce(address),
Balance: (*hexutil.Big)(l.env.StateDB.GetBalance(address)),
CodeHash: l.env.StateDB.GetCodeHash(address),
Proof: encodeProof(proof),
}, nil
accountProof := types.NewAccountProofWrapper(
address,
l.env.StateDB.GetNonce(address),
(*hexutil.Big)(l.env.StateDB.GetBalance(address)),
l.env.StateDB.GetCodeHash(address),
)
encodeProof(&accountProof.Proof, proof)
mask-pp marked this conversation as resolved.
Show resolved Hide resolved

return accountProof, nil
}

func getWrappedProofForStorage(l *StructLogger, address common.Address, key common.Hash) (*types.AccountProofWrapper, error) {
Expand All @@ -147,26 +148,25 @@ func getWrappedProofForStorage(l *StructLogger, address common.Address, key comm
return nil, err
}

return &types.AccountProofWrapper{
Address: address,
Nonce: l.env.StateDB.GetNonce(address),
Balance: (*hexutil.Big)(l.env.StateDB.GetBalance(address)),
CodeHash: l.env.StateDB.GetCodeHash(address),
Proof: encodeProof(proof),
Storage: &types.StorageProofWrapper{
Key: key.String(),
Value: l.env.StateDB.GetState(address, key).String(),
Proof: encodeProof(storageProof),
},
}, nil
accountProof := types.NewAccountProofWrapper(
address,
l.env.StateDB.GetNonce(address),
(*hexutil.Big)(l.env.StateDB.GetBalance(address)),
l.env.StateDB.GetCodeHash(address),
)
encodeProof(&accountProof.Proof, proof)
storage := accountProof.Storage
storage.Key, storage.Value = key.String(), l.env.StateDB.GetState(address, key).String()
encodeProof(&storage.Proof, storageProof)

return accountProof, nil
}

func encodeProof(proof [][]byte) (res []string) {
func encodeProof(res *[]string, proof [][]byte) {
if len(proof) == 0 {
return nil
return
}
for _, node := range proof {
res = append(res, hexutil.Encode(node))
*res = append(*res, hexutil.Encode(node))
}
return
}