core: initial version of state snapshots
This commit is contained in:
@ -195,15 +195,26 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has
|
||||
if value, cached := s.originStorage[key]; cached {
|
||||
return value
|
||||
}
|
||||
// Track the amount of time wasted on reading the storage trie
|
||||
if metrics.EnabledExpensive {
|
||||
defer func(start time.Time) { s.db.StorageReads += time.Since(start) }(time.Now())
|
||||
}
|
||||
// Otherwise load the value from the database
|
||||
enc, err := s.getTrie(db).TryGet(key[:])
|
||||
if err != nil {
|
||||
s.setError(err)
|
||||
return common.Hash{}
|
||||
// If no live objects are available, attempt to use snapshots
|
||||
var (
|
||||
enc []byte
|
||||
err error
|
||||
)
|
||||
if s.db.snap != nil {
|
||||
if metrics.EnabledExpensive {
|
||||
defer func(start time.Time) { s.db.SnapshotStorageReads += time.Since(start) }(time.Now())
|
||||
}
|
||||
enc = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key[:]))
|
||||
} else {
|
||||
// Track the amount of time wasted on reading the storage trie
|
||||
if metrics.EnabledExpensive {
|
||||
defer func(start time.Time) { s.db.StorageReads += time.Since(start) }(time.Now())
|
||||
}
|
||||
// Otherwise load the value from the database
|
||||
if enc, err = s.getTrie(db).TryGet(key[:]); err != nil {
|
||||
s.setError(err)
|
||||
return common.Hash{}
|
||||
}
|
||||
}
|
||||
var value common.Hash
|
||||
if len(enc) > 0 {
|
||||
@ -283,6 +294,23 @@ func (s *stateObject) updateTrie(db Database) Trie {
|
||||
if metrics.EnabledExpensive {
|
||||
defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now())
|
||||
}
|
||||
// Retrieve the snapshot storage map for the object
|
||||
var storage map[common.Hash][]byte
|
||||
if s.db.snap != nil {
|
||||
// Retrieve the old storage map, if available
|
||||
s.db.snapLock.RLock()
|
||||
storage = s.db.snapStorage[s.addrHash]
|
||||
s.db.snapLock.RUnlock()
|
||||
|
||||
// If no old storage map was available, create a new one
|
||||
if storage == nil {
|
||||
storage = make(map[common.Hash][]byte)
|
||||
|
||||
s.db.snapLock.Lock()
|
||||
s.db.snapStorage[s.addrHash] = storage
|
||||
s.db.snapLock.Unlock()
|
||||
}
|
||||
}
|
||||
// Insert all the pending updates into the trie
|
||||
tr := s.getTrie(db)
|
||||
for key, value := range s.pendingStorage {
|
||||
@ -292,13 +320,18 @@ func (s *stateObject) updateTrie(db Database) Trie {
|
||||
}
|
||||
s.originStorage[key] = value
|
||||
|
||||
var v []byte
|
||||
if (value == common.Hash{}) {
|
||||
s.setError(tr.TryDelete(key[:]))
|
||||
continue
|
||||
} else {
|
||||
// Encoding []byte cannot fail, ok to ignore the error.
|
||||
v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:]))
|
||||
s.setError(tr.TryUpdate(key[:], v))
|
||||
}
|
||||
// If state snapshotting is active, cache the data til commit
|
||||
if storage != nil {
|
||||
storage[crypto.Keccak256Hash(key[:])] = v // v will be nil if value is 0x00
|
||||
}
|
||||
// Encoding []byte cannot fail, ok to ignore the error.
|
||||
v, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(value[:]))
|
||||
s.setError(tr.TryUpdate(key[:], v))
|
||||
}
|
||||
if len(s.pendingStorage) > 0 {
|
||||
s.pendingStorage = make(Storage)
|
||||
|
Reference in New Issue
Block a user