Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Enhanced StateDB logs for Concurrency Safety #1727

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions core/state/journal.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"sync"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)

// journalEntry is a modification entry in the state change journal that can be
Expand Down Expand Up @@ -247,11 +248,20 @@ func (ch refundChange) dirtied() *common.Address {
}

func (ch addLogChange) revert(s *StateDB) {
logs := s.logs[ch.txhash]
logsInterface, ok := s.logs.Load(ch.txhash)
if !ok {
return
}

logs, ok := logsInterface.([]*types.Log)
if !ok {
return
}

if len(logs) == 1 {
delete(s.logs, ch.txhash)
s.logs.Delete(ch.txhash)
} else {
s.logs[ch.txhash] = logs[:len(logs)-1]
s.logs.Store(ch.txhash, logs[:len(logs)-1])
}
s.logSize--
}
Expand Down
62 changes: 44 additions & 18 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ type StateDB struct {

thash, bhash common.Hash
txIndex int
logs map[common.Hash][]*types.Log
logs sync.Map
logSize uint

preimages map[common.Hash][]byte
Expand Down Expand Up @@ -142,6 +142,9 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
}
// End Quorum - Privacy Enhancements

// Ensure mapping is type of map[common.Hash][]*types.Log
var logs sync.Map

sdb := &StateDB{
db: db,
trie: tr,
Expand All @@ -150,7 +153,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
stateObjects: make(map[common.Address]*stateObject),
stateObjectsPending: make(map[common.Address]struct{}),
stateObjectsDirty: make(map[common.Address]struct{}),
logs: make(map[common.Hash][]*types.Log),
logs: logs,
preimages: make(map[common.Hash][]byte),
journal: newJournal(),
accessList: newAccessList(),
Expand Down Expand Up @@ -202,25 +205,42 @@ func (s *StateDB) Error() error {
}

func (s *StateDB) AddLog(log *types.Log) {
s.journalMutex.Lock()
s.journal.append(addLogChange{txhash: s.thash})
s.journalMutex.Unlock()

log.TxHash = s.thash
log.BlockHash = s.bhash
log.TxIndex = uint(s.txIndex)
log.Index = s.logSize
s.logs[s.thash] = append(s.logs[s.thash], log)

var logs []*types.Log
txHashLogs, ok := s.logs.Load(s.thash)
if ok {
logs = txHashLogs.([]*types.Log)
}
s.logs.Store(s.thash, append(logs, log))

s.logSize++
}

func (s *StateDB) GetLogs(hash common.Hash) []*types.Log {
return s.logs[hash]
txLogs, ok := s.logs.Load(hash)
if !ok {
return make([]*types.Log, 0)
}
return txLogs.([]*types.Log)
}

func (s *StateDB) Logs() []*types.Log {
var logs []*types.Log
for _, lgs := range s.logs {
logs = append(logs, lgs...)
}

s.logs.Range(func(key, value interface{}) bool {
logValue := value.([]*types.Log)
logs = append(logs, logValue...)
return true
})

return logs
}

Expand Down Expand Up @@ -340,15 +360,20 @@ func (s *StateDB) Reset(root common.Hash) error {
s.stateObjects = make(map[common.Address]*stateObject)
s.stateObjectsPending = make(map[common.Address]struct{})
s.stateObjectsDirty = make(map[common.Address]struct{})
s.logSize = 0
s.mutex.Unlock()
s.thash = common.Hash{}
s.bhash = common.Hash{}
s.txIndex = 0
s.logs = make(map[common.Hash][]*types.Log)
s.logSize = 0
s.preimages = make(map[common.Hash][]byte)
s.clearJournalAndRefund()

// Clear all entries
s.logs.Range(func(key, value interface{}) bool {
s.logs.Delete(key)
return true
})

if s.snaps != nil {
s.snapAccounts, s.snapDestructs, s.snapStorage = nil, nil, nil
if s.snap = s.snaps.Snapshot(root); s.snap != nil {
Expand Down Expand Up @@ -816,6 +841,9 @@ func (s *StateDB) Copy() *StateDB {
}
journal.mutex.Unlock()

// Instantiate new copy of "logs"
var copyOfLogs sync.Map

// Copy all the basic fields, initialize the memory ones
state := &StateDB{
db: s.db,
Expand All @@ -824,7 +852,7 @@ func (s *StateDB) Copy() *StateDB {
stateObjectsPending: make(map[common.Address]struct{}, len(s.stateObjectsPending)),
stateObjectsDirty: make(map[common.Address]struct{}, size),
refund: s.refund,
logs: make(map[common.Hash][]*types.Log, len(s.logs)),
logs: copyOfLogs,
logSize: s.logSize,
preimages: make(map[common.Hash][]byte, len(s.preimages)),
journal: newJournal(),
Expand Down Expand Up @@ -866,14 +894,12 @@ func (s *StateDB) Copy() *StateDB {
state.stateObjectsDirty[addr] = struct{}{}
}
s.mutex.Unlock()
for hash, logs := range s.logs {
cpy := make([]*types.Log, len(logs))
for i, l := range logs {
cpy[i] = new(types.Log)
*cpy[i] = *l
}
state.logs[hash] = cpy
}

s.logs.Range(func(key, value interface{}) bool {
state.logs.Store(key, value)
return true
})

for hash, preimage := range s.preimages {
state.preimages[hash] = preimage
}
Expand Down