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
|
account *common.Address
|
||||||
key, prevalue common.Hash
|
key, prevalue common.Hash
|
||||||
}
|
}
|
||||||
|
storageByteArrayChange struct {
|
||||||
|
account *common.Address
|
||||||
|
key common.Hash
|
||||||
|
prevalue []byte
|
||||||
|
}
|
||||||
codeChange struct {
|
codeChange struct {
|
||||||
account *common.Address
|
account *common.Address
|
||||||
prevcode, prevhash []byte
|
prevcode, prevhash []byte
|
||||||
|
|
@ -179,6 +184,14 @@ func (ch balanceChange) dirtied() *common.Address {
|
||||||
return ch.account
|
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) {
|
func (ch nonceChange) revert(s *StateDB) {
|
||||||
s.getStateObject(*ch.account).setNonce(ch.prev)
|
s.getStateObject(*ch.account).setNonce(ch.prev)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,8 @@ func (c Code) String() string {
|
||||||
|
|
||||||
type Storage map[common.Hash]common.Hash
|
type Storage map[common.Hash]common.Hash
|
||||||
|
|
||||||
|
type StorageByteArray map[common.Hash][]byte
|
||||||
|
|
||||||
func (s Storage) String() (str string) {
|
func (s Storage) String() (str string) {
|
||||||
for key, value := range s {
|
for key, value := range s {
|
||||||
str += fmt.Sprintf("%X : %X\n", key, value)
|
str += fmt.Sprintf("%X : %X\n", key, value)
|
||||||
|
|
@ -56,6 +58,15 @@ func (s Storage) Copy() Storage {
|
||||||
return cpy
|
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.
|
// stateObject represents an Ethereum account which is being modified.
|
||||||
//
|
//
|
||||||
// The usage pattern is as follows:
|
// 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
|
dirtyStorage Storage // Storage entries that have been modified in the current transaction execution
|
||||||
fakeStorage Storage // Fake storage which constructed by caller for debugging purpose.
|
fakeStorage Storage // Fake storage which constructed by caller for debugging purpose.
|
||||||
|
|
||||||
|
cachedStorageByteArray StorageByteArray
|
||||||
|
dirtyStorageByteArray StorageByteArray
|
||||||
|
|
||||||
// Cache flags.
|
// Cache flags.
|
||||||
// When an object is marked suicided it will be delete from the trie
|
// When an object is marked suicided it will be delete from the trie
|
||||||
// during the "update" phase of the state transition.
|
// during the "update" phase of the state transition.
|
||||||
|
|
@ -94,7 +108,7 @@ type stateObject struct {
|
||||||
|
|
||||||
// empty returns whether the account is considered empty.
|
// empty returns whether the account is considered empty.
|
||||||
func (s *stateObject) empty() bool {
|
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.
|
// 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
|
data.Root = emptyRoot
|
||||||
}
|
}
|
||||||
return &stateObject{
|
return &stateObject{
|
||||||
db: db,
|
db: db,
|
||||||
address: address,
|
address: address,
|
||||||
addrHash: crypto.Keccak256Hash(address[:]),
|
addrHash: crypto.Keccak256Hash(address[:]),
|
||||||
data: data,
|
data: data,
|
||||||
originStorage: make(Storage),
|
originStorage: make(Storage),
|
||||||
pendingStorage: make(Storage),
|
pendingStorage: make(Storage),
|
||||||
dirtyStorage: 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
|
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
|
// 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.
|
// committed later. It is invoked at the end of every transaction.
|
||||||
func (s *stateObject) finalise() {
|
func (s *stateObject) finalise() {
|
||||||
|
|
@ -300,6 +344,19 @@ func (s *stateObject) updateTrie(db Database) Trie {
|
||||||
if len(s.pendingStorage) > 0 {
|
if len(s.pendingStorage) > 0 {
|
||||||
s.pendingStorage = make(Storage)
|
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
|
return tr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -380,6 +437,8 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject {
|
||||||
stateObject.dirtyStorage = s.dirtyStorage.Copy()
|
stateObject.dirtyStorage = s.dirtyStorage.Copy()
|
||||||
stateObject.originStorage = s.originStorage.Copy()
|
stateObject.originStorage = s.originStorage.Copy()
|
||||||
stateObject.pendingStorage = s.pendingStorage.Copy()
|
stateObject.pendingStorage = s.pendingStorage.Copy()
|
||||||
|
stateObject.dirtyStorageByteArray = s.dirtyStorageByteArray.Copy()
|
||||||
|
stateObject.cachedStorageByteArray = s.cachedStorageByteArray.Copy()
|
||||||
stateObject.suicided = s.suicided
|
stateObject.suicided = s.suicided
|
||||||
stateObject.dirtyCode = s.dirtyCode
|
stateObject.dirtyCode = s.dirtyCode
|
||||||
stateObject.deleted = s.deleted
|
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.
|
// Suicide marks the given account as suicided.
|
||||||
// This clears the account balance.
|
// This clears the account balance.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,9 @@ type StateDB interface {
|
||||||
GetState(common.Address, common.Hash) common.Hash
|
GetState(common.Address, common.Hash) common.Hash
|
||||||
SetState(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
|
Suicide(common.Address) bool
|
||||||
HasSuicided(common.Address) bool
|
HasSuicided(common.Address) bool
|
||||||
|
|
||||||
|
|
@ -64,6 +67,8 @@ type StateDB interface {
|
||||||
AddPreimage(common.Hash, []byte)
|
AddPreimage(common.Hash, []byte)
|
||||||
|
|
||||||
ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) error
|
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
|
// CallContext provides a basic interface for the EVM calling conventions. The EVM
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue