|
|
@ -42,7 +42,6 @@ func (s Storage) Copy() Storage { |
|
|
|
for key, value := range s { |
|
|
|
for key, value := range s { |
|
|
|
cpy[key] = value |
|
|
|
cpy[key] = value |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return cpy |
|
|
|
return cpy |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -118,16 +117,16 @@ type Tracer interface { |
|
|
|
type StructLogger struct { |
|
|
|
type StructLogger struct { |
|
|
|
cfg LogConfig |
|
|
|
cfg LogConfig |
|
|
|
|
|
|
|
|
|
|
|
logs []StructLog |
|
|
|
storage map[common.Address]Storage |
|
|
|
changedValues map[common.Address]Storage |
|
|
|
logs []StructLog |
|
|
|
output []byte |
|
|
|
output []byte |
|
|
|
err error |
|
|
|
err error |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// NewStructLogger returns a new logger
|
|
|
|
// NewStructLogger returns a new logger
|
|
|
|
func NewStructLogger(cfg *LogConfig) *StructLogger { |
|
|
|
func NewStructLogger(cfg *LogConfig) *StructLogger { |
|
|
|
logger := &StructLogger{ |
|
|
|
logger := &StructLogger{ |
|
|
|
changedValues: make(map[common.Address]Storage), |
|
|
|
storage: make(map[common.Address]Storage), |
|
|
|
} |
|
|
|
} |
|
|
|
if cfg != nil { |
|
|
|
if cfg != nil { |
|
|
|
logger.cfg = *cfg |
|
|
|
logger.cfg = *cfg |
|
|
@ -142,28 +141,12 @@ func (l *StructLogger) CaptureStart(from common.Address, to common.Address, crea |
|
|
|
|
|
|
|
|
|
|
|
// CaptureState logs a new structured log message and pushes it out to the environment
|
|
|
|
// CaptureState logs a new structured log message and pushes it out to the environment
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// CaptureState also tracks SSTORE ops to track dirty values.
|
|
|
|
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
|
|
|
|
func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rStack *ReturnStack, contract *Contract, depth int, err error) error { |
|
|
|
func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rStack *ReturnStack, contract *Contract, depth int, err error) error { |
|
|
|
// check if already accumulated the specified number of logs
|
|
|
|
// check if already accumulated the specified number of logs
|
|
|
|
if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) { |
|
|
|
if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) { |
|
|
|
return errTraceLimitReached |
|
|
|
return errTraceLimitReached |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// initialise new changed values storage container for this contract
|
|
|
|
|
|
|
|
// if not present.
|
|
|
|
|
|
|
|
if l.changedValues[contract.Address()] == nil { |
|
|
|
|
|
|
|
l.changedValues[contract.Address()] = make(Storage) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// capture SSTORE opcodes and determine the changed value and store
|
|
|
|
|
|
|
|
// it in the local storage container.
|
|
|
|
|
|
|
|
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.changedValues[contract.Address()][address] = value |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Copy a snapshot of the current memory state to a new buffer
|
|
|
|
// Copy a snapshot of the current memory state to a new buffer
|
|
|
|
var mem []byte |
|
|
|
var mem []byte |
|
|
|
if !l.cfg.DisableMemory { |
|
|
|
if !l.cfg.DisableMemory { |
|
|
@ -178,19 +161,39 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui |
|
|
|
stck[i] = new(big.Int).Set(item.ToBig()) |
|
|
|
stck[i] = new(big.Int).Set(item.ToBig()) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// Copy a snapshot of the current storage to a new container
|
|
|
|
|
|
|
|
var storage Storage |
|
|
|
|
|
|
|
if !l.cfg.DisableStorage { |
|
|
|
|
|
|
|
storage = l.changedValues[contract.Address()].Copy() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
var rstack []uint64 |
|
|
|
var rstack []uint64 |
|
|
|
if !l.cfg.DisableStack && rStack != nil { |
|
|
|
if !l.cfg.DisableStack && rStack != nil { |
|
|
|
rstck := make([]uint64, len(rStack.data)) |
|
|
|
rstck := make([]uint64, len(rStack.data)) |
|
|
|
copy(rstck, rStack.data) |
|
|
|
copy(rstck, rStack.data) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Copy a snapshot of the current storage to a new container
|
|
|
|
|
|
|
|
var storage Storage |
|
|
|
|
|
|
|
if !l.cfg.DisableStorage { |
|
|
|
|
|
|
|
// initialise new changed values storage container for this contract
|
|
|
|
|
|
|
|
// if not present.
|
|
|
|
|
|
|
|
if l.storage[contract.Address()] == nil { |
|
|
|
|
|
|
|
l.storage[contract.Address()] = make(Storage) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// capture SLOAD opcodes and record the read entry in the local storage
|
|
|
|
|
|
|
|
if op == SLOAD && stack.len() >= 1 { |
|
|
|
|
|
|
|
var ( |
|
|
|
|
|
|
|
address = common.Hash(stack.data[stack.len()-1].Bytes32()) |
|
|
|
|
|
|
|
value = env.StateDB.GetState(contract.Address(), address) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
l.storage[contract.Address()][address] = value |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// 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() |
|
|
|
|
|
|
|
} |
|
|
|
// create a new snapshot of the EVM.
|
|
|
|
// create a new snapshot of the EVM.
|
|
|
|
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rstack, storage, depth, env.StateDB.GetRefund(), err} |
|
|
|
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rstack, storage, depth, env.StateDB.GetRefund(), err} |
|
|
|
|
|
|
|
|
|
|
|
l.logs = append(l.logs, log) |
|
|
|
l.logs = append(l.logs, log) |
|
|
|
return nil |
|
|
|
return nil |
|
|
|
} |
|
|
|
} |
|
|
|