core, eth, internal: include read storage entries in structlog output (#21204)
* core, eth, internal: extend structLog tracer * core/vm, internal: add storage view * core, internal: add slots to storage directly * core: remove useless * core: address martin's comment * core/vm: fix tests
This commit is contained in:
parent
e9ba536d85
commit
4a19c0e7b8
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,11 +62,11 @@ func TestStoreCapture(t *testing.T) {
|
||||||
stack.push(uint256.NewInt())
|
stack.push(uint256.NewInt())
|
||||||
var index common.Hash
|
var index common.Hash
|
||||||
logger.CaptureState(env, 0, SSTORE, 0, 0, mem, stack, rstack, contract, 0, nil)
|
logger.CaptureState(env, 0, SSTORE, 0, 0, mem, stack, rstack, contract, 0, nil)
|
||||||
if len(logger.changedValues[contract.Address()]) == 0 {
|
if len(logger.storage[contract.Address()]) == 0 {
|
||||||
t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(), len(logger.changedValues[contract.Address()]))
|
t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(), len(logger.storage[contract.Address()]))
|
||||||
}
|
}
|
||||||
exp := common.BigToHash(big.NewInt(1))
|
exp := common.BigToHash(big.NewInt(1))
|
||||||
if logger.changedValues[contract.Address()][index] != exp {
|
if logger.storage[contract.Address()][index] != exp {
|
||||||
t.Errorf("expected %x, got %x", exp, logger.changedValues[contract.Address()][index])
|
t.Errorf("expected %x, got %x", exp, logger.storage[contract.Address()][index])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -387,7 +387,7 @@ func (f *TxFetcher) loop() {
|
||||||
if announces := f.announces[ann.origin]; announces != nil {
|
if announces := f.announces[ann.origin]; announces != nil {
|
||||||
announces[hash] = struct{}{}
|
announces[hash] = struct{}{}
|
||||||
} else {
|
} else {
|
||||||
f.announces[ann.origin] = map[common.Hash]struct{}{hash: struct{}{}}
|
f.announces[ann.origin] = map[common.Hash]struct{}{hash: {}}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -400,7 +400,7 @@ func (f *TxFetcher) loop() {
|
||||||
if announces := f.announces[ann.origin]; announces != nil {
|
if announces := f.announces[ann.origin]; announces != nil {
|
||||||
announces[hash] = struct{}{}
|
announces[hash] = struct{}{}
|
||||||
} else {
|
} else {
|
||||||
f.announces[ann.origin] = map[common.Hash]struct{}{hash: struct{}{}}
|
f.announces[ann.origin] = map[common.Hash]struct{}{hash: {}}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -413,18 +413,18 @@ func (f *TxFetcher) loop() {
|
||||||
if waitslots := f.waitslots[ann.origin]; waitslots != nil {
|
if waitslots := f.waitslots[ann.origin]; waitslots != nil {
|
||||||
waitslots[hash] = struct{}{}
|
waitslots[hash] = struct{}{}
|
||||||
} else {
|
} else {
|
||||||
f.waitslots[ann.origin] = map[common.Hash]struct{}{hash: struct{}{}}
|
f.waitslots[ann.origin] = map[common.Hash]struct{}{hash: {}}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Transaction unknown to the fetcher, insert it into the waiting list
|
// Transaction unknown to the fetcher, insert it into the waiting list
|
||||||
f.waitlist[hash] = map[string]struct{}{ann.origin: struct{}{}}
|
f.waitlist[hash] = map[string]struct{}{ann.origin: {}}
|
||||||
f.waittime[hash] = f.clock.Now()
|
f.waittime[hash] = f.clock.Now()
|
||||||
|
|
||||||
if waitslots := f.waitslots[ann.origin]; waitslots != nil {
|
if waitslots := f.waitslots[ann.origin]; waitslots != nil {
|
||||||
waitslots[hash] = struct{}{}
|
waitslots[hash] = struct{}{}
|
||||||
} else {
|
} else {
|
||||||
f.waitslots[ann.origin] = map[common.Hash]struct{}{hash: struct{}{}}
|
f.waitslots[ann.origin] = map[common.Hash]struct{}{hash: {}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If a new item was added to the waitlist, schedule it into the fetcher
|
// If a new item was added to the waitlist, schedule it into the fetcher
|
||||||
|
@ -434,7 +434,7 @@ func (f *TxFetcher) loop() {
|
||||||
// If this peer is new and announced something already queued, maybe
|
// If this peer is new and announced something already queued, maybe
|
||||||
// request transactions from them
|
// request transactions from them
|
||||||
if !oldPeer && len(f.announces[ann.origin]) > 0 {
|
if !oldPeer && len(f.announces[ann.origin]) > 0 {
|
||||||
f.scheduleFetches(timeoutTimer, timeoutTrigger, map[string]struct{}{ann.origin: struct{}{}})
|
f.scheduleFetches(timeoutTimer, timeoutTrigger, map[string]struct{}{ann.origin: {}})
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-waitTrigger:
|
case <-waitTrigger:
|
||||||
|
@ -452,7 +452,7 @@ func (f *TxFetcher) loop() {
|
||||||
if announces := f.announces[peer]; announces != nil {
|
if announces := f.announces[peer]; announces != nil {
|
||||||
announces[hash] = struct{}{}
|
announces[hash] = struct{}{}
|
||||||
} else {
|
} else {
|
||||||
f.announces[peer] = map[common.Hash]struct{}{hash: struct{}{}}
|
f.announces[peer] = map[common.Hash]struct{}{hash: {}}
|
||||||
}
|
}
|
||||||
delete(f.waitslots[peer], hash)
|
delete(f.waitslots[peer], hash)
|
||||||
if len(f.waitslots[peer]) == 0 {
|
if len(f.waitslots[peer]) == 0 {
|
||||||
|
|
Loading…
Reference in New Issue