From 4a05bcf6dfa97c3c19eeb0ad3a74790c9e17a6e1 Mon Sep 17 00:00:00 2001 From: Jonathan Downing Date: Tue, 4 Jun 2024 15:09:00 -0500 Subject: [PATCH] ETX bugfixes: store inboundEtxs before generating pending header, collect outbound etxs in proper order --- core/block_validator.go | 12 ++---------- core/slice.go | 12 +++++------- core/state_processor.go | 15 ++++++++++----- core/types.go | 2 +- 4 files changed, 18 insertions(+), 23 deletions(-) diff --git a/core/block_validator.go b/core/block_validator.go index a75768e066..9de09966fc 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -112,7 +112,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, usedGas uint64) error { +func (v *BlockValidator) ValidateState(block *types.WorkObject, statedb *state.StateDB, receipts types.Receipts, etxs types.Transactions, usedGas uint64) error { start := time.Now() header := types.CopyHeader(block.Header()) time1 := common.PrettyDuration(time.Since(start)) @@ -139,19 +139,11 @@ func (v *BlockValidator) ValidateState(block *types.WorkObject, statedb *state.S 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 - for _, receipt := range receipts { - if receipt.Status == types.ReceiptStatusSuccessful { - emittedEtxs = append(emittedEtxs, receipt.Etxs...) - } - } - emittedEtxs = append(emittedEtxs, utxoEtxs...) time6 := common.PrettyDuration(time.Since(start)) // Confirm the ETXs emitted by the transactions in this block exactly match the // ETXs given in the block body - if etxHash := types.DeriveSha(emittedEtxs, trie.NewStackTrie(nil)); etxHash != header.EtxHash() { + if etxHash := types.DeriveSha(etxs, trie.NewStackTrie(nil)); etxHash != header.EtxHash() { return fmt.Errorf("invalid etx hash (remote: %x local: %x)", header.EtxHash(), etxHash) } diff --git a/core/slice.go b/core/slice.go index 9f9ce8d42b..37925931cd 100644 --- a/core/slice.go +++ b/core/slice.go @@ -243,6 +243,11 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb if err != nil { return nil, false, false, err } + } else if nodeCtx == common.ZONE_CTX && order < nodeCtx { + // 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) } // If this was a coincident block, our dom will be passing us a set of newly @@ -332,13 +337,6 @@ func (sl *Slice) Append(header *types.WorkObject, domPendingHeader *types.WorkOb subReorg = sl.miningStrategy(bestPh, tempPendingHeader) - if order < nodeCtx { - // 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) - } - setHead = sl.poem(sl.engine.TotalLogS(sl.hc, block), sl.engine.TotalLogS(sl.hc, sl.hc.CurrentHeader())) if subReorg || (sl.hc.CurrentHeader().NumberU64(nodeCtx) < block.NumberU64(nodeCtx)+c_currentStateComputeWindow) { diff --git a/core/state_processor.go b/core/state_processor.go index 419efd7ebe..68f80db0d4 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -297,7 +297,7 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty maximumEtxGas := minimumEtxGas * params.MaximumEtxGasMultiplier // 40% of the block gas limit totalEtxGas := uint64(0) totalFees := big.NewInt(0) - qiEtxs := make([]*types.Transaction, 0) + emittedEtxs := make([]*types.Transaction, 0) var totalQiTime time.Duration for i, tx := range block.Transactions() { if i == 0 && types.IsCoinBaseTx(tx, header.ParentHash(nodeCtx), nodeLocation) { @@ -316,7 +316,7 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty return nil, nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } for _, etx := range etxs { - qiEtxs = append(qiEtxs, types.NewTx(etx)) + emittedEtxs = append(emittedEtxs, types.NewTx(etx)) } totalFees.Add(totalFees, fees) totalQiTime += time.Since(qiTimeBefore) @@ -434,6 +434,11 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty } else { return nil, nil, nil, nil, 0, ErrTxTypeNotSupported } + for _, etx := range receipt.Etxs { + if receipt.Status == types.ReceiptStatusSuccessful { + emittedEtxs = append(emittedEtxs, etx) + } + } receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) i++ @@ -566,7 +571,7 @@ func (p *StateProcessor) Process(block *types.WorkObject) (types.Receipts, []*ty "tx time": common.PrettyDuration(timeTx), }).Info("Total Tx Processing Time") - return receipts, qiEtxs, allLogs, statedb, *usedGas, nil + return receipts, emittedEtxs, allLogs, statedb, *usedGas, nil } func applyTransaction(msg types.Message, parent *types.WorkObject, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *types.GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM, etxRLimit, etxPLimit *int, logger *log.Logger) (*types.Receipt, error) { @@ -1106,7 +1111,7 @@ func (p *StateProcessor) Apply(batch ethdb.Batch, block *types.WorkObject) ([]*t time1 := common.PrettyDuration(time.Since(start)) time2 := common.PrettyDuration(time.Since(start)) // Process our block - receipts, utxoEtxs, logs, statedb, usedGas, err := p.Process(block) + receipts, etxs, logs, statedb, usedGas, err := p.Process(block) if err != nil { return nil, err } @@ -1117,7 +1122,7 @@ func (p *StateProcessor) Apply(batch ethdb.Batch, block *types.WorkObject) ([]*t }).Warn("Block hash changed after Processing the block") } time3 := common.PrettyDuration(time.Since(start)) - err = p.validator.ValidateState(block, statedb, receipts, utxoEtxs, usedGas) + err = p.validator.ValidateState(block, statedb, receipts, etxs, usedGas) if err != nil { return nil, err } diff --git a/core/types.go b/core/types.go index dc1a07391a..94ddc06098 100644 --- a/core/types.go +++ b/core/types.go @@ -31,7 +31,7 @@ type Validator interface { // ValidateState validates the given statedb and optionally the receipts and // gas used. - ValidateState(block *types.WorkObject, state *state.StateDB, receipts types.Receipts, utxoEtxs []*types.Transaction, usedGas uint64) error + ValidateState(block *types.WorkObject, state *state.StateDB, receipts types.Receipts, etxs types.Transactions, usedGas uint64) error } // Prefetcher is an interface for pre-caching transaction signatures and state.