Skip to content

Commit

Permalink
final version, just need to merge into one commit and should be done
Browse files Browse the repository at this point in the history
  • Loading branch information
samalws-tob committed Sep 5, 2024
1 parent 40cf708 commit b6d446f
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 34 deletions.
18 changes: 3 additions & 15 deletions fuzzing/coverage/coverage_maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,6 @@ type CoverageMaps struct {
// maps represents a structure used to track every ContractCoverageMap by a given deployed address/lookup hash.
maps map[common.Hash]map[common.Address]*ContractCoverageMap

// TODO comment this
// The assumption here is that geth codehash matches if and only if codehash matches
gethCodeHashToCodeHash map[common.Hash]*common.Hash

// TODO comment this
// The assumption here is that geth codehash matches if and only if codehash matches
cachedGethCodeHash common.Hash

// cachedCodeAddress represents the last code address which coverage was updated for. This is used to prevent an
// expensive lookup in maps. If cachedCodeHash does not match the current code address for which we are updating
// coverage for, it, along with other cache variables are updated.
Expand All @@ -44,9 +36,7 @@ type CoverageMaps struct {

// NewCoverageMaps initializes a new CoverageMaps object.
func NewCoverageMaps() *CoverageMaps {
maps := &CoverageMaps{
gethCodeHashToCodeHash: make(map[common.Hash]*common.Hash),
}
maps := &CoverageMaps{}
maps.Reset()
return maps
}
Expand All @@ -56,7 +46,6 @@ func (cm *CoverageMaps) Reset() {
cm.maps = make(map[common.Hash]map[common.Address]*ContractCoverageMap)
cm.cachedCodeAddress = common.Address{}
cm.cachedCodeHash = common.Hash{}
cm.cachedGethCodeHash = common.Hash{}
cm.cachedMap = nil
}

Expand Down Expand Up @@ -181,7 +170,7 @@ func (cm *CoverageMaps) Update(coverageMaps *CoverageMaps) (bool, bool, error) {
}

// UpdateAt updates the hit count of a given program counter location within code coverage data.
func (cm *CoverageMaps) UpdateAt(codeAddress common.Address, gethCodeHash common.Hash, codeLookupHash common.Hash, codeSize int, pc uint64) (bool, error) {
func (cm *CoverageMaps) UpdateAt(codeAddress common.Address, codeLookupHash common.Hash, codeSize int, pc uint64) (bool, error) {
// If the code size is zero, do nothing
if codeSize == 0 {
return false, nil
Expand All @@ -196,7 +185,7 @@ func (cm *CoverageMaps) UpdateAt(codeAddress common.Address, gethCodeHash common
)

// Try to obtain a coverage map from our cache
if cm.cachedMap != nil && cm.cachedCodeAddress == codeAddress && cm.cachedCodeHash == codeLookupHash && cm.cachedGethCodeHash == gethCodeHash {
if cm.cachedMap != nil && cm.cachedCodeAddress == codeAddress && cm.cachedCodeHash == codeLookupHash {
coverageMap = cm.cachedMap
} else {
// If a coverage map lookup for this code hash doesn't exist, create the mapping.
Expand All @@ -218,7 +207,6 @@ func (cm *CoverageMaps) UpdateAt(codeAddress common.Address, gethCodeHash common
// Set our cached variables for faster coverage setting next time this method is called.
cm.cachedMap = coverageMap
cm.cachedCodeHash = codeLookupHash
cm.cachedGethCodeHash = gethCodeHash
cm.cachedCodeAddress = codeAddress
}

Expand Down
36 changes: 17 additions & 19 deletions fuzzing/coverage/coverage_tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,12 @@ type CoverageTracer struct {
// nativeTracer is the underlying tracer used to capture EVM execution.
nativeTracer *chain.TestChainTracer

// TODO comment
gethCodeHashToCodeHash map[common.Hash]*common.Hash
// codeHashCache is a cache for values returned by getContractCoverageMapHash,
// so that this expensive calculation doesn't need to be done every opcode.
// The Hash key is a contract's codehash (which uniquely identifies it),
// and the bool key is whether we're in contract init (true) or runtime (false)
// (since init vs runtime produces different results from getContractCoverageMapHash).
codeHashCache map[bool]map[common.Hash]common.Hash
}

// coverageTracerCallFrameState tracks state across call frames in the tracer.
Expand All @@ -72,9 +76,9 @@ type coverageTracerCallFrameState struct {
// NewCoverageTracer returns a new CoverageTracer.
func NewCoverageTracer() *CoverageTracer {
tracer := &CoverageTracer{
coverageMaps: NewCoverageMaps(),
gethCodeHashToCodeHash: make(map[common.Hash]*common.Hash),
callFrameStates: make([]*coverageTracerCallFrameState, 0),
coverageMaps: NewCoverageMaps(),
callFrameStates: make([]*coverageTracerCallFrameState, 0),
codeHashCache: map[bool]map[common.Hash]common.Hash{false: make(map[common.Hash]common.Hash), true: make(map[common.Hash]common.Hash)},
}
nativeTracer := &tracers.Tracer{
Hooks: &tracing.Hooks{
Expand Down Expand Up @@ -161,30 +165,24 @@ func (t *CoverageTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tr
address := scope.Address()
// We can cast OpContext to ScopeContext because that is the type passed to OnOpcode.
scopeContext := scope.(*vm.ScopeContext)
gethCodeHash := scopeContext.Contract.CodeHash
code := scopeContext.Contract.Code
codeSize := len(code)
isCreate := callFrameState.create
gethCodeHash := scopeContext.Contract.CodeHash
if codeSize > 0 {

// Obtain our contract coverage map lookup hash.
if callFrameState.lookupHash == nil {
if callFrameState.pendingCoverageMap.cachedGethCodeHash == gethCodeHash {
lookupHash := callFrameState.pendingCoverageMap.cachedCodeHash
callFrameState.lookupHash = &lookupHash
} else if t.gethCodeHashToCodeHash[gethCodeHash] != nil {
callFrameState.lookupHash = t.gethCodeHashToCodeHash[gethCodeHash]
} else if callFrameState.pendingCoverageMap.gethCodeHashToCodeHash[gethCodeHash] != nil {
callFrameState.lookupHash = t.gethCodeHashToCodeHash[gethCodeHash]
} else {
lookupHash := getContractCoverageMapHash(code, callFrameState.create)
callFrameState.lookupHash = &lookupHash
t.gethCodeHashToCodeHash[gethCodeHash] = &lookupHash
callFrameState.pendingCoverageMap.gethCodeHashToCodeHash[gethCodeHash] = &lookupHash
lookupHash, cacheHit := t.codeHashCache[isCreate][gethCodeHash]
if !cacheHit {
lookupHash = getContractCoverageMapHash(code, isCreate)
t.codeHashCache[isCreate][gethCodeHash] = lookupHash
}
callFrameState.lookupHash = &lookupHash
}

// Record coverage for this location in our map.
_, coverageUpdateErr := callFrameState.pendingCoverageMap.UpdateAt(address, gethCodeHash, *callFrameState.lookupHash, codeSize, pc)
_, coverageUpdateErr := callFrameState.pendingCoverageMap.UpdateAt(address, *callFrameState.lookupHash, codeSize, pc)
if coverageUpdateErr != nil {
logging.GlobalLogger.Panic("Coverage tracer failed to update coverage map while tracing state", coverageUpdateErr)
}
Expand Down

0 comments on commit b6d446f

Please sign in to comment.