Skip to content

Commit

Permalink
Merge pull request #5 from cffls/agnostic_zero_tracer
Browse files Browse the repository at this point in the history
Make read list in zero trace agnostic to opcodes
  • Loading branch information
cffls authored May 28, 2024
2 parents d96fa3a + c53d1d7 commit d5c12eb
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 17 deletions.
35 changes: 33 additions & 2 deletions core/state/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ func NewTrieDbState(root common.Hash, db kv.Tx, blockNr uint64, stateReader Stat
blockNr: blockNr,
retainListBuilder: trie.NewRetainListBuilder(),
tp: tp,
pw: &PreimageWriter{db: db, savePreimages: true},
pw: &PreimageWriter{savePreimages: true},
hashBuilder: trie.NewHashBuilder(false),
incarnationMap: make(map[common.Address]uint64),
}
Expand Down Expand Up @@ -301,7 +301,7 @@ func (tds *TrieDbState) Copy() *TrieDbState {
db: tds.db,
blockNr: n,
tp: tp,
pw: &PreimageWriter{db: tds.db, savePreimages: true},
pw: &PreimageWriter{savePreimages: true},
hashBuilder: trie.NewHashBuilder(false),
incarnationMap: make(map[common.Address]uint64),
}
Expand Down Expand Up @@ -439,6 +439,20 @@ func (tds *TrieDbState) buildStorageReads() common.StorageKeys {
return storageTouches
}

func (tds *TrieDbState) BuildStorageReads() map[common.Address][]common.Hash {
storageReads := make(map[common.Address][]common.Hash)
for storageKey := range tds.aggregateBuffer.storageReads {
addr := common.BytesToAddress(tds.pw.GetPreimage(common.BytesToHash(storageKey[:length.Hash])))

if _, ok := storageReads[addr]; !ok {
storageReads[addr] = make([]common.Hash, 0)
}

storageReads[addr] = append(storageReads[addr], common.BytesToHash(storageKey[length.Hash+length.Incarnation:]))
}
return storageReads
}

// buildStorageWrites builds a sorted list of all storage key hashes that were modified within the
// period for which we are aggregating updates. It skips the updates that
// were nullified by subsequent updates - best example is the
Expand Down Expand Up @@ -482,6 +496,14 @@ func (tds *TrieDbState) buildCodeTouches() map[common.Hash]common.Hash {
return tds.aggregateBuffer.codeReads
}

func (tds *TrieDbState) BuildCodeReads() map[common.Address]common.Hash {
addresses := make(map[common.Address]common.Hash)
for addrHash, codeHash := range tds.aggregateBuffer.codeReads {
addresses[common.BytesToAddress(tds.pw.GetPreimage(addrHash))] = codeHash
}
return addresses
}

func (tds *TrieDbState) buildCodeSizeTouches() map[common.Hash]common.Hash {
return tds.aggregateBuffer.codeSizeReads
}
Expand All @@ -498,6 +520,15 @@ func (tds *TrieDbState) buildAccountReads() common.Hashes {
return accountTouches
}

func (tds *TrieDbState) BuildAddressReads() []common.Address {
accountTouches := tds.buildAccountReads()
addresses := make([]common.Address, len(accountTouches))
for i, addrHash := range accountTouches {
addresses[i] = common.BytesToAddress(tds.pw.GetPreimage(addrHash))
}
return addresses
}

// buildAccountWrites builds a sorted list of all address hashes that were modified within the
// period for which we are aggregating updates.
func (tds *TrieDbState) buildAccountWrites() (common.Hashes, []*accounts.Account, [][]byte) {
Expand Down
29 changes: 15 additions & 14 deletions core/state/database_writer.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
package state

import (
"fmt"

"github.com/ledgerwatch/erigon-lib/common"
"github.com/ledgerwatch/erigon-lib/kv"
)

type PreimageWriter struct {
db kv.Getter
preImageMap map[string][]byte
savePreimages bool
}

Expand All @@ -33,20 +30,24 @@ func (pw *PreimageWriter) HashKey(key *common.Hash, save bool) (common.Hash, err
}

func (pw *PreimageWriter) savePreimage(save bool, hash []byte, preimage []byte) error {
if !save || !pw.savePreimages {
return nil
}
// Following check is to minimise the overwriting the same value of preimage
// in the database, which would cause extra write churn
if p, _ := pw.db.GetOne(kv.PreimagePrefix, hash); p != nil {
if !pw.savePreimages {
return nil
}

putter, ok := pw.db.(kv.Putter)
if pw.preImageMap == nil {
pw.preImageMap = make(map[string][]byte)
}

if !ok {
return fmt.Errorf("db does not support putter interface")
if _, ok := pw.preImageMap[string(hash)]; !ok {
pw.preImageMap[string(hash)] = preimage
}

return putter.Put(kv.PreimagePrefix, hash, preimage)
return nil
}

func (pw *PreimageWriter) GetPreimage(hash common.Hash) []byte {
if pw.preImageMap == nil {
return nil
}
return pw.preImageMap[string(hash[:])]
}
8 changes: 8 additions & 0 deletions core/state/intra_block_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@ func (sdb *IntraBlockState) SetTrace(trace bool) {
sdb.trace = trace
}

func (sdb *IntraBlockState) SetStateReader(stateReader StateReader) {
sdb.stateReader = stateReader
}

func (sdb *IntraBlockState) GetStateReader() StateReader {
return sdb.stateReader
}

func (sdb *IntraBlockState) SetDisableBalanceInc(disable bool) {
sdb.disableBalanceInc = disable
}
Expand Down
27 changes: 26 additions & 1 deletion eth/tracers/native/zero.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/holiman/uint256"
libcommon "github.com/ledgerwatch/erigon-lib/common"
corestate "github.com/ledgerwatch/erigon/core/state"
"github.com/ledgerwatch/erigon/core/types"
"github.com/ledgerwatch/erigon/core/vm"
"github.com/ledgerwatch/erigon/crypto"
Expand Down Expand Up @@ -203,6 +204,28 @@ func (t *zeroTracer) CaptureTxEnd(restGas uint64) {
t.tx.Meta.GasUsed = t.gasLimit - restGas
*t.ctx.CumulativeGasUsed += t.tx.Meta.GasUsed

ibs := t.env.IntraBlockState()

tds := ibs.(*corestate.IntraBlockState).GetStateReader().(*corestate.TrieDbState)

addressReads := tds.BuildAddressReads()
for _, addr := range addressReads {
t.addAccountToTrace(addr)
}

storageReads := tds.BuildStorageReads()
for addr, keys := range storageReads {
for _, key := range keys {
t.addSLOADToAccount(addr, key)
}
}

codeReads := tds.BuildCodeReads()

for addr := range codeReads {
t.addAccountToTrace(addr)
}

for addr := range t.tx.Traces {
trace := t.tx.Traces[addr]
hasLiveAccount := t.env.IntraBlockState().HasLiveAccount(addr)
Expand Down Expand Up @@ -267,7 +290,7 @@ func (t *zeroTracer) CaptureTxEnd(restGas uint64) {
// DELEGATECALL, CALL, STATICCALL, CALLCODE, EXTCODECOPY, EXTCODEHASH, EXTCODESIZE
opCodes := []vm.OpCode{vm.DELEGATECALL, vm.CALL, vm.STATICCALL, vm.CALLCODE, vm.EXTCODECOPY,
vm.EXTCODEHASH, vm.EXTCODESIZE}
keep := false
_, keep := codeReads[addr]
for _, opCode := range opCodes {
if _, ok := t.addrOpCodes[addr][opCode]; ok {
keep = true
Expand All @@ -288,6 +311,8 @@ func (t *zeroTracer) CaptureTxEnd(restGas uint64) {
}
}

tds.ClearUpdates()

receipt := &types.Receipt{Type: t.ctx.Txn.Type(), CumulativeGasUsed: *t.ctx.CumulativeGasUsed}
receipt.Status = t.txStatus
receipt.TxHash = t.ctx.Txn.Hash()
Expand Down
6 changes: 6 additions & 0 deletions turbo/jsonrpc/tracing.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ func (api *PrivateDebugAPIImpl) traceBlock(ctx context.Context, blockNrOrHash rp
return err
}

if config.Tracer != nil && *config.Tracer == "zeroTracer" {
reader := ibs.GetStateReader()
tds := state.NewTrieDbState(common.Hash{}, tx, blockNumber, reader)
ibs.SetStateReader(tds)
}

signer := types.MakeSigner(chainConfig, block.NumberU64(), block.Time())
rules := chainConfig.Rules(block.NumberU64(), block.Time())
stream.WriteArrayStart()
Expand Down

0 comments on commit d5c12eb

Please sign in to comment.