return err
}
- voteResult, err := c.getBestVoteResult()
+ consensusResult, err := c.getBestConsensusResult()
if err != nil {
return err
}
- if err := voteResult.ApplyBlock(block); err != nil {
+ if err := consensusResult.ApplyBlock(block); err != nil {
return err
}
- irrBlockHeader := c.bestIrrBlockHeader
+ irrBlockHeader := c.lastIrrBlockHeader
if c.isIrreversible(&block.BlockHeader) && block.Height > irrBlockHeader.Height {
irrBlockHeader = &block.BlockHeader
}
- if err := c.setState(&block.BlockHeader, irrBlockHeader, []*types.BlockHeader{&block.BlockHeader}, utxoView, []*state.VoteResult{voteResult}); err != nil {
+ if err := c.setState(&block.BlockHeader, irrBlockHeader, []*types.BlockHeader{&block.BlockHeader}, utxoView, []*state.ConsensusResult{consensusResult}); err != nil {
return err
}
}
utxoView := state.NewUtxoViewpoint()
- voteResults := []*state.VoteResult{}
- voteResult, err := c.getBestVoteResult()
+ consensusResults := []*state.ConsensusResult{}
+ consensusResult, err := c.getBestConsensusResult()
if err != nil {
return err
}
+ txsToRestore := map[bc.Hash]*types.Tx{}
for _, detachBlockHeader := range detachBlockHeaders {
detachHash := detachBlockHeader.Hash()
b, err := c.store.GetBlock(&detachHash)
return err
}
- if err := voteResult.DetachBlock(b); err != nil {
+ if err := consensusResult.DetachBlock(b); err != nil {
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")
}
- irrBlockHeader := c.bestIrrBlockHeader
+ txsToRemove := map[bc.Hash]*types.Tx{}
+ irrBlockHeader := c.lastIrrBlockHeader
for _, attachBlockHeader := range attachBlockHeaders {
attachHash := attachBlockHeader.Hash()
b, err := c.store.GetBlock(&attachHash)
return err
}
- if err := voteResult.ApplyBlock(b); err != nil {
+ if err := consensusResult.ApplyBlock(b); err != nil {
return err
}
- if voteResult.IsFinalize() {
- voteResults = append(voteResults, voteResult.Fork())
+ if consensusResult.IsFinalize() {
+ consensusResults = append(consensusResults, consensusResult.Fork())
}
if c.isIrreversible(attachBlockHeader) && attachBlockHeader.Height > irrBlockHeader.Height {
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")
}
- if len(detachBlockHeaders) > 0 && detachBlockHeaders[len(detachBlockHeaders)-1].Height <= c.bestIrrBlockHeader.Height && irrBlockHeader.Height <= c.bestIrrBlockHeader.Height {
+ if len(detachBlockHeaders) > 0 &&
+ detachBlockHeaders[len(detachBlockHeaders)-1].Height <= c.lastIrrBlockHeader.Height &&
+ irrBlockHeader.Height <= c.lastIrrBlockHeader.Height {
return errors.New("rollback block below the height of irreversible block")
}
- voteResults = append(voteResults, voteResult.Fork())
- return c.setState(blockHeader, irrBlockHeader, attachBlockHeaders, utxoView, voteResults)
+
+ consensusResults = append(consensusResults, consensusResult.Fork())
+ 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
return err
}
+ consensusResult, err := c.GetConsensusResultByHash(&block.PreviousBlockHash)
+ if err != nil {
+ return err
+ }
+
+ if err := consensusResult.AttachCoinbaseReward(block); err != nil {
+ return err
+ }
+
+ rewards, err := consensusResult.GetCoinbaseRewards(block.Height)
+ if err != nil {
+ return err
+ }
+
bcBlock := types.MapBlock(block)
- if err := validation.ValidateBlock(bcBlock, parent); err != nil {
+ if err := validation.ValidateBlock(bcBlock, parent, rewards); err != nil {
return errors.Sub(ErrBadBlock, err)
}