Skip to content

Commit

Permalink
opt: add conflict check cache
Browse files Browse the repository at this point in the history
  • Loading branch information
sunny2022da committed Aug 22, 2024
1 parent 9ec5fc1 commit b685b8b
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 8 deletions.
55 changes: 49 additions & 6 deletions core/state/parallel_statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func hasKvConflict(slotDB *ParallelStateDB, addr common.Address, key common.Hash
}
}
}
valMain := mainDB.GetStateNoUpdate(addr, key)
valMain := slotDB.getStateFromMainNoUpdate(addr, key) // mainDB.GetStateNoUpdate(addr, key)

if !bytes.Equal(val.Bytes(), valMain.Bytes()) {
log.Debug("hasKvConflict is invalid", "addr", addr,
Expand Down Expand Up @@ -1267,6 +1267,45 @@ func (s *ParallelStateDB) getStateObjectFromUnconfirmedDB(addr common.Address) (
return nil, false
}

func (s *ParallelStateDB) getStateObjectFromMainDBNoUpdate(addr common.Address) *stateObject {
var mainObj *stateObject

if m, ok := s.parallel.conflictCheckStateObjectCache.Load(addr); ok {
mainObj = m.(*stateObject)
return mainObj
} else {
mainDB := s.parallel.baseStateDB
mainObj = mainDB.getStateObjectNoUpdate(addr)
s.parallel.conflictCheckStateObjectCache.Store(addr, mainObj)
}
return mainObj
}

// GetStateNoUpdate retrieves a value from the given account's storage trie, but do not update the db.stateObjects cache.
func (s *ParallelStateDB) getStateFromMainNoUpdate(addr common.Address, key common.Hash) (ret common.Hash) {

if kvPair, ok := s.parallel.conflictCheckKVReadCache.Load(addr); !ok {
s.parallel.conflictCheckKVReadCache.Store(addr, newStorage(true))
} else {
st := kvPair.(*StorageSyncMap)
if val, ok := st.GetValue(key); ok {
return val
}
}
val := common.Hash{}
object := s.getStateObjectFromMainDBNoUpdate(addr)
if object != nil {
val = object.GetStateNoUpdate(key)
}
if kvPair, ok := s.parallel.conflictCheckKVReadCache.Load(addr); ok {
st := kvPair.(*StorageSyncMap)
st.StoreValue(key, val)
s.parallel.conflictCheckKVReadCache.Store(addr, st)
}

return val
}

// IsParallelReadsValid If stage2 is true, it is a likely conflict check,
// to detect these potential conflict results in advance and schedule redo ASAP.
func (slotDB *ParallelStateDB) IsParallelReadsValid(isStage2 bool) bool {
Expand All @@ -1275,6 +1314,10 @@ func (slotDB *ParallelStateDB) IsParallelReadsValid(isStage2 bool) bool {
})

mainDB := slotDB.parallel.baseStateDB
// conservatively use kvRead size as the initial size.
slotDB.parallel.conflictCheckStateObjectCache = new(sync.Map)
slotDB.parallel.conflictCheckKVReadCache = new(sync.Map)

// for nonce
for addr, nonceSlot := range slotDB.parallel.nonceReadsInSlot {
if isStage2 { // update slotDB's unconfirmed DB list and try
Expand All @@ -1292,7 +1335,7 @@ func (slotDB *ParallelStateDB) IsParallelReadsValid(isStage2 bool) bool {
}
}
var nonceMain uint64 = 0
mainObj := mainDB.getStateObjectNoUpdate(addr)
mainObj := slotDB.getStateObjectFromMainDBNoUpdate(addr)
if mainObj != nil {
nonceMain = mainObj.Nonce()
}
Expand Down Expand Up @@ -1321,7 +1364,7 @@ func (slotDB *ParallelStateDB) IsParallelReadsValid(isStage2 bool) bool {
}

balanceMain := common.Big0
mainObj := mainDB.getStateObjectNoUpdate(addr)
mainObj := slotDB.getStateObjectFromMainDBNoUpdate(addr)
if mainObj != nil {
balanceMain = mainObj.Balance()
}
Expand Down Expand Up @@ -1413,7 +1456,7 @@ func (slotDB *ParallelStateDB) IsParallelReadsValid(isStage2 bool) bool {
// check code
for addr, codeSlot := range slotDB.parallel.codeReadsInSlot {
var codeMain []byte = nil
object := mainDB.getStateObjectNoUpdate(addr)
object := slotDB.getStateObjectFromMainDBNoUpdate(addr)
if object != nil {
codeMain = object.Code()
}
Expand All @@ -1428,7 +1471,7 @@ func (slotDB *ParallelStateDB) IsParallelReadsValid(isStage2 bool) bool {
// check codeHash
for addr, codeHashSlot := range slotDB.parallel.codeHashReadsInSlot {
codeHashMain := common.Hash{}
object := mainDB.getStateObjectNoUpdate(addr)
object := slotDB.getStateObjectFromMainDBNoUpdate(addr)
if object != nil {
codeHashMain = common.BytesToHash(object.CodeHash())
}
Expand All @@ -1442,7 +1485,7 @@ func (slotDB *ParallelStateDB) IsParallelReadsValid(isStage2 bool) bool {
// addr state check
for addr, stateSlot := range slotDB.parallel.addrStateReadsInSlot {
stateMain := false // addr not exist
if mainDB.getStateObjectNoUpdate(addr) != nil {
if slotDB.getStateObjectFromMainDBNoUpdate(addr) != nil {
stateMain = true // addr exist in main DB
}
if stateSlot != stateMain {
Expand Down
6 changes: 4 additions & 2 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,10 @@ type ParallelState struct {
storagesOriginDeleteRecord []common.Address
createdObjectRecord map[common.Address]struct{}
// we may need to redo for some specific reasons, like we read the wrong state and need to panic in sequential mode in SubRefund
needsRedo bool
useDAG bool
needsRedo bool
useDAG bool
conflictCheckStateObjectCache *sync.Map
conflictCheckKVReadCache *sync.Map
}

// StateDB structs within the ethereum protocol are used to store anything
Expand Down

0 comments on commit b685b8b

Please sign in to comment.