Skip to content
Merged
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
2 changes: 1 addition & 1 deletion core/state/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func (s *StateDB) dump(c collector, excludeCode, excludeStorage, excludeMissingP
account.SecureKey = it.Key
}
addr := common.BytesToAddress(addrBytes)
obj := newObject(s, addr, data)
obj := newObject(s, addr, &data)
if !excludeCode {
account.Code = common.Bytes2Hex(obj.Code(s.db))
}
Expand Down
14 changes: 12 additions & 2 deletions core/state/journal.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ type (
prevdestruct bool
prevAccount []byte
prevStorage map[common.Hash][]byte

prevAccountOriginExist bool
prevAccountOrigin []byte
prevStorageOrigin map[common.Hash][]byte
}
suicideChange struct {
account *common.Address
Expand Down Expand Up @@ -168,10 +172,16 @@ func (ch resetObjectChange) revert(s *StateDB) {
delete(s.stateObjectsDestruct, ch.prev.address)
}
if ch.prevAccount != nil {
s.snapAccounts[ch.prev.addrHash] = ch.prevAccount
s.accounts[ch.prev.addrHash] = ch.prevAccount
}
if ch.prevStorage != nil {
s.snapStorage[ch.prev.addrHash] = ch.prevStorage
s.storages[ch.prev.addrHash] = ch.prevStorage
}
if ch.prevAccountOriginExist {
s.accountsOrigin[ch.prev.addrHash] = ch.prevAccountOrigin
}
if ch.prevStorageOrigin != nil {
s.storagesOrigin[ch.prev.addrHash] = ch.prevStorageOrigin
}
}

Expand Down
36 changes: 36 additions & 0 deletions core/state/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2021 The CortexTheseus Authors
// This file is part of the CortexTheseus library.
//
// The CortexTheseus library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The CortexTheseus library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the CortexTheseus library. If not, see <http://www.gnu.org/licenses/>.
package state

import "github.com/CortexFoundation/CortexTheseus/metrics"

var (
accountUpdatedMeter = metrics.NewRegisteredMeter("state/update/account", nil)
storageUpdatedMeter = metrics.NewRegisteredMeter("state/update/storage", nil)
accountDeletedMeter = metrics.NewRegisteredMeter("state/delete/account", nil)
storageDeletedMeter = metrics.NewRegisteredMeter("state/delete/storage", nil)
accountTrieUpdatedMeter = metrics.NewRegisteredMeter("state/update/accountnodes", nil)
storageTriesUpdatedMeter = metrics.NewRegisteredMeter("state/update/storagenodes", nil)
accountTrieDeletedMeter = metrics.NewRegisteredMeter("state/delete/accountnodes", nil)
storageTriesDeletedMeter = metrics.NewRegisteredMeter("state/delete/storagenodes", nil)

slotDeletionMaxCount = metrics.NewRegisteredGauge("state/delete/storage/max/slot", nil)
slotDeletionMaxSize = metrics.NewRegisteredGauge("state/delete/storage/max/size", nil)
slotDeletionTimer = metrics.NewRegisteredResettingTimer("state/delete/storage/timer", nil)
slotDeletionCount = metrics.NewRegisteredMeter("state/delete/storage/slot", nil)
slotDeletionSize = metrics.NewRegisteredMeter("state/delete/storage/size", nil)
slotDeletionSkip = metrics.NewRegisteredGauge("state/delete/storage/skip", nil)
)
9 changes: 5 additions & 4 deletions core/state/snapshot/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"math/big"

"github.com/CortexFoundation/CortexTheseus/common"
"github.com/CortexFoundation/CortexTheseus/core/types"
"github.com/CortexFoundation/CortexTheseus/rlp"
)

