From: apolloww <32606824+apolloww@users.noreply.github.com> Date: Tue, 9 Jul 2019 06:24:57 +0000 (+0800) Subject: restore Tx back to Tx pool when chain is reorganized (#254) X-Git-Tag: v1.0.5~167 X-Git-Url: http://git.osdn.net/view?p=bytom%2Fvapor.git;a=commitdiff_plain;h=78a95664d6bf5b9b576901ddd596d51ea039287c;hp=2e4f5f11ae3bec54e4918a7aac5c8b3e2381de44 restore Tx back to Tx pool when chain is reorganized (#254) * restore Tx back to Tx pool when chain is reorganized * print log if restoring tx fails --- diff --git a/protocol/block.go b/protocol/block.go index c1dc2651..4870de32 100644 --- a/protocol/block.go +++ b/protocol/block.go @@ -138,6 +138,7 @@ func (c *Chain) reorganizeChain(blockHeader *types.BlockHeader) error { return err } + txsToRestore := map[bc.Hash]*types.Tx{} for _, detachBlockHeader := range detachBlockHeaders { detachHash := detachBlockHeader.Hash() b, err := c.store.GetBlock(&detachHash) @@ -163,10 +164,15 @@ func (c *Chain) reorganizeChain(blockHeader *types.BlockHeader) error { return err } + for _, tx := range b.Transactions { + txsToRestore[tx.ID] = tx + } + blockHash := blockHeader.Hash() log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("detach from mainchain") } + txsToRemove := map[bc.Hash]*types.Tx{} irrBlockHeader := c.lastIrrBlockHeader for _, attachBlockHeader := range attachBlockHeaders { attachHash := attachBlockHeader.Hash() @@ -201,6 +207,14 @@ func (c *Chain) reorganizeChain(blockHeader *types.BlockHeader) error { irrBlockHeader = attachBlockHeader } + for _, tx := range b.Transactions { + if _, ok := txsToRestore[tx.ID]; !ok { + txsToRemove[tx.ID] = tx + } else { + delete(txsToRestore, tx.ID) + } + } + blockHash := blockHeader.Hash() log.WithFields(log.Fields{"module": logModule, "height": blockHeader.Height, "hash": blockHash.String()}).Debug("attach from mainchain") } @@ -210,8 +224,29 @@ func (c *Chain) reorganizeChain(blockHeader *types.BlockHeader) error { irrBlockHeader.Height <= c.lastIrrBlockHeader.Height { return errors.New("rollback block below the height of irreversible block") } + consensusResults = append(consensusResults, consensusResult.Fork()) - return c.setState(blockHeader, irrBlockHeader, attachBlockHeaders, utxoView, consensusResults) + if err := c.setState(blockHeader, irrBlockHeader, attachBlockHeaders, utxoView, consensusResults); err != nil { + return err + } + + for txHash := range txsToRemove { + c.txPool.RemoveTransaction(&txHash) + } + + for _, tx := range txsToRestore { + // the number of restored Tx should be very small or most of time ZERO + // Error returned from validation is ignored, tx could still be lost if validation fails. + // TODO: adjust tx timestamp so that it won't starve in pool. + if _, err := c.ValidateTx(tx); err != nil { + log.WithFields(log.Fields{"module": logModule, "tx_id": tx.Tx.ID.String(), "error": err}).Info("restore tx fail") + } + } + + if len(txsToRestore) > 0 { + log.WithFields(log.Fields{"module": logModule, "num": len(txsToRestore)}).Debug("restore txs back to pool") + } + return nil } // SaveBlock will validate and save block into storage