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

feat: fix oom bug #284

Merged
merged 6 commits into from
Apr 19, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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
37 changes: 11 additions & 26 deletions core/types/l2trace.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,12 @@ package types
import (
"encoding/json"
"math/big"
"runtime"
"sync"

"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/common/hexutil"
"github.com/scroll-tech/go-ethereum/params"
)

var (
loggerResPool = sync.Pool{
New: func() interface{} {
// init arrays here; other types are inited with default values
return &StructLogRes{
Stack: []string{},
Memory: []string{},
}
},
}
)

// BlockTrace contains block execution traces and results required for rollers.
type BlockTrace struct {
ChainID uint64 `json:"chainID"`
Expand Down Expand Up @@ -97,22 +83,21 @@ type StructLogRes struct {
ExtraData *ExtraData `json:"extraData,omitempty"`
}

// Basic StructLogRes skeleton, Stack&Memory&Storage&ExtraData are separated from it for GC optimization;
// NewStructLogResBasic Basic StructLogRes skeleton, Stack&Memory&Storage&ExtraData are separated from it for GC optimization;
// still need to fill in with Stack&Memory&Storage&ExtraData
func NewStructLogResBasic(pc uint64, op string, gas, gasCost uint64, depth int, refundCounter uint64, err error) *StructLogRes {
logRes := loggerResPool.Get().(*StructLogRes)
logRes.Pc, logRes.Op, logRes.Gas, logRes.GasCost, logRes.Depth, logRes.RefundCounter = pc, op, gas, gasCost, depth, refundCounter
logRes := &StructLogRes{
Pc: pc,
Op: op,
Gas: gas,
GasCost: gasCost,
Depth: depth,
RefundCounter: refundCounter,
}

if err != nil {
logRes.Error = err.Error()
}
runtime.SetFinalizer(logRes, func(logRes *StructLogRes) {
logRes.Stack = logRes.Stack[:0]
logRes.Memory = logRes.Memory[:0]
logRes.Storage = nil
logRes.ExtraData = nil
logRes.Error = ""
loggerResPool.Put(logRes)
})
return logRes
}

Expand Down Expand Up @@ -151,7 +136,7 @@ type AccountWrapper struct {
Storage *StorageWrapper `json:"storage,omitempty"` // StorageWrapper can be empty if irrelated to storage operation
}

// while key & value can also be retrieved from StructLogRes.Storage,
// StorageWrapper while key & value can also be retrieved from StructLogRes.Storage,
// we still stored in here for roller's processing convenience.
type StorageWrapper struct {
Key string `json:"key,omitempty"`
Expand Down
2 changes: 1 addition & 1 deletion core/vm/gen_structlog.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 21 additions & 33 deletions core/vm/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ import (
"fmt"
"io"
"math/big"
"runtime"
"strings"
"sync"
"time"

"github.com/holiman/uint256"
Expand Down Expand Up @@ -81,26 +79,15 @@ type StructLog struct {
Err error `json:"-"`
}

var (
loggerPool = sync.Pool{
New: func() interface{} {
return &StructLog{
// init arrays here; other types are inited with default values
Stack: make([]uint256.Int, 0),
}
},
}
)

func NewStructlog(pc uint64, op OpCode, gas, cost uint64, depth int, err error) *StructLog {
structlog := loggerPool.Get().(*StructLog)
structlog.Pc, structlog.Op, structlog.Gas, structlog.GasCost, structlog.Depth, structlog.Err = pc, op, gas, cost, depth, err

runtime.SetFinalizer(structlog, func(logger *StructLog) {
logger.clean()
loggerPool.Put(logger)
})
return structlog
return &StructLog{
Pc: pc,
Op: op,
Gas: gas,
GasCost: cost,
Depth: depth,
Err: err,
}
}

func (s *StructLog) clean() {
Expand Down Expand Up @@ -185,6 +172,7 @@ func NewStructLogger(cfg *LogConfig) *StructLogger {
if cfg != nil {
logger.cfg = *cfg
}

return logger
}

Expand Down Expand Up @@ -225,20 +213,20 @@ func (l *StructLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scop
stack := scope.Stack
contract := scope.Contract
// create a struct log.
structlog := NewStructlog(pc, op, gas, cost, depth, opErr)
structLog := NewStructlog(pc, op, gas, cost, depth, opErr)

// check if already accumulated the specified number of logs
if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) {
return
}
// Copy a snapshot of the current memory state to a new buffer
if l.cfg.EnableMemory {
structlog.Memory.Write(memory.Data())
structlog.MemorySize = memory.Len()
structLog.Memory.Write(memory.Data())
structLog.MemorySize = memory.Len()
}
// Copy a snapshot of the current stack state to a new buffer
if !l.cfg.DisableStack {
structlog.Stack = append(structlog.Stack, stack.Data()...)
structLog.Stack = append(structLog.Stack, stack.Data()...)
}
var (
recordStorageDetail bool
Expand All @@ -262,33 +250,33 @@ func (l *StructLogger) CaptureState(pc uint64, op OpCode, gas, cost uint64, scop
l.storage[contractAddress] = make(Storage)
}
l.storage[contractAddress][storageKey] = storageValue
structlog.Storage = l.storage[contractAddress].Copy()
structLog.Storage = l.storage[contractAddress].Copy()

if err := traceStorage(l, scope, structlog.getOrInitExtraData()); err != nil {
if err := traceStorage(l, scope, structLog.getOrInitExtraData()); err != nil {
log.Error("Failed to trace data", "opcode", op.String(), "err", err)
}
}
if l.cfg.EnableReturnData {
structlog.ReturnData.Write(rData)
structLog.ReturnData.Write(rData)
}
execFuncList, ok := OpcodeExecs[op]
if ok {
// execute trace func list.
for _, exec := range execFuncList {
if err := exec(l, scope, structlog.getOrInitExtraData()); err != nil {
if err := exec(l, scope, structLog.getOrInitExtraData()); err != nil {
log.Error("Failed to trace data", "opcode", op.String(), "err", err)
}
}
}
// for each "calling" op, pick the caller's state
switch op {
case CALL, CALLCODE, STATICCALL, DELEGATECALL, CREATE, CREATE2:
extraData := structlog.getOrInitExtraData()
extraData := structLog.getOrInitExtraData()
extraData.Caller = append(extraData.Caller, getWrappedAccountForAddr(l, scope.Contract.Address()))
}

structlog.RefundCounter = l.env.StateDB.GetRefund()
l.logs = append(l.logs, structlog)
structLog.RefundCounter = l.env.StateDB.GetRefund()
l.logs = append(l.logs, structLog)
}

func (l *StructLogger) CaptureStateAfter(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
Expand Down Expand Up @@ -335,7 +323,7 @@ func (l *StructLogger) CaptureEnter(typ OpCode, from common.Address, to common.A
}
}

// in CaptureExit phase, a CREATE has its target address's code being set and queryable
// CaptureExit phase, a CREATE has its target address's code being set and queryable
func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {
stackH := len(l.callStackLogInd)
if stackH == 0 {
Expand Down