Skip to content

Commit

Permalink
Feat: TxDAG: support TxDAG
Browse files Browse the repository at this point in the history
rwset: support collect rwset from statedb;
mvstates: support export DAG;
dag: support travel all execution paths;
dag: refactor versioned TxDAG;
dag: support profile parallel execution path;
protocol: support to transfer TxDAG in NewBLock msg;

PR: bnb-chain#4
  • Loading branch information
galaio authored and sunny2022da committed Aug 13, 2024
1 parent 89f61e2 commit 3c6f2c2
Show file tree
Hide file tree
Showing 17 changed files with 1,525 additions and 58 deletions.
6 changes: 6 additions & 0 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,12 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
return ancestorErr
}

// TODO(galaio): add more TxDAG hash when TxDAG in consensus, txDAG check here
if len(block.TxDAG()) > 0 {
if _, err := types.DecodeTxDAG(block.TxDAG()); err != nil {
return errors.New("wrong TxDAG in block body")
}
}
return nil
}

Expand Down
9 changes: 9 additions & 0 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1924,6 +1924,15 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
return it.index, err
}

// TODO(galaio): use txDAG in some accelerate scenarios.
if len(block.TxDAG()) > 0 {
txDAG, err := types.DecodeTxDAG(block.TxDAG())
if err != nil {
return it.index, err
}
log.Info("Insert chain", "block", block.NumberU64(), "txDAG", txDAG)
}

// Enable prefetching to pull in trie node paths while processing transactions
statedb.StartPrefetcher("chain")
activeState = statedb
Expand Down
2 changes: 1 addition & 1 deletion core/chain_makers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ func ExampleGenerateChain() {
db = rawdb.NewMemoryDatabase()
genDb = rawdb.NewMemoryDatabase()
)

// Ensure that key1 has some funds in the genesis block.
gspec := &Genesis{
Config: &params.ChainConfig{HomesteadBlock: new(big.Int)},
Expand Down
5 changes: 3 additions & 2 deletions core/state/journal.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ package state

import (
"fmt"
"github.com/ethereum/go-ethereum/common"
"math/big"

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

// journalEntry is a modification entry in the state change journal that can be
Expand Down Expand Up @@ -189,7 +190,7 @@ func (ch resetObjectChange) revert(dber StateDBer) {

if !ch.prevdestruct {
s.snapParallelLock.Lock()
delete(s.stateObjectsDestruct, ch.prev.address)
s.deleteStateObjectsDestruct(ch.prev.address)
s.snapParallelLock.Unlock()
}
if ch.prevAccount != nil {
Expand Down
81 changes: 75 additions & 6 deletions core/state/state_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"time"

"github.com/ethereum/go-ethereum/core/opcodeCompiler/compiler"
"golang.org/x/exp/slices"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -156,6 +157,11 @@ type stateObject struct {
origin *types.StateAccount // Account original data without any change applied, nil means it was not existent
data types.StateAccount // Account data with all mutations applied in the scope of block

// dirty account state
dirtyBalance *big.Int
dirtyNonce *uint64
dirtyCodeHash []byte

// Write caches.
trie Trie // storage trie, which becomes non-nil on first access
code Code // contract bytecode, which gets set when code is loaded
Expand Down Expand Up @@ -242,7 +248,7 @@ func newObject(dbItf StateDBer, isParallel bool, address common.Address, acct *t
if acct == nil {
acct = types.NewEmptyStateAccount()
}
return &stateObject{
s := &stateObject{
db: db,
dbItf: dbItf,
address: address,
Expand All @@ -255,6 +261,15 @@ func newObject(dbItf StateDBer, isParallel bool, address common.Address, acct *t
dirtyStorage: newStorage(isParallel),
created: created,
}

// dirty data when create a new account
if acct == nil {
s.dirtyBalance = new(big.Int).Set(acct.Balance)
s.dirtyNonce = new(uint64)
*s.dirtyNonce = acct.Nonce
s.dirtyCodeHash = acct.CodeHash
}
return s
}

// EncodeRLP implements rlp.Encoder.
Expand Down Expand Up @@ -345,7 +360,7 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
// 2) we don't have new values, and can deliver empty response back
//if _, destructed := s.db.stateObjectsDestruct[s.address]; destructed {
s.db.snapParallelLock.RLock()
if _, destructed := s.db.stateObjectsDestruct[s.address]; destructed { // fixme: use sync.Map, instead of RWMutex?
if _, destructed := s.db.queryStateObjectsDestruct(s.address); destructed { // fixme: use sync.Map, instead of RWMutex?
s.db.snapParallelLock.RUnlock()
return common.Hash{}
}
Expand Down Expand Up @@ -438,6 +453,18 @@ func (s *stateObject) finalise(prefetch bool) {
}
return true
})
if s.dirtyNonce != nil {
s.data.Nonce = *s.dirtyNonce
s.dirtyNonce = nil
}
if s.dirtyBalance != nil {
s.data.Balance = s.dirtyBalance
s.dirtyBalance = nil
}
if s.dirtyCodeHash != nil {
s.data.CodeHash = s.dirtyCodeHash
s.dirtyCodeHash = nil
}
if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash {
s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch)
}
Expand All @@ -446,6 +473,28 @@ func (s *stateObject) finalise(prefetch bool) {
}
}

func (s *stateObject) finaliseRWSet() {
s.dirtyStorage.Range(func(key, value interface{}) bool {
// three are some unclean dirtyStorage from previous reverted txs, it will skip finalise
// so add a new rule, if val has no change, then skip it
if value == s.GetCommittedState(key.(common.Hash)) {
return true
}
s.db.RecordWrite(types.StorageStateKey(s.address, key.(common.Hash)), value.(common.Hash))
return true
})

if s.dirtyNonce != nil && *s.dirtyNonce != s.data.Nonce {
s.db.RecordWrite(types.AccountStateKey(s.address, types.AccountNonce), *s.dirtyNonce)
}
if s.dirtyBalance != nil && s.dirtyBalance.Cmp(s.data.Balance) != 0 {
s.db.RecordWrite(types.AccountStateKey(s.address, types.AccountBalance), new(big.Int).Set(s.dirtyBalance))
}
if s.dirtyCodeHash != nil && !slices.Equal(s.dirtyCodeHash, s.data.CodeHash) {
s.db.RecordWrite(types.AccountStateKey(s.address, types.AccountCodeHash), s.dirtyCodeHash)
}
}

// updateTrie is responsible for persisting cached storage changes into the
// object's storage trie. In case the storage trie is not yet loaded, this
// function will load the trie automatically. If any issues arise during the
Expand Down Expand Up @@ -644,13 +693,13 @@ func (s *stateObject) SubBalance(amount *big.Int) {
func (s *stateObject) SetBalance(amount *big.Int) {
s.db.journal.append(balanceChange{
account: &s.address,
prev: new(big.Int).Set(s.data.Balance),
prev: new(big.Int).Set(s.Balance()),
})
s.setBalance(amount)
}

func (s *stateObject) setBalance(amount *big.Int) {
s.data.Balance = amount
s.dirtyBalance = amount
}

// ReturnGas Return the gas back to the origin. Used by the Virtual machine or Closures
Expand Down Expand Up @@ -715,6 +764,17 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject {
obj.selfDestructed = s.selfDestructed
obj.dirtyCode = s.dirtyCode
obj.deleted = s.deleted

// dirty states
if s.dirtyNonce != nil {
obj.dirtyNonce = new(uint64)
*obj.dirtyNonce = *s.dirtyNonce
}
if s.dirtyBalance != nil {
obj.dirtyBalance = new(big.Int).Set(s.dirtyBalance)
}
obj.dirtyCodeHash = s.dirtyCodeHash

return obj
}

Expand Down Expand Up @@ -784,7 +844,7 @@ func (s *stateObject) SetCode(codeHash common.Hash, code []byte) {

func (s *stateObject) setCode(codeHash common.Hash, code []byte) {
s.code = code
s.data.CodeHash = codeHash[:]
s.dirtyCodeHash = codeHash[:]
s.dirtyCode = true
compiler.GenOrLoadOptimizedCode(codeHash, s.code)
}
Expand All @@ -799,18 +859,27 @@ func (s *stateObject) SetNonce(nonce uint64) {
}

func (s *stateObject) setNonce(nonce uint64) {
s.data.Nonce = nonce
s.dirtyNonce = &nonce
}

func (s *stateObject) CodeHash() []byte {
if len(s.dirtyCodeHash) > 0 {
return s.dirtyCodeHash
}
return s.data.CodeHash
}

func (s *stateObject) Balance() *big.Int {
if s.dirtyBalance != nil {
return s.dirtyBalance
}
return s.data.Balance
}

func (s *stateObject) Nonce() uint64 {
if s.dirtyNonce != nil {
return *s.dirtyNonce
}
return s.data.Nonce
}

Expand Down
Loading

0 comments on commit 3c6f2c2

Please sign in to comment.