github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/protocol/block.go (about) 1 package protocol 2 3 import ( 4 log "github.com/sirupsen/logrus" 5 6 "github.com/bytom/bytom/errors" 7 "github.com/bytom/bytom/protocol/bc" 8 "github.com/bytom/bytom/protocol/bc/types" 9 "github.com/bytom/bytom/protocol/state" 10 "github.com/bytom/bytom/protocol/validation" 11 ) 12 13 var ( 14 // ErrBadBlock is returned when a block is invalid. 15 ErrBadBlock = errors.New("invalid block") 16 // ErrBadStateRoot is returned when the computed assets merkle root 17 // disagrees with the one declared in a block header. 18 ErrBadStateRoot = errors.New("invalid state merkle root") 19 ) 20 21 // BlockExist check is a block in chain or orphan 22 func (c *Chain) BlockExist(hash *bc.Hash) bool { 23 return c.index.BlockExist(hash) || c.orphanManage.BlockExist(hash) 24 } 25 26 // GetBlockByHash return a block by given hash 27 func (c *Chain) GetBlockByHash(hash *bc.Hash) (*types.Block, error) { 28 return c.store.GetBlock(hash) 29 } 30 31 // GetBlockByHeight return a block header by given height 32 func (c *Chain) GetBlockByHeight(height uint64) (*types.Block, error) { 33 node := c.index.NodeByHeight(height) 34 if node == nil { 35 return nil, errors.New("can't find block in given height") 36 } 37 return c.store.GetBlock(&node.Hash) 38 } 39 40 // GetHeaderByHash return a block header by given hash 41 func (c *Chain) GetHeaderByHash(hash *bc.Hash) (*types.BlockHeader, error) { 42 node := c.index.GetNode(hash) 43 if node == nil { 44 return nil, errors.New("can't find block header in given hash") 45 } 46 return node.BlockHeader(), nil 47 } 48 49 // GetHeaderByHeight return a block header by given height 50 func (c *Chain) GetHeaderByHeight(height uint64) (*types.BlockHeader, error) { 51 node := c.index.NodeByHeight(height) 52 if node == nil { 53 return nil, errors.New("can't find block header in given height") 54 } 55 return node.BlockHeader(), nil 56 } 57 58 func (c *Chain) calcReorganizeNodes(node *state.BlockNode) ([]*state.BlockNode, []*state.BlockNode) { 59 var attachNodes []*state.BlockNode 60 var detachNodes []*state.BlockNode 61 62 attachNode := node 63 for c.index.NodeByHeight(attachNode.Height) != attachNode { 64 attachNodes = append([]*state.BlockNode{attachNode}, attachNodes...) 65 attachNode = attachNode.Parent 66 } 67 68 detachNode := c.bestNode 69 for detachNode != attachNode { 70 detachNodes = append(detachNodes, detachNode) 71 detachNode = detachNode.Parent 72 } 73 return attachNodes, detachNodes 74 } 75 76 func (c *Chain) connectBlock(block *types.Block) (err error) { 77 bcBlock := types.MapBlock(block) 78 if bcBlock.TransactionStatus, err = c.store.GetTransactionStatus(&bcBlock.ID); err != nil { 79 return err 80 } 81 82 utxoView := state.NewUtxoViewpoint() 83 if err := c.store.GetTransactionsUtxo(utxoView, bcBlock.Transactions); err != nil { 84 return err 85 } 86 if err := utxoView.ApplyBlock(bcBlock, bcBlock.TransactionStatus); err != nil { 87 return err 88 } 89 90 node := c.index.GetNode(&bcBlock.ID) 91 if err := c.setState(node, utxoView); err != nil { 92 return err 93 } 94 95 for _, tx := range block.Transactions { 96 c.txPool.RemoveTransaction(&tx.Tx.ID) 97 } 98 return nil 99 } 100 101 func (c *Chain) reorganizeChain(node *state.BlockNode) error { 102 attachNodes, detachNodes := c.calcReorganizeNodes(node) 103 utxoView := state.NewUtxoViewpoint() 104 105 txsToRestore := map[bc.Hash]*types.Tx{} 106 for _, detachNode := range detachNodes { 107 b, err := c.store.GetBlock(&detachNode.Hash) 108 if err != nil { 109 return err 110 } 111 112 detachBlock := types.MapBlock(b) 113 if err := c.store.GetTransactionsUtxo(utxoView, detachBlock.Transactions); err != nil { 114 return err 115 } 116 txStatus, err := c.GetTransactionStatus(&detachBlock.ID) 117 if err != nil { 118 return err 119 } 120 if err := utxoView.DetachBlock(detachBlock, txStatus); err != nil { 121 return err 122 } 123 124 for _, tx := range b.Transactions { 125 txsToRestore[tx.ID] = tx 126 } 127 log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("detach from mainchain") 128 } 129 130 txsToRemove := map[bc.Hash]*types.Tx{} 131 for _, attachNode := range attachNodes { 132 b, err := c.store.GetBlock(&attachNode.Hash) 133 if err != nil { 134 return err 135 } 136 137 attachBlock := types.MapBlock(b) 138 if err := c.store.GetTransactionsUtxo(utxoView, attachBlock.Transactions); err != nil { 139 return err 140 } 141 txStatus, err := c.GetTransactionStatus(&attachBlock.ID) 142 if err != nil { 143 return err 144 } 145 if err := utxoView.ApplyBlock(attachBlock, txStatus); err != nil { 146 return err 147 } 148 149 for _, tx := range b.Transactions { 150 if _, ok := txsToRestore[tx.ID]; !ok { 151 txsToRemove[tx.ID] = tx 152 } else { 153 delete(txsToRestore, tx.ID) 154 } 155 } 156 157 log.WithFields(log.Fields{"module": logModule, "height": node.Height, "hash": node.Hash.String()}).Debug("attach from mainchain") 158 } 159 160 if err := c.setState(node, utxoView); err != nil { 161 return err 162 } 163 164 for txHash := range txsToRemove { 165 c.txPool.RemoveTransaction(&txHash) 166 } 167 168 for _, tx := range txsToRestore { 169 // the number of restored Tx should be very small or most of time ZERO 170 // Error returned from validation is ignored, tx could still be lost if validation fails. 171 // TODO: adjust tx timestamp so that it won't starve in pool. 172 if _, err := c.ValidateTx(tx); err != nil { 173 log.WithFields(log.Fields{"module": logModule, "tx_id": tx.Tx.ID.String(), "error": err}).Info("restore tx fail") 174 } 175 } 176 177 if len(txsToRestore) > 0 { 178 log.WithFields(log.Fields{"module": logModule, "num": len(txsToRestore)}).Debug("restore txs back to pool") 179 } 180 181 return nil 182 } 183 184 // SaveBlock will validate and save block into storage 185 func (c *Chain) saveBlock(block *types.Block) error { 186 bcBlock := types.MapBlock(block) 187 parent := c.index.GetNode(&block.PreviousBlockHash) 188 189 if err := validation.ValidateBlock(bcBlock, parent); err != nil { 190 return errors.Sub(ErrBadBlock, err) 191 } 192 if err := c.store.SaveBlock(block, bcBlock.TransactionStatus); err != nil { 193 return err 194 } 195 196 c.orphanManage.Delete(&bcBlock.ID) 197 node, err := state.NewBlockNode(&block.BlockHeader, parent) 198 if err != nil { 199 return err 200 } 201 202 c.index.AddNode(node) 203 return nil 204 } 205 206 func (c *Chain) saveSubBlock(block *types.Block) *types.Block { 207 blockHash := block.Hash() 208 prevOrphans, ok := c.orphanManage.GetPrevOrphans(&blockHash) 209 if !ok { 210 return block 211 } 212 213 bestBlock := block 214 for _, prevOrphan := range prevOrphans { 215 orphanBlock, ok := c.orphanManage.Get(prevOrphan) 216 if !ok { 217 log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String()}).Warning("saveSubBlock fail to get block from orphanManage") 218 continue 219 } 220 if err := c.saveBlock(orphanBlock); err != nil { 221 log.WithFields(log.Fields{"module": logModule, "hash": prevOrphan.String(), "height": orphanBlock.Height}).Warning("saveSubBlock fail to save block") 222 continue 223 } 224 225 if subBestBlock := c.saveSubBlock(orphanBlock); subBestBlock.Height > bestBlock.Height { 226 bestBlock = subBestBlock 227 } 228 } 229 return bestBlock 230 } 231 232 type processBlockResponse struct { 233 isOrphan bool 234 err error 235 } 236 237 type processBlockMsg struct { 238 block *types.Block 239 reply chan processBlockResponse 240 } 241 242 // ProcessBlock is the entry for chain update 243 func (c *Chain) ProcessBlock(block *types.Block) (bool, error) { 244 reply := make(chan processBlockResponse, 1) 245 c.processBlockCh <- &processBlockMsg{block: block, reply: reply} 246 response := <-reply 247 return response.isOrphan, response.err 248 } 249 250 func (c *Chain) blockProcesser() { 251 for msg := range c.processBlockCh { 252 isOrphan, err := c.processBlock(msg.block) 253 msg.reply <- processBlockResponse{isOrphan: isOrphan, err: err} 254 } 255 } 256 257 // ProcessBlock is the entry for handle block insert 258 func (c *Chain) processBlock(block *types.Block) (bool, error) { 259 blockHash := block.Hash() 260 if c.BlockExist(&blockHash) { 261 log.WithFields(log.Fields{"module": logModule, "hash": blockHash.String(), "height": block.Height}).Info("block has been processed") 262 return c.orphanManage.BlockExist(&blockHash), nil 263 } 264 265 if parent := c.index.GetNode(&block.PreviousBlockHash); parent == nil { 266 c.orphanManage.Add(block) 267 return true, nil 268 } 269 270 if err := c.saveBlock(block); err != nil { 271 return false, err 272 } 273 274 bestBlock := c.saveSubBlock(block) 275 bestBlockHash := bestBlock.Hash() 276 bestNode := c.index.GetNode(&bestBlockHash) 277 278 if bestNode.Parent == c.bestNode { 279 log.WithFields(log.Fields{"module": logModule}).Debug("append block to the end of mainchain") 280 return false, c.connectBlock(bestBlock) 281 } 282 283 if bestNode.Height > c.bestNode.Height && bestNode.WorkSum.Cmp(c.bestNode.WorkSum) >= 0 { 284 log.WithFields(log.Fields{"module": logModule}).Debug("start to reorganize chain") 285 return false, c.reorganizeChain(bestNode) 286 } 287 return false, nil 288 }