mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
ota underlying storage
This commit is contained in:
parent
7f5d6a0bde
commit
fcb5aaff61
4 changed files with 130 additions and 8 deletions
|
|
@ -111,6 +111,11 @@ type (
|
|||
account *common.Address
|
||||
key, prevalue common.Hash
|
||||
}
|
||||
storageByteArrayChange struct {
|
||||
account *common.Address
|
||||
key common.Hash
|
||||
prevalue []byte
|
||||
}
|
||||
codeChange struct {
|
||||
account *common.Address
|
||||
prevcode, prevhash []byte
|
||||
|
|
@ -179,6 +184,14 @@ func (ch balanceChange) dirtied() *common.Address {
|
|||
return ch.account
|
||||
}
|
||||
|
||||
func (ch storageByteArrayChange) revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setStateByteArray(ch.key, ch.prevalue)
|
||||
}
|
||||
|
||||
func (ch storageByteArrayChange) dirtied() *common.Address {
|
||||
return ch.account
|
||||
}
|
||||
|
||||
func (ch nonceChange) revert(s *StateDB) {
|
||||
s.getStateObject(*ch.account).setNonce(ch.prev)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ func (c Code) String() string {
|
|||
|
||||
type Storage map[common.Hash]common.Hash
|
||||
|
||||
type StorageByteArray map[common.Hash][]byte
|
||||
|
||||
func (s Storage) String() (str string) {
|
||||
for key, value := range s {
|
||||
str += fmt.Sprintf("%X : %X\n", key, value)
|
||||
|
|
@ -56,6 +58,15 @@ func (s Storage) Copy() Storage {
|
|||
return cpy
|
||||
}
|
||||
|
||||
func (self StorageByteArray) Copy() StorageByteArray {
|
||||
cpy := make(StorageByteArray)
|
||||
for key, value := range self {
|
||||
cpy[key] = value
|
||||
}
|
||||
|
||||
return cpy
|
||||
}
|
||||
|
||||
// stateObject represents an Ethereum account which is being modified.
|
||||
//
|
||||
// The usage pattern is as follows:
|
||||
|
|
@ -84,6 +95,9 @@ type stateObject struct {
|
|||
dirtyStorage Storage // Storage entries that have been modified in the current transaction execution
|
||||
fakeStorage Storage // Fake storage which constructed by caller for debugging purpose.
|
||||
|
||||
cachedStorageByteArray StorageByteArray
|
||||
dirtyStorageByteArray StorageByteArray
|
||||
|
||||
// Cache flags.
|
||||
// When an object is marked suicided it will be delete from the trie
|
||||
// during the "update" phase of the state transition.
|
||||
|
|
@ -94,7 +108,7 @@ type stateObject struct {
|
|||
|
||||
// empty returns whether the account is considered empty.
|
||||
func (s *stateObject) empty() bool {
|
||||
return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash)
|
||||
return s.data.Nonce == 0 && s.data.Balance.Sign() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash) && len(s.dirtyStorage) == 0 && len(s.dirtyStorageByteArray) == 0
|
||||
}
|
||||
|
||||
// Account is the Ethereum consensus representation of accounts.
|
||||
|
|
@ -118,13 +132,15 @@ func newObject(db *StateDB, address common.Address, data Account) *stateObject {
|
|||
data.Root = emptyRoot
|
||||
}
|
||||
return &stateObject{
|
||||
db: db,
|
||||
address: address,
|
||||
addrHash: crypto.Keccak256Hash(address[:]),
|
||||
data: data,
|
||||
originStorage: make(Storage),
|
||||
pendingStorage: make(Storage),
|
||||
dirtyStorage: make(Storage),
|
||||
db: db,
|
||||
address: address,
|
||||
addrHash: crypto.Keccak256Hash(address[:]),
|
||||
data: data,
|
||||
originStorage: make(Storage),
|
||||
pendingStorage: make(Storage),
|
||||
dirtyStorage: make(Storage),
|
||||
cachedStorageByteArray: make(StorageByteArray),
|
||||
dirtyStorageByteArray: make(StorageByteArray),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -260,6 +276,34 @@ func (s *stateObject) setState(key, value common.Hash) {
|
|||
s.dirtyStorage[key] = value
|
||||
}
|
||||
|
||||
func (s *stateObject) GetStateByteArray(db Database, key common.Hash) []byte {
|
||||
value, exists := s.cachedStorageByteArray[key]
|
||||
if exists {
|
||||
return value
|
||||
}
|
||||
// Load from DB in case it is missing.
|
||||
value, err := s.getTrie(db).TryGet(key[:])
|
||||
if err == nil && len(value) != 0 {
|
||||
s.cachedStorageByteArray[key] = value
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func (s *stateObject) SetStateByteArray(db Database, key common.Hash, value []byte) {
|
||||
s.db.journal.append(storageByteArrayChange{
|
||||
account: &s.address,
|
||||
key: key,
|
||||
prevalue: s.GetStateByteArray(db, key),
|
||||
})
|
||||
s.setStateByteArray(key, value)
|
||||
|
||||
}
|
||||
|
||||
func (self *stateObject) setStateByteArray(key common.Hash, value []byte) {
|
||||
self.cachedStorageByteArray[key] = value
|
||||
self.dirtyStorageByteArray[key] = value
|
||||
}
|
||||
|
||||
// finalise moves all dirty storage slots into the pending area to be hashed or
|
||||
// committed later. It is invoked at the end of every transaction.
|
||||
func (s *stateObject) finalise() {
|
||||
|
|
@ -300,6 +344,19 @@ func (s *stateObject) updateTrie(db Database) Trie {
|
|||
if len(s.pendingStorage) > 0 {
|
||||
s.pendingStorage = make(Storage)
|
||||
}
|
||||
|
||||
for key, value := range s.dirtyStorageByteArray {
|
||||
delete(s.dirtyStorageByteArray, key)
|
||||
if len(value) == 0 {
|
||||
s.setError(tr.TryDelete(key[:]))
|
||||
continue
|
||||
}
|
||||
s.setError(tr.TryUpdate(key[:], value))
|
||||
}
|
||||
if len(s.dirtyStorageByteArray) > 0 {
|
||||
s.dirtyStorageByteArray = make(StorageByteArray)
|
||||
}
|
||||
|
||||
return tr
|
||||
}
|
||||
|
||||
|
|
@ -380,6 +437,8 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject {
|
|||
stateObject.dirtyStorage = s.dirtyStorage.Copy()
|
||||
stateObject.originStorage = s.originStorage.Copy()
|
||||
stateObject.pendingStorage = s.pendingStorage.Copy()
|
||||
stateObject.dirtyStorageByteArray = s.dirtyStorageByteArray.Copy()
|
||||
stateObject.cachedStorageByteArray = s.cachedStorageByteArray.Copy()
|
||||
stateObject.suicided = s.suicided
|
||||
stateObject.dirtyCode = s.dirtyCode
|
||||
stateObject.deleted = s.deleted
|
||||
|
|
|
|||
|
|
@ -398,6 +398,51 @@ func (self *StateDB) SetStorage(addr common.Address, storage map[common.Hash]com
|
|||
}
|
||||
}
|
||||
|
||||
// cb is callback function. cb return true indicating like to continue, return false indicating stop
|
||||
func (db *StateDB) ForEachStorageByteArray(addr common.Address, cb func(key common.Hash, value []byte) bool) {
|
||||
so := db.getStateObject(addr)
|
||||
if so == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// When iterating over the storage check the cache first
|
||||
for h, value := range so.cachedStorageByteArray {
|
||||
if !cb(h, value) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
it := trie.NewIterator(so.getTrie(db.db).NodeIterator(nil))
|
||||
for it.Next() {
|
||||
// ignore cached values
|
||||
key := common.BytesToHash(db.trie.GetKey(it.Key))
|
||||
if _, ok := so.fakeStorage[key]; !ok {
|
||||
if !cb(key, it.Value) {
|
||||
return
|
||||
}
|
||||
} else if _, ok := so.dirtyStorage[key]; !ok {
|
||||
if !cb(key, it.Value) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *StateDB) GetStateByteArray(a common.Address, b common.Hash) []byte {
|
||||
stateObject := self.getStateObject(a)
|
||||
if stateObject != nil {
|
||||
return stateObject.GetStateByteArray(self.db, b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *StateDB) SetStateByteArray(addr common.Address, key common.Hash, value []byte) {
|
||||
stateObject := self.GetOrNewStateObject(addr)
|
||||
if stateObject != nil {
|
||||
stateObject.SetStateByteArray(self.db, key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// Suicide marks the given account as suicided.
|
||||
// This clears the account balance.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ type StateDB interface {
|
|||
GetState(common.Address, common.Hash) common.Hash
|
||||
SetState(common.Address, common.Hash, common.Hash)
|
||||
|
||||
GetStateByteArray(common.Address, common.Hash) []byte
|
||||
SetStateByteArray(common.Address, common.Hash, []byte)
|
||||
|
||||
Suicide(common.Address) bool
|
||||
HasSuicided(common.Address) bool
|
||||
|
||||
|
|
@ -64,6 +67,8 @@ type StateDB interface {
|
|||
AddPreimage(common.Hash, []byte)
|
||||
|
||||
ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) error
|
||||
|
||||
ForEachStorageByteArray(common.Address, func(common.Hash, []byte) bool)
|
||||
}
|
||||
|
||||
// CallContext provides a basic interface for the EVM calling conventions. The EVM
|
||||
|
|
|
|||
Loading…
Reference in a new issue