Skip to content

Commit

Permalink
Moved ETX Set to FIFO PMT with header commitment
Browse files Browse the repository at this point in the history
  • Loading branch information
jdowning100 committed Apr 25, 2024
1 parent f3df01c commit 40640d8
Show file tree
Hide file tree
Showing 24 changed files with 393 additions and 260 deletions.
4 changes: 4 additions & 0 deletions common/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -403,3 +403,7 @@ func (a AddressBytes) IsInQuaiLedgerScope() bool {
func MakeErrQiAddress(addr string) error {
return fmt.Errorf("address %s is in Qi ledger scope and is not in Quai ledger scope", addr)
}

func (a Address) MixedcaseAddress() MixedcaseAddress {
return NewMixedcaseAddress(a)
}
1 change: 1 addition & 0 deletions consensus/blake3pow/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,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())
}

// 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 @@ -618,6 +618,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())
}

// FinalizeAndAssemble implements consensus.Engine, accumulating the block and
Expand Down
18 changes: 4 additions & 14 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ func (v *BlockValidator) ValidateBody(block *types.WorkObject) error {
// transition, such as amount of used gas, the receipt roots and the state root
// itself. ValidateState returns a database batch if the validation was a success
// otherwise nil and an error is returned.
func (v *BlockValidator) ValidateState(block *types.WorkObject, statedb *state.StateDB, receipts types.Receipts, utxoEtxs []*types.Transaction, etxSet *types.EtxSet, usedGas uint64) error {
func (v *BlockValidator) ValidateState(block *types.WorkObject, statedb *state.StateDB, receipts types.Receipts, utxoEtxs []*types.Transaction, usedGas uint64) error {
start := time.Now()
header := types.CopyHeader(block.Header())
time1 := common.PrettyDuration(time.Since(start))
Expand All @@ -130,6 +130,9 @@ func (v *BlockValidator) ValidateState(block *types.WorkObject, statedb *state.S
if root := statedb.UTXORoot(); header.UTXORoot() != root {
return fmt.Errorf("invalid utxo root (remote: %x local: %x)", header.UTXORoot(), root)
}
if root := statedb.ETXRoot(); header.EtxSetRoot() != root {
return fmt.Errorf("invalid etx root (remote: %x local: %x)", header.EtxSetRoot(), root)
}
time5 := common.PrettyDuration(time.Since(start))
// Collect ETXs emitted from each successful transaction
var emittedEtxs types.Transactions
Expand All @@ -146,19 +149,6 @@ func (v *BlockValidator) ValidateState(block *types.WorkObject, statedb *state.S
if etxHash := types.DeriveSha(emittedEtxs, trie.NewStackTrie(nil)); etxHash != header.EtxHash() {
return fmt.Errorf("invalid etx hash (remote: %x local: %x)", header.EtxHash(), etxHash)
}
// Confirm the ETX set used by the block matches the ETX set given in the block body
// This is the resulting ETX set after all ETXs in the block have been processed
// After validation, this ETX set should be stored in the database
if etxSet != nil {
etxSetHash := etxSet.Hash()
if etxSetHash != block.EtxSetHash() {
return fmt.Errorf("expected ETX Set hash %x does not match block ETXSetHash %x", etxSetHash, block.EtxSetHash())
}
} else {
if block.EtxSetHash() != types.EmptyEtxSetHash {
return fmt.Errorf("expected ETX Set hash %x does not match block ETXSetHash %x", types.EmptyRootHash, block.EtxSetHash())
}
}

// Check that the UncledS in the header matches the S from the block
expectedUncledS := v.engine.UncledLogS(block)
Expand Down
4 changes: 2 additions & 2 deletions core/bodydb.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func NewBodyDb(db ethdb.Database, engine consensus.Engine, hc *HeaderChain, chai
}

// Append
func (bc *BodyDb) Append(block *types.WorkObject, newInboundEtxs types.Transactions) ([]*types.Log, error) {
func (bc *BodyDb) Append(block *types.WorkObject) ([]*types.Log, error) {
bc.chainmu.Lock()
defer bc.chainmu.Unlock()

Expand All @@ -101,7 +101,7 @@ func (bc *BodyDb) Append(block *types.WorkObject, newInboundEtxs types.Transacti
var err error
if nodeCtx == common.ZONE_CTX && bc.ProcessingState() {
// Process our block
logs, err = bc.processor.Apply(batch, block, newInboundEtxs)
logs, err = bc.processor.Apply(batch, block)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -1056,8 +1056,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 common.Hash, utxoRoot common.Hash) (*state.StateDB, error) {
return c.sl.hc.bc.processor.StateAt(root, utxoRoot)
func (c *Core) StateAt(root, utxoRoot, etxRoot common.Hash) (*state.StateDB, error) {
return c.sl.hc.bc.processor.StateAt(root, utxoRoot, etxRoot)
}

// StateCache returns the caching database underpinning the blockchain instance.
Expand Down
4 changes: 2 additions & 2 deletions 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, 0)
if _, err := state.New(header.EVMRoot(), header.UTXORoot(), state.NewDatabaseWithConfig(db, nil), state.NewDatabaseWithConfig(db, nil), nil, nodeLocation); err != nil {
if _, err := state.New(header.EVMRoot(), header.UTXORoot(), header.EtxSetRoot(), state.NewDatabaseWithConfig(db, nil), state.NewDatabaseWithConfig(db, nil), state.NewDatabaseWithConfig(db, nil), nil, nodeLocation); err != nil {
if genesis == nil {
genesis = DefaultGenesisBlock()
}
Expand Down Expand Up @@ -286,7 +286,7 @@ func (g *Genesis) ToBlock(startingExpansionNumber uint64) *types.WorkObject {
}
head.Header().SetCoinbase(common.Zero)
head.Header().SetBaseFee(new(big.Int).SetUint64(params.InitialBaseFee))
head.Header().SetEtxSetHash(types.EmptyEtxSetHash)
head.Header().SetEtxSetRoot(types.EmptyRootHash)
if g.GasLimit == 0 {
head.Header().SetGasLimit(params.GenesisGasLimit)
}
Expand Down
44 changes: 13 additions & 31 deletions core/headerchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,10 +317,10 @@ func (hc *HeaderChain) ProcessingState() bool {
}

// Append
func (hc *HeaderChain) AppendBlock(block *types.WorkObject, newInboundEtxs types.Transactions) error {
func (hc *HeaderChain) AppendBlock(block *types.WorkObject) error {
blockappend := time.Now()
// Append block else revert header append
logs, err := hc.bc.Append(block, newInboundEtxs)
logs, err := hc.bc.Append(block)
if err != nil {
return err
}
Expand Down Expand Up @@ -441,47 +441,29 @@ func (hc *HeaderChain) SetCurrentState(head *types.WorkObject) error {
if hc.IsGenesisHash(header.Hash()) {
break
}
// Checking of the Etx set exists makes sure that we have processed the
// state of the parent block
etxSet := rawdb.ReadEtxSet(hc.headerDb, header.Hash(), header.NumberU64(nodeCtx))
if etxSet != nil {
// This is not perfect because it's possible some blocks have the same root hash (no uniqueness guarantee)
// We probably need a better way to determine if we have processed the state and ETXs for a given block
_, err := hc.bc.processor.StateAt(header.EVMRoot(), header.UTXORoot(), header.EtxSetRoot())
if err == nil {
break
}
current = types.CopyWorkObject(header)
}

// Run through the hash stack to update canonicalHash and forward state processor
for i := len(headersWithoutState) - 1; i >= 0; i-- {
err := hc.ReadInboundEtxsAndAppendBlock(headersWithoutState[i])
block := hc.GetBlockOrCandidate(headersWithoutState[i].Hash(), headersWithoutState[i].NumberU64(nodeCtx))
if block == nil {
return errors.New("could not find block during SetCurrentState: " + headersWithoutState[i].Hash().String())
}
err := hc.AppendBlock(block)
if err != nil {
return err
}
}
return nil
}

// ReadInboundEtxsAndAppendBlock reads the inbound etxs from database and appends the block
func (hc *HeaderChain) ReadInboundEtxsAndAppendBlock(header *types.WorkObject) error {
nodeCtx := hc.NodeCtx()
block := hc.GetBlockOrCandidate(header.Hash(), header.NumberU64(nodeCtx))
if block == nil {
return errors.New("could not find block during reorg")
}
_, order, err := hc.engine.CalcOrder(block)
if err != nil {
return err
}
var inboundEtxs types.Transactions
if order < nodeCtx {
inboundEtxs = rawdb.ReadInboundEtxs(hc.headerDb, header.Hash())
}
err = hc.AppendBlock(block, inboundEtxs)
if err != nil {
return err
}
return nil
}

// findCommonAncestor
func (hc *HeaderChain) findCommonAncestor(header *types.WorkObject) *types.WorkObject {
current := types.CopyWorkObject(header)
Expand Down Expand Up @@ -998,8 +980,8 @@ func (hc *HeaderChain) SubscribeChainSideEvent(ch chan<- ChainSideEvent) event.S
return hc.scope.Track(hc.chainSideFeed.Subscribe(ch))
}

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

func (hc *HeaderChain) SlicesRunning() []common.Location {
Expand Down
23 changes: 0 additions & 23 deletions core/rawdb/accessors_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,29 +60,6 @@ func TestTerminiStorage(t *testing.T) {
}
}

func TestEtxSetStorage(t *testing.T) {
db := NewMemoryDatabase()

// Create a test etxSet to move around the database and make sure it's really new
etxSet := types.NewEtxSet()
hash := common.Hash{1}
var number uint64 = 0
if entry := ReadEtxSet(db, hash, number); entry != nil {
t.Fatalf("Non existent etxSet returned: %v", entry)
}
t.Log("EtxSet Hash stored", hash)
// Write and verify the etxSet in the database
WriteEtxSet(db, hash, 0, etxSet)
if entry := ReadEtxSet(db, hash, number); entry == nil {
t.Fatalf("Stored etxSet not found with hash %s", hash)
}
// Delete the etxSet and verify the execution
DeleteEtxSet(db, hash, number)
if entry := ReadEtxSet(db, hash, number); entry != nil {
t.Fatalf("Deleted etxSet returned: %v", entry)
}
}

// Tests inbound etx storage and retrieval operations.
func TestInboundEtxsStorage(t *testing.T) {
db := NewMemoryDatabase()
Expand Down
39 changes: 21 additions & 18 deletions core/slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,8 +335,9 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb
subReorg = sl.miningStrategy(bestPh, tempPendingHeader)

if order < nodeCtx {
// Store the inbound etxs for dom blocks that did not get picked and use
// Store the inbound etxs for all dom blocks and use
// it in the future if dom switch happens
// This should be pruned at the re-org tolerance depth
rawdb.WriteInboundEtxs(sl.sliceDb, block.Hash(), newInboundEtxs)
}

Expand Down Expand Up @@ -438,20 +439,23 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb
}).Info("Times during sub append")

sl.logger.WithFields(log.Fields{
"dom number": block.Header().NumberArray(),
"zone number": block.Number(common.ZONE_CTX),
"hash": block.Hash(),
"difficulty": block.Difficulty(),
"uncles": len(block.Uncles()),
"txs": len(block.Transactions()),
"etxs": len(block.ExtTransactions()),
"utxos": len(block.QiTransactions()),
"gas": block.GasUsed(),
"gasLimit": block.GasLimit(),
"evmRoot": block.EVMRoot(),
"order": order,
"location": block.Location(),
"elapsed": common.PrettyDuration(time.Since(start)),
"dom number": block.Header().NumberArray(),
"zone number": block.Number(common.ZONE_CTX),
"hash": block.Hash(),
"difficulty": block.Difficulty(),
"uncles": len(block.Uncles()),
"totalTxs": len(block.Transactions()),
"etxs emitted": len(block.ExtTransactions()),
"qiTxs": len(block.QiTransactions()),
"quaiTxs": len(block.QuaiTransactions()),
"gas": block.GasUsed(),
"gasLimit": block.GasLimit(),
"evmRoot": block.EVMRoot(),
"utxoRoot": block.UTXORoot(),
"etxSetRoot": block.EtxSetRoot(),
"order": order,
"location": block.Location(),
"elapsed": common.PrettyDuration(time.Since(start)),
}).Info("Appended new block")

if nodeCtx == common.ZONE_CTX {
Expand Down Expand Up @@ -1223,7 +1227,6 @@ func (sl *Slice) init() error {
if err != nil {
return err
}
rawdb.WriteEtxSet(sl.sliceDb, genesisHash, 0, types.NewEtxSet())
// This is just done for the startup process
sl.hc.SetCurrentHeader(genesisHeader)

Expand Down Expand Up @@ -1345,10 +1348,11 @@ func (sl *Slice) combinePendingHeader(header *types.WorkObject, slPendingHeader
combinedPendingHeader.Header().SetUncleHash(header.UncleHash())
combinedPendingHeader.Header().SetTxHash(header.Header().TxHash())
combinedPendingHeader.Header().SetEtxHash(header.EtxHash())
combinedPendingHeader.Header().SetEtxSetHash(header.EtxSetHash())
combinedPendingHeader.Header().SetEtxSetRoot(header.EtxSetRoot())
combinedPendingHeader.Header().SetReceiptHash(header.ReceiptHash())
combinedPendingHeader.Header().SetEVMRoot(header.EVMRoot())
combinedPendingHeader.Header().SetUTXORoot(header.UTXORoot())
combinedPendingHeader.Header().SetEtxSetRoot(header.EtxSetRoot())
combinedPendingHeader.Header().SetCoinbase(header.Coinbase())
combinedPendingHeader.Header().SetBaseFee(header.BaseFee())
combinedPendingHeader.Header().SetGasLimit(header.GasLimit())
Expand Down Expand Up @@ -1406,7 +1410,6 @@ func (sl *Slice) WriteGenesisBlock(block *types.WorkObject, location common.Loca
sl.AddPendingEtxsRollup(types.PendingEtxsRollup{block, emptyPendingEtxs})
sl.hc.AddBloom(types.Bloom{}, block.Hash())
sl.hc.currentHeader.Store(block)
rawdb.WriteEtxSet(sl.sliceDb, block.Hash(), block.NumberU64(sl.NodeCtx()), types.NewEtxSet())
}

// NewGenesisPendingHeader creates a pending header on the genesis block
Expand Down
Loading

0 comments on commit 40640d8

Please sign in to comment.