Skip to content

Commit

Permalink
Added QuaiStateSize field into the header and computing it
Browse files Browse the repository at this point in the history
  • Loading branch information
gameofpointers committed Aug 23, 2024
1 parent 945631c commit 2636960
Show file tree
Hide file tree
Showing 22 changed files with 480 additions and 421 deletions.
1 change: 1 addition & 0 deletions consensus/blake3pow/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,7 @@ func (blake3pow *Blake3pow) Finalize(chain consensus.ChainHeaderReader, header *
header.Header().SetUTXORoot(state.UTXORoot())
header.Header().SetEVMRoot(state.IntermediateRoot(true))
header.Header().SetEtxSetRoot(state.ETXRoot())
header.Header().SetQuaiStateSize(state.GetQuaiTrieSize())
}

// FinalizeAndAssemble implements consensus.Engine, accumulating the block and
Expand Down
1 change: 1 addition & 0 deletions consensus/progpow/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,7 @@ func (progpow *Progpow) Finalize(chain consensus.ChainHeaderReader, header *type
header.Header().SetUTXORoot(state.UTXORoot())
header.Header().SetEVMRoot(state.IntermediateRoot(true))
header.Header().SetEtxSetRoot(state.ETXRoot())
header.Header().SetQuaiStateSize(state.GetQuaiTrieSize())
}

// FinalizeAndAssemble implements consensus.Engine, accumulating the block and
Expand Down
3 changes: 3 additions & 0 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,9 @@ func (v *BlockValidator) ValidateState(block *types.WorkObject, statedb *state.S
if root := statedb.IntermediateRoot(true); header.EVMRoot() != root {
return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.EVMRoot(), root)
}
if stateSize := statedb.GetQuaiTrieSize(); header.QuaiStateSize().Cmp(stateSize) != 0 {
return fmt.Errorf("invalid quai trie size (remote: %x local: %x)", header.QuaiStateSize(), stateSize)
}
if root := statedb.UTXORoot(); header.UTXORoot() != root {
return fmt.Errorf("invalid utxo root (remote: %x local: %x)", header.UTXORoot(), root)
}
Expand Down
7 changes: 4 additions & 3 deletions core/chain_indexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"encoding/binary"
"fmt"
"math/big"
"runtime/debug"
"sync"
"sync/atomic"
Expand Down Expand Up @@ -66,7 +67,7 @@ type ChainIndexerChain interface {
// NodeCtx returns the context of the chain
NodeCtx() int
// StateAt returns the state for a state trie root and utxo root
StateAt(root common.Hash, utxoRoot common.Hash, etxRoot common.Hash) (*state.StateDB, error)
StateAt(root common.Hash, utxoRoot common.Hash, etxRoot common.Hash, quaiStateSize *big.Int) (*state.StateDB, error)
}

// ChainIndexer does a post-processing job for equally sized sections of the
Expand All @@ -84,7 +85,7 @@ type ChainIndexer struct {
backend ChainIndexerBackend // Background processor generating the index data content
children []*ChainIndexer // Child indexers to cascade chain updates to
GetBloom func(common.Hash) (*types.Bloom, error)
StateAt func(common.Hash, common.Hash, common.Hash) (*state.StateDB, error)
StateAt func(common.Hash, common.Hash, common.Hash, *big.Int) (*state.StateDB, error)
active uint32 // Flag whether the event loop was started
update chan struct{} // Notification channel that headers should be processed
quit chan chan error // Quit channel to tear down running goroutines
Expand Down Expand Up @@ -652,7 +653,7 @@ func (c *ChainIndexer) reorgUtxoIndexer(headers []*types.WorkObject, addressOutp

parent := rawdb.ReadHeader(c.chainDb, block.ParentHash(nodeCtx))

state, err := c.StateAt(parent.EVMRoot(), parent.UTXORoot(), parent.EtxSetRoot())
state, err := c.StateAt(parent.EVMRoot(), parent.UTXORoot(), parent.EtxSetRoot(), parent.QuaiStateSize())
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -1139,8 +1139,8 @@ func (c *Core) State() (*state.StateDB, error) {
}

// StateAt returns a new mutable state based on a particular point in time.
func (c *Core) StateAt(root, utxoRoot, etxRoot common.Hash) (*state.StateDB, error) {
return c.sl.hc.bc.processor.StateAt(root, utxoRoot, etxRoot)
func (c *Core) StateAt(root, utxoRoot, etxRoot common.Hash, quaiStateSize *big.Int) (*state.StateDB, error) {
return c.sl.hc.bc.processor.StateAt(root, utxoRoot, etxRoot, quaiStateSize)
}

// StateCache returns the caching database underpinning the blockchain instance.
Expand Down
2 changes: 1 addition & 1 deletion core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, nodeLoca
// We have the genesis block in database(perhaps in ancient database)
// but the corresponding state is missing.
header := rawdb.ReadHeader(db, stored)
if _, err := state.New(header.EVMRoot(), header.UTXORoot(), header.EtxSetRoot(), state.NewDatabaseWithConfig(db, nil), state.NewDatabaseWithConfig(db, nil), state.NewDatabaseWithConfig(db, nil), nil, nodeLocation, logger); err != nil {
if _, err := state.New(header.EVMRoot(), header.UTXORoot(), header.EtxSetRoot(), header.QuaiStateSize(), state.NewDatabaseWithConfig(db, nil), state.NewDatabaseWithConfig(db, nil), state.NewDatabaseWithConfig(db, nil), nil, nodeLocation, logger); err != nil {
if genesis == nil {
genesis = DefaultGenesisBlock()
}
Expand Down
4 changes: 2 additions & 2 deletions core/headerchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -958,8 +958,8 @@ func (hc *HeaderChain) SubscribeChainSideEvent(ch chan<- ChainSideEvent) event.S
return hc.scope.Track(hc.chainSideFeed.Subscribe(ch))
}

func (hc *HeaderChain) StateAt(root, utxoRoot, etxRoot common.Hash) (*state.StateDB, error) {
return hc.bc.processor.StateAt(root, utxoRoot, etxRoot)
func (hc *HeaderChain) StateAt(root, utxoRoot, etxRoot common.Hash, quaiStateSize *big.Int) (*state.StateDB, error) {
return hc.bc.processor.StateAt(root, utxoRoot, etxRoot, quaiStateSize)
}

func (hc *HeaderChain) SlicesRunning() []common.Location {
Expand Down
1 change: 1 addition & 0 deletions core/slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -1405,6 +1405,7 @@ func (sl *Slice) combinePendingHeader(header *types.WorkObject, slPendingHeader

combinedPendingHeader.Header().SetEtxRollupHash(header.EtxRollupHash())
combinedPendingHeader.Header().SetUncledS(header.Header().UncledS())
combinedPendingHeader.Header().SetQuaiStateSize(header.Header().QuaiStateSize())
combinedPendingHeader.Header().SetUncleHash(header.UncleHash())
combinedPendingHeader.Header().SetTxHash(header.Header().TxHash())
combinedPendingHeader.Header().SetEtxHash(header.EtxHash())
Expand Down
4 changes: 2 additions & 2 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ type StateDB struct {
}

// New creates a new state from a given trie.
func New(root common.Hash, utxoRoot common.Hash, etxRoot common.Hash, db Database, utxoDb Database, etxDb Database, snaps *snapshot.Tree, nodeLocation common.Location, logger *log.Logger) (*StateDB, error) {
func New(root common.Hash, utxoRoot common.Hash, etxRoot common.Hash, quaiStateSize *big.Int, db Database, utxoDb Database, etxDb Database, snaps *snapshot.Tree, nodeLocation common.Location, logger *log.Logger) (*StateDB, error) {
tr, err := db.OpenTrie(root)
if err != nil {
return nil, err
Expand All @@ -186,7 +186,7 @@ func New(root common.Hash, utxoRoot common.Hash, etxRoot common.Hash, db Databas
etxTrie: etxTr,
originalRoot: root,
snaps: snaps,
size: common.Big0, // TODO: this needs to be store for each block or commited to in the state
size: quaiStateSize,
newAccountsAdded: make(map[common.AddressBytes]bool),
logger: logger,
stateObjects: make(map[common.InternalAddress]*stateObject),
Expand Down
16 changes: 8 additions & 8 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty
parentEtxSetRoot = types.EmptyRootHash
}
// Initialize a statedb
statedb, err := state.New(parentEvmRoot, parentUtxoRoot, parentEtxSetRoot, p.stateCache, p.utxoCache, p.etxCache, p.snaps, nodeLocation, p.logger)
statedb, err := state.New(parentEvmRoot, parentUtxoRoot, parentEtxSetRoot, parent.QuaiStateSize(), p.stateCache, p.utxoCache, p.etxCache, p.snaps, nodeLocation, p.logger)
if err != nil {
return types.Receipts{}, []*types.Transaction{}, []*types.Log{}, nil, 0, err
}
Expand Down Expand Up @@ -1307,12 +1307,12 @@ func (p *StateProcessor) GetVMConfig() *vm.Config {

// State returns a new mutable state based on the current HEAD block.
func (p *StateProcessor) State() (*state.StateDB, error) {
return p.StateAt(p.hc.CurrentHeader().EVMRoot(), p.hc.CurrentHeader().UTXORoot(), p.hc.CurrentHeader().EtxSetRoot())
return p.StateAt(p.hc.CurrentHeader().EVMRoot(), p.hc.CurrentHeader().UTXORoot(), p.hc.CurrentHeader().EtxSetRoot(), p.hc.CurrentHeader().QuaiStateSize())
}

// StateAt returns a new mutable state based on a particular point in time.
func (p *StateProcessor) StateAt(root, utxoRoot, etxRoot common.Hash) (*state.StateDB, error) {
return state.New(root, utxoRoot, etxRoot, p.stateCache, p.utxoCache, p.etxCache, p.snaps, p.hc.NodeLocation(), p.logger)
func (p *StateProcessor) StateAt(root, utxoRoot, etxRoot common.Hash, quaiStateSize *big.Int) (*state.StateDB, error) {
return state.New(root, utxoRoot, etxRoot, quaiStateSize, p.stateCache, p.utxoCache, p.etxCache, p.snaps, p.hc.NodeLocation(), p.logger)
}

// StateCache returns the caching database underpinning the blockchain instance.
Expand Down Expand Up @@ -1419,7 +1419,7 @@ func (p *StateProcessor) StateAtBlock(block *types.WorkObject, reexec uint64, ba
)
// Check the live database first if we have the state fully available, use that.
if checkLive {
statedb, err = p.StateAt(block.EVMRoot(), block.UTXORoot(), block.EtxSetRoot())
statedb, err = p.StateAt(block.EVMRoot(), block.UTXORoot(), block.EtxSetRoot(), block.QuaiStateSize())
if err == nil {
return statedb, nil
}
Expand Down Expand Up @@ -1448,7 +1448,7 @@ func (p *StateProcessor) StateAtBlock(block *types.WorkObject, reexec uint64, ba
// we would rewind past a persisted block (specific corner case is chain
// tracing from the genesis).
if !checkLive {
statedb, err = state.New(current.EVMRoot(), current.UTXORoot(), current.EtxSetRoot(), database, utxoDatabase, etxDatabase, nil, nodeLocation, p.logger)
statedb, err = state.New(current.EVMRoot(), current.UTXORoot(), current.EtxSetRoot(), current.QuaiStateSize(), database, utxoDatabase, etxDatabase, nil, nodeLocation, p.logger)
if err == nil {
return statedb, nil
}
Expand All @@ -1465,7 +1465,7 @@ func (p *StateProcessor) StateAtBlock(block *types.WorkObject, reexec uint64, ba
}
current = types.CopyWorkObject(parent)

statedb, err = state.New(current.EVMRoot(), current.UTXORoot(), current.EtxSetRoot(), database, utxoDatabase, etxDatabase, nil, nodeLocation, p.logger)
statedb, err = state.New(current.EVMRoot(), current.UTXORoot(), current.EtxSetRoot(), current.QuaiStateSize(), database, utxoDatabase, etxDatabase, nil, nodeLocation, p.logger)
if err == nil {
break
}
Expand Down Expand Up @@ -1522,7 +1522,7 @@ func (p *StateProcessor) StateAtBlock(block *types.WorkObject, reexec uint64, ba
return nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w",
current.NumberU64(nodeCtx), current.EVMRoot().Hex(), err)
}
statedb, err = state.New(root, utxoRoot, etxRoot, database, utxoDatabase, etxDatabase, nil, nodeLocation, p.logger)
statedb, err = state.New(root, utxoRoot, etxRoot, currentBlock.QuaiStateSize(), database, utxoDatabase, etxDatabase, nil, nodeLocation, p.logger)
if err != nil {
return nil, fmt.Errorf("state reset after block %d failed: %v", current.NumberU64(nodeCtx), err)
}
Expand Down
6 changes: 4 additions & 2 deletions core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ const (
type blockChain interface {
CurrentBlock() *types.WorkObject
GetBlock(hash common.Hash, number uint64) *types.WorkObject
StateAt(root, utxoRoot, etxRoot common.Hash) (*state.StateDB, error)
StateAt(root, utxoRoot, etxRoot common.Hash, quaiStateSize *big.Int) (*state.StateDB, error)
SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription
IsGenesisHash(hash common.Hash) bool
CheckIfEtxIsEligible(hash common.Hash, location common.Location) bool
Expand Down Expand Up @@ -1831,12 +1831,14 @@ func (pool *TxPool) reset(oldHead, newHead *types.WorkObject) {
evmRoot := newHead.EVMRoot()
utxoRoot := newHead.UTXORoot()
etxRoot := newHead.EtxSetRoot()
quaiStateSize := newHead.QuaiStateSize()
if pool.chain.IsGenesisHash(newHead.Hash()) {
evmRoot = types.EmptyRootHash
utxoRoot = types.EmptyRootHash
etxRoot = types.EmptyRootHash
quaiStateSize = big.NewInt(0)
}
statedb, err := pool.chain.StateAt(evmRoot, utxoRoot, etxRoot)
statedb, err := pool.chain.StateAt(evmRoot, utxoRoot, etxRoot, quaiStateSize)
if err != nil {
pool.logger.WithField("err", err).Error("Failed to reset txpool state")
return
Expand Down
18 changes: 18 additions & 0 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ type Header struct {
uncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
evmRoot common.Hash `json:"evmRoot" gencodec:"required"`
utxoRoot common.Hash `json:"utxoRoot" gencodec:"required"`
quaiStateSize *big.Int `json:"quaiStateSize" gencodec:"required"`
txHash common.Hash `json:"transactionsRoot" gencodec:"required"`
etxHash common.Hash `json:"extTransactionsRoot" gencodec:"required"`
etxSetRoot common.Hash `json:"etxSetRoot" gencodec:"required"`
Expand Down Expand Up @@ -148,6 +149,7 @@ func EmptyHeader() *Header {
h.uncledS = big.NewInt(0)
h.evmRoot = EmptyRootHash
h.utxoRoot = EmptyRootHash
h.quaiStateSize = big.NewInt(0)
h.txHash = EmptyRootHash
h.etxHash = EmptyRootHash
h.etxSetRoot = EmptyRootHash
Expand Down Expand Up @@ -231,6 +233,7 @@ func (h *Header) ProtoEncode() (*ProtoHeader, error) {
TxHash: &txHash,
EtxHash: &etxhash,
EtxSetRoot: &etxSetRoot,
QuaiStateSize: h.QuaiStateSize().Bytes(),
EtxRollupHash: &etxRollupHash,
ReceiptHash: &receiptHash,
PrimeTerminus: &primeTerminus,
Expand Down Expand Up @@ -341,6 +344,9 @@ func (h *Header) ProtoDecode(protoHeader *ProtoHeader, location common.Location)
if protoHeader.PrimeTerminus == nil {
return errors.New("missing required field 'PrimeTerminus' in Header")
}
if protoHeader.QuaiStateSize == nil {
return errors.New("missing required field 'QuaiStateSize' in Header")
}

// Initialize the array fields before setting
h.parentHash = make([]common.Hash, common.HierarchyDepth-1)
Expand All @@ -363,6 +369,7 @@ func (h *Header) ProtoDecode(protoHeader *ProtoHeader, location common.Location)

h.SetUncleHash(common.BytesToHash(protoHeader.GetUncleHash().GetValue()))
h.SetEVMRoot(common.BytesToHash(protoHeader.GetEvmRoot().GetValue()))
h.SetQuaiStateSize(new(big.Int).SetBytes(protoHeader.GetQuaiStateSize()))
h.SetUTXORoot(common.BytesToHash(protoHeader.GetUtxoRoot().GetValue()))
h.SetTxHash(common.BytesToHash(protoHeader.GetTxHash().GetValue()))
h.SetReceiptHash(common.BytesToHash(protoHeader.GetReceiptHash().GetValue()))
Expand Down Expand Up @@ -399,6 +406,7 @@ func (h *Header) RPCMarshalHeader() map[string]interface{} {
"hash": h.Hash(),
"parentHash": h.ParentHashArray(),
"uncledS": (*hexutil.Big)(h.UncledS()),
"quaiStateSize": (*hexutil.Big)(h.QuaiStateSize()),
"sha3Uncles": h.UncleHash(),
"evmRoot": h.EVMRoot(),
"utxoRoot": h.UTXORoot(),
Expand Down Expand Up @@ -462,6 +470,9 @@ func (h *Header) EVMRoot() common.Hash {
func (h *Header) UTXORoot() common.Hash {
return h.utxoRoot
}
func (h *Header) QuaiStateSize() *big.Int {
return h.quaiStateSize
}
func (h *Header) TxHash() common.Hash {
return h.txHash
}
Expand Down Expand Up @@ -544,6 +555,11 @@ func (h *Header) SetEVMRoot(val common.Hash) {
h.sealHash = atomic.Value{} // clear sealHash cache
h.evmRoot = val
}
func (h *Header) SetQuaiStateSize(val *big.Int) {
h.hash = atomic.Value{} // clear hash cache
h.sealHash = atomic.Value{} // clear sealHash cache
h.quaiStateSize = val
}
func (h *Header) SetUTXORoot(val common.Hash) {
h.hash = atomic.Value{} // clear hash cache
h.sealHash = atomic.Value{} // clear sealHash cache
Expand Down Expand Up @@ -710,6 +726,7 @@ func (h *Header) SealEncode() *ProtoHeader {
ReceiptHash: &receiptHash,
GasLimit: &gasLimit,
GasUsed: &gasUsed,
QuaiStateSize: h.QuaiStateSize().Bytes(),
BaseFee: h.BaseFee().Bytes(),
StateLimit: &stateLimit,
StateUsed: &stateUsed,
Expand Down Expand Up @@ -881,6 +898,7 @@ func CopyHeader(h *Header) *Header {
cpy.SetParentHash(h.ParentHash(i), i)
cpy.SetNumber(h.Number(i), i)
}
cpy.SetQuaiStateSize(h.QuaiStateSize())
cpy.SetUncledS(h.UncledS())
cpy.SetUncleHash(h.UncleHash())
cpy.SetEVMRoot(h.EVMRoot())
Expand Down
8 changes: 7 additions & 1 deletion core/types/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func headerTestData() (*Header, common.Hash) {
parentHash: []common.Hash{common.HexToHash("0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0"), common.HexToHash("0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0")},
uncleHash: common.HexToHash("0x23456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef1"),
evmRoot: common.HexToHash("0x456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef3"),
quaiStateSize: big.NewInt(1000),
utxoRoot: common.HexToHash("0x56789abcdef0123456789abcdef0123456789abcdef0123456789abcdef4"),
txHash: common.HexToHash("0x6789abcdef0123456789abcdef0123456789abcdef0123456789abcdef5"),
etxHash: common.HexToHash("0x789abcdef0123456789abcdef0123456789abcdef0123456789abcdef6"),
Expand Down Expand Up @@ -66,7 +67,7 @@ func headerTestData() (*Header, common.Hash) {

func TestHeaderHash(t *testing.T) {
_, hash := headerTestData()
correctHash := common.HexToHash("0x89d7716b39e330a7532700c919b83e9d699f41823adf2bd97a64c3f98d560457")
correctHash := common.HexToHash("0xc8110a0bb8fe2f98081d1202ce0dcf299dc42a14df271a994e1925c78931177b")
require.Equal(t, hash, correctHash, "Hash not equal to expected hash")
}

Expand Down Expand Up @@ -303,6 +304,11 @@ func FuzzHeaderStateUsedHash(f *testing.F) {
func(h *Header) uint64 { return h.stateUsed },
func(h *Header, bi uint64) { h.stateUsed = bi })
}
func FuzzHeaderQuaiStateSize(f *testing.F) {
fuzzHeaderBigIntHash(f,
func(h *Header) *big.Int { return h.quaiStateSize },
func(h *Header, bi *big.Int) { h.quaiStateSize = bi })
}
func FuzzHeaderExtraHash(f *testing.F) {
header, _ := headerTestData()
f.Add(testByte)
Expand Down
7 changes: 7 additions & 0 deletions core/types/gen_header_json.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 2636960

Please sign in to comment.