return c.store.GetBlock(hash)
}
-// GetBlockByHeight return a block by given height
+// GetBlockByHeight return a block header by given height
func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, error) {
node := c.index.NodeByHeight(height)
if node == nil {
return c.store.GetBlock(&node.Hash)
}
+// GetHeaderByHash return a block header by given hash
+func (c *Chain) GetHeaderByHash(hash *bc.Hash) (*types.BlockHeader, error) {
+ node := c.index.GetNode(hash)
+ if node == nil {
+ return nil, errors.New("can't find block header in given hash")
+ }
+ return node.BlockHeader(), nil
+}
+
+// GetHeaderByHeight return a block header by given height
+func (c *Chain) GetHeaderByHeight(height uint64) (*types.BlockHeader, error) {
+ node := c.index.NodeByHeight(height)
+ if node == nil {
+ return nil, errors.New("can't find block header in given height")
+ }
+ return node.BlockHeader(), nil
+}
+
func (c *Chain) calcReorganizeNodes(node *state.BlockNode) ([]*state.BlockNode, []*state.BlockNode) {
var attachNodes []*state.BlockNode
var detachNodes []*state.BlockNode
attachNodes, detachNodes := c.calcReorganizeNodes(node)
utxoView := state.NewUtxoViewpoint()
+ txsToRestore := map[bc.Hash]*types.Tx{}
for _, detachNode := range detachNodes {
b, err := c.store.GetBlock(&detachNode.Hash)
if err != nil {
return err
}
- log.WithFields(log.Fields{"height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain")
+ for _, tx := range b.Transactions {
+ txsToRestore[tx.ID] = tx
+ }
+ log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain")
}
+ txsToRemove := map[bc.Hash]*types.Tx{}
for _, attachNode := range attachNodes {
b, err := c.store.GetBlock(&attachNode.Hash)
if err != nil {
return err
}
- log.WithFields(log.Fields{"height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain")
+ for _, tx := range b.Transactions {
+ if _, ok := txsToRestore[tx.ID]; !ok {
+ txsToRemove[tx.ID] = tx
+ } else {
+ delete(txsToRestore, tx.ID)
+ }
+ }
+
+ log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain")
}
- return c.setState(node, utxoView)
+ if err := c.setState(node, utxoView); 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
for _, prevOrphan := range prevOrphans {
orphanBlock, ok := c.orphanManage.Get(prevOrphan)
if !ok {
- log.WithFields(log.Fields{"hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
+ log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage")
continue
}
if err := c.saveBlock(orphanBlock); err != nil {
- log.WithFields(log.Fields{"hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
+ log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block")
continue
}
func (c *Chain) processBlock(block *types.Block) (bool, error) {
blockHash := block.Hash()
if c.BlockExist(&blockHash) {
- log.WithFields(log.Fields{"hash": blockHash.String(), "height": block.Height}).Info("block has been processed")
+ log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("block has been processed")
return c.orphanManage.BlockExist(&blockHash), nil
}
bestNode := c.index.GetNode(&bestBlockHash)
if bestNode.Parent == c.bestNode {
- log.Debug("append block to the end of mainchain")
+ log.WithFields(log.Fields{"module": logModule}).Debug("append block to the end of mainchain")
return false, c.connectBlock(bestBlock)
}
if bestNode.Height > c.bestNode.Height && bestNode.WorkSum.Cmp(c.bestNode.WorkSum) >= 0 {
- log.Debug("start to reorganize chain")
+ log.WithFields(log.Fields{"module": logModule}).Debug("start to reorganize chain")
return false, c.reorganizeChain(bestNode)
}
return false, nil