Expand All @@ -44,10 +45,10 @@ func SlimAccount(nonce uint64, balance *big.Int, root common.Hash, codehash []by
Upload: upload,
Num: num,
}
if root != emptyRoot {
if root != types.EmptyRootHash {
slim.Root = root[:]
}
if !bytes.Equal(codehash, emptyCode[:]) {
if !bytes.Equal(codehash, types.EmptyCodeHash[:]) {
slim.CodeHash = codehash
}
return slim
Expand All @@ -71,10 +72,10 @@ func FullAccount(data []byte) (Account, error) {
return Account{}, err
}
if len(account.Root) == 0 {
account.Root = emptyRoot[:]
account.Root = types.EmptyRootHash[:]
}
if len(account.CodeHash) == 0 {
account.CodeHash = emptyCode[:]
account.CodeHash = types.EmptyCodeHash[:]
}
return account, nil
}
Expand Down
12 changes: 2 additions & 10 deletions core/state/snapshot/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,14 @@ import (
"github.com/CortexFoundation/CortexTheseus/common"
"github.com/CortexFoundation/CortexTheseus/common/math"
"github.com/CortexFoundation/CortexTheseus/core/rawdb"
"github.com/CortexFoundation/CortexTheseus/crypto"
"github.com/CortexFoundation/CortexTheseus/core/types"
"github.com/CortexFoundation/CortexTheseus/ctxcdb"
"github.com/CortexFoundation/CortexTheseus/log"
"github.com/CortexFoundation/CortexTheseus/rlp"
"github.com/CortexFoundation/CortexTheseus/trie"
"github.com/VictoriaMetrics/fastcache"
)

var (
// emptyRoot is the known root hash of an empty trie.
emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")

// emptyCode is the known hash of the empty CVM bytecode.
emptyCode = crypto.Keccak256Hash(nil)
)

// generatorStats is a collection of statistics gathered by the snapshot generator
// for logging purposes.
type generatorStats struct {
Expand Down Expand Up @@ -246,7 +238,7 @@ func (dl *diskLayer) generate(stats *generatorStats) {
}
}
// If the account is in-progress, continue where we left off (otherwise iterate all)
if acc.Root != emptyRoot {
if acc.Root != types.EmptyRootHash {
storeTrie, err := trie.NewSecure(acc.Root, dl.triedb)
if err != nil {
log.Error("Generator failed to access storage trie", "root", dl.root, "hash", common.BytesToHash(accIt.Key), "root", acc.Root, "err", err)
Expand Down
3 changes: 2 additions & 1 deletion core/state/snapshot/snapshot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (

"github.com/CortexFoundation/CortexTheseus/common"
"github.com/CortexFoundation/CortexTheseus/core/rawdb"
"github.com/CortexFoundation/CortexTheseus/core/types"
"github.com/CortexFoundation/CortexTheseus/rlp"
"github.com/VictoriaMetrics/fastcache"
)
Expand All @@ -46,7 +47,7 @@ func randomAccount() []byte {
Balance: big.NewInt(rand.Int63()),
Nonce: rand.Uint64(),
Root: root[:],
CodeHash: emptyCode[:],
CodeHash: types.EmptyCodeHash[:],
}
data, _ := rlp.EncodeToBytes(a)
return data
Expand Down
105 changes: 62 additions & 43 deletions core/state/state_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ func (s Storage) Copy() Storage {
// Finally, call CommitTrie to write the modified storage trie into a database.
type stateObject struct {
address common.Address
addrHash common.Hash // hash of cortex address of the account
addrHash common.Hash // hash of cortex address of the account
origin *types.StateAccount // Account original data without any change applied, nil means it was not existent
data types.StateAccount
db *StateDB

Expand Down Expand Up @@ -100,30 +101,18 @@ func (s *stateObject) empty() bool {
}

// newObject creates a state object.
func newObject(db *StateDB, address common.Address, data types.StateAccount) *stateObject {
if data.Balance == nil {
data.Balance = new(big.Int)
}
if data.Upload == nil {
data.Upload = new(big.Int)
}

if data.Num == nil {
data.Num = new(big.Int)
}
if data.CodeHash == nil {
data.CodeHash = emptyCodeHash
}

if data.Root == (common.Hash{}) {
data.Root = emptyRoot
func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *stateObject {
origin := acct
if acct == nil {
acct = types.NewEmptyStateAccount()
}

return &stateObject{
db: db,
address: address,
addrHash: crypto.Keccak256Hash(address[:]),
data: data,
origin: origin,
data: *acct,
originStorage: make(Storage),
pendingStorage: make(Storage),
dirtyStorage: make(Storage),
Expand Down Expand Up @@ -296,17 +285,21 @@ func (s *stateObject) updateTrie(db Database) Trie {
defer func(start time.Time) { s.db.StorageUpdates += time.Since(start) }(time.Now())
}
// The snapshot storage map for the object
var storage map[common.Hash][]byte
var (
storage map[common.Hash][]byte
origin map[common.Hash][]byte
hasher = s.db.hasher
)
// Insert all the pending updates into the trie
tr := s.getTrie(db)
hasher := s.db.hasher

usedStorage := make([][]byte, 0, len(s.pendingStorage))
for key, value := range s.pendingStorage {
// Skip noop changes, persist actual changes
if value == s.originStorage[key] {
continue
}
prev := s.originStorage[key]
s.originStorage[key] = value

var v []byte
Expand All @@ -318,17 +311,34 @@ func (s *stateObject) updateTrie(db Database) Trie {
v, _ = rlp.EncodeToBytes(common.TrimLeftZeroes(value[:]))
s.setError(tr.TryUpdate(key[:], v))
}
// If state snapshotting is active, cache the data til commit
if s.db.snap != nil {
if storage == nil {
// Retrieve the old storage map, if available, create a new one otherwise
if storage = s.db.snapStorage[s.addrHash]; storage == nil {
storage = make(map[common.Hash][]byte)
s.db.snapStorage[s.addrHash] = storage
}
// Cache the mutated storage slots until commit
if storage == nil {
if storage = s.db.storages[s.addrHash]; storage == nil {
storage = make(map[common.Hash][]byte)
s.db.storages[s.addrHash] = storage
}
}
khash := crypto.HashData(hasher, key[:])
storage[khash] = v // snapshotVal will be nil if it's deleted

// Cache the original value of mutated storage slots
if origin == nil {
if origin = s.db.storagesOrigin[s.addrHash]; origin == nil {
origin = make(map[common.Hash][]byte)
s.db.storagesOrigin[s.addrHash] = origin
}
storage[crypto.HashData(hasher, key[:])] = v // v will be nil if value is 0x00
}
// Track the original value of slot only if it's mutated first time
if _, ok := origin[khash]; !ok {
if prev == (common.Hash{}) {
origin[khash] = nil // nil if it was not present previously
} else {
// Encoding []byte cannot fail, ok to ignore the error.
b, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(prev[:]))
origin[khash] = b
}
}
// Cache the items for preloading
usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure
}
if s.db.prefetcher != nil {
Expand All @@ -349,10 +359,11 @@ func (s *stateObject) updateRoot(db Database) {
s.data.Root = s.trie.Hash()
}

// CommitTrie the storage trie of the object to db.
// commit the storage trie of the object to db.
// This updates the trie root.
func (s *stateObject) CommitTrie(db Database) error {
func (s *stateObject) commit(db Database) error {
if s.updateTrie(db) == nil {
s.origin = s.data.Copy()
return nil
}
if s.dbErr != nil {
Expand All @@ -361,6 +372,8 @@ func (s *stateObject) CommitTrie(db Database) error {
root, err := s.trie.Commit(nil)
if err == nil {
s.data.Root = root
// Update original account data after commit
s.origin = s.data.Copy()
}
return err
}
Expand Down Expand Up @@ -452,18 +465,24 @@ func (s *stateObject) setUpload(amount *big.Int) {
func (s *stateObject) ReturnGas(gas *big.Int) {}

func (s *stateObject) deepCopy(db *StateDB) *stateObject {
stateObject := newObject(db, s.address, s.data)
obj := &stateObject{
db: db,
address: s.address,
addrHash: s.addrHash,
origin: s.origin,
data: s.data,
}
if s.trie != nil {
stateObject.trie = db.db.CopyTrie(s.trie)
}
stateObject.code = s.code
stateObject.dirtyStorage = s.dirtyStorage.Copy()
stateObject.originStorage = s.originStorage.Copy()
stateObject.pendingStorage = s.pendingStorage.Copy()
stateObject.suicided = s.suicided
stateObject.dirtyCode = s.dirtyCode
stateObject.deleted = s.deleted
return stateObject
obj.trie = db.db.CopyTrie(s.trie)
}
obj.code = s.code
obj.dirtyStorage = s.dirtyStorage.Copy()
obj.originStorage = s.originStorage.Copy()
obj.pendingStorage = s.pendingStorage.Copy()
obj.suicided = s.suicided
obj.dirtyCode = s.dirtyCode
obj.deleted = s.deleted
return obj
}

//
Expand Down
Loading