github.com/turingchain2020/turingchain@v1.1.21/blockchain/process.go (about) 1 // Copyright Turing Corp. 2018 All Rights Reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package blockchain 6 7 import ( 8 "bytes" 9 "container/list" 10 "math/big" 11 "sync/atomic" 12 13 "github.com/turingchain2020/turingchain/client/api" 14 "github.com/turingchain2020/turingchain/common" 15 "github.com/turingchain2020/turingchain/common/difficulty" 16 "github.com/turingchain2020/turingchain/types" 17 "github.com/turingchain2020/turingchain/util" 18 ) 19 20 //ProcessBlock 处理共识模块过来的blockdetail,peer广播过来的block,以及从peer同步过来的block 21 // 共识模块和peer广播过来的block需要广播出去 22 //共识模块过来的Receipts不为空,广播和同步过来的Receipts为空 23 // 返回参数说明:是否主链,是否孤儿节点,具体err 24 func (chain *BlockChain) ProcessBlock(broadcast bool, block *types.BlockDetail, pid string, addBlock bool, sequence int64) (*types.BlockDetail, bool, bool, error) { 25 chainlog.Debug("ProcessBlock:Processing", "height", block.Block.Height, "blockHash", common.ToHex(block.Block.Hash(chain.client.GetConfig()))) 26 27 //blockchain close 时不再处理block 28 if atomic.LoadInt32(&chain.isclosed) == 1 { 29 return nil, false, false, types.ErrIsClosed 30 } 31 cfg := chain.client.GetConfig() 32 if block.Block.Height > 0 { 33 var lastBlockHash []byte 34 if addBlock { 35 lastBlockHash = block.Block.GetParentHash() 36 } else { 37 lastBlockHash = block.Block.Hash(cfg) 38 } 39 if pid == "self" && !bytes.Equal(lastBlockHash, chain.bestChain.Tip().hash) { 40 chainlog.Error("addBlockDetail parent hash no match", "err", types.ErrBlockHashNoMatch, 41 "bestHash", common.ToHex(chain.bestChain.Tip().hash), "blockHash", common.ToHex(lastBlockHash), 42 "addBlock", addBlock, "height", block.Block.Height) 43 return nil, false, false, types.ErrBlockHashNoMatch 44 } 45 } 46 blockHash := block.Block.Hash(cfg) 47 48 //目前只支持删除平行链的block处理,主链不支持删除block的操作 49 if !addBlock { 50 if chain.isParaChain { 51 return chain.ProcessDelParaChainBlock(broadcast, block, pid, sequence) 52 } 53 return nil, false, false, types.ErrNotSupport 54 } 55 //判断本block是否已经存在主链或者侧链中 56 //如果此block已经存在,并且已经被记录执行不过, 57 //将此block的源peer节点添加到故障peerlist中 58 exists := chain.blockExists(blockHash) 59 if exists { 60 is, err := chain.IsErrExecBlock(block.Block.Height, blockHash) 61 if is { 62 chain.RecordFaultPeer(pid, block.Block.Height, blockHash, err) 63 } 64 chainlog.Debug("ProcessBlock already have block", "blockHash", common.ToHex(blockHash)) 65 return nil, false, false, types.ErrBlockExist 66 } 67 68 // 判断本区块是否已经存在孤儿链中 69 exists = chain.orphanPool.IsKnownOrphan(blockHash) 70 if exists { 71 //本区块已经存在孤儿链中,但是自己的父区块也已经存在主链中 72 //此时可能是上次加载父区块的过程中,刚好子区块过来导致子区块被存入到孤儿链中了没有及时处理 73 //本次需要删除孤儿连中本区块的信息,尝试将此区块添加到主链上 74 if chain.blockExists(block.Block.GetParentHash()) { 75 chain.orphanPool.RemoveOrphanBlockByHash(blockHash) 76 chainlog.Debug("ProcessBlock:maybe Accept Orphan Block", "blockHash", common.ToHex(blockHash)) 77 } else { 78 chainlog.Debug("ProcessBlock already have block(orphan)", "blockHash", common.ToHex(blockHash)) 79 return nil, false, false, types.ErrBlockExist 80 } 81 } 82 83 //判断本block的父block是否存在,如果不存在就将此block添加到孤儿链中 84 //创世块0需要做一些特殊的判断 85 var prevHashExists bool 86 prevHash := block.Block.GetParentHash() 87 if 0 == block.Block.GetHeight() { 88 if bytes.Equal(prevHash, make([]byte, sha256Len)) { 89 prevHashExists = true 90 } 91 } else { 92 prevHashExists = chain.blockExists(prevHash) 93 } 94 if !prevHashExists { 95 chainlog.Debug("ProcessBlock:AddOrphanBlock", "height", block.Block.GetHeight(), "blockHash", common.ToHex(blockHash), "prevHash", common.ToHex(prevHash)) 96 chain.orphanPool.AddOrphanBlock(broadcast, block.Block, pid, sequence) 97 return nil, false, true, nil 98 } 99 100 // 基本检测通过之后尝试添加block到主链上 101 return chain.maybeAddBestChain(broadcast, block, pid, sequence) 102 } 103 104 //基本检测通过之后尝试将此block添加到主链上 105 func (chain *BlockChain) maybeAddBestChain(broadcast bool, block *types.BlockDetail, pid string, sequence int64) (*types.BlockDetail, bool, bool, error) { 106 chain.chainLock.Lock() 107 defer chain.chainLock.Unlock() 108 109 blockHash := block.Block.Hash(chain.client.GetConfig()) 110 exists := chain.blockExists(blockHash) 111 if exists { 112 return nil, false, false, types.ErrBlockExist 113 } 114 chainlog.Debug("maybeAddBestChain", "height", block.Block.GetHeight(), "blockHash", common.ToHex(blockHash)) 115 blockdetail, isMainChain, err := chain.maybeAcceptBlock(broadcast, block, pid, sequence) 116 117 if err != nil { 118 return nil, false, false, err 119 } 120 // 尝试处理blockHash对应的孤儿子节点 121 err = chain.orphanPool.ProcessOrphans(blockHash, chain) 122 if err != nil { 123 return nil, false, false, err 124 } 125 return blockdetail, isMainChain, false, nil 126 } 127 128 //检查block是否已经存在index或者数据库中 129 func (chain *BlockChain) blockExists(hash []byte) bool { 130 // Check block index first (could be main chain or side chain blocks). 131 if chain.index.HaveBlock(hash) { 132 return true 133 } 134 135 // 检测数据库中是否存在,通过hash获取blockheader,不存在就返回false。 136 blockheader, err := chain.blockStore.GetBlockHeaderByHash(hash) 137 if blockheader == nil || err != nil { 138 return false 139 } 140 //block存在数据库中时,需要确认是否在主链上。不在主链上返回false 141 height, err := chain.blockStore.GetHeightByBlockHash(hash) 142 if err != nil { 143 return false 144 } 145 return height != -1 146 } 147 148 // 尝试接受此block 149 func (chain *BlockChain) maybeAcceptBlock(broadcast bool, block *types.BlockDetail, pid string, sequence int64) (*types.BlockDetail, bool, error) { 150 // 首先判断本block的Parent block是否存在index中 151 prevHash := block.Block.GetParentHash() 152 prevNode := chain.index.LookupNode(prevHash) 153 if prevNode == nil { 154 chainlog.Debug("maybeAcceptBlock", "previous block is unknown", common.ToHex(prevHash)) 155 return nil, false, types.ErrParentBlockNoExist 156 } 157 158 blockHeight := block.Block.GetHeight() 159 if blockHeight != prevNode.height+1 { 160 chainlog.Debug("maybeAcceptBlock height err", "blockHeight", blockHeight, "prevHeight", prevNode.height) 161 return nil, false, types.ErrBlockHeightNoMatch 162 } 163 164 //将此block存储到db中,方便后面blockchain重组时使用,加入到主链saveblock时通过hash重新覆盖即可 165 sync := true 166 if atomic.LoadInt32(&chain.isbatchsync) == 0 { 167 sync = false 168 } 169 170 err := chain.blockStore.dbMaybeStoreBlock(block, sync) 171 if err != nil { 172 if err == types.ErrDataBaseDamage { 173 chainlog.Error("dbMaybeStoreBlock newbatch.Write", "err", err) 174 go util.ReportErrEventToFront(chainlog, chain.client, "blockchain", "wallet", types.ErrDataBaseDamage) 175 } 176 return nil, false, err 177 } 178 // 创建一个node并添加到内存中index 179 cfg := chain.client.GetConfig() 180 newNode := newBlockNode(cfg, broadcast, block.Block, pid, sequence) 181 if prevNode != nil { 182 newNode.parent = prevNode 183 } 184 chain.index.AddNode(newNode) 185 186 // 将本block添加到主链中 187 var isMainChain bool 188 block, isMainChain, err = chain.connectBestChain(newNode, block) 189 if err != nil { 190 return nil, false, err 191 } 192 193 return block, isMainChain, nil 194 } 195 196 //将block添加到主链中 197 func (chain *BlockChain) connectBestChain(node *blockNode, block *types.BlockDetail) (*types.BlockDetail, bool, error) { 198 199 enBestBlockCmp := chain.client.GetConfig().GetModuleConfig().Consensus.EnableBestBlockCmp 200 parentHash := block.Block.GetParentHash() 201 tip := chain.bestChain.Tip() 202 cfg := chain.client.GetConfig() 203 204 // 将此block添加到主链中,tip节点刚好是插入block的父节点. 205 if bytes.Equal(parentHash, tip.hash) { 206 var err error 207 block, err = chain.connectBlock(node, block) 208 if err != nil { 209 return nil, false, err 210 } 211 return block, true, nil 212 } 213 chainlog.Debug("connectBestChain", "parentHash", common.ToHex(parentHash), "bestChain.Tip().hash", common.ToHex(tip.hash)) 214 215 // 获取tip节点的block总难度tipid 216 tiptd, Err := chain.blockStore.GetTdByBlockHash(tip.hash) 217 if tiptd == nil || Err != nil { 218 chainlog.Error("connectBestChain tiptd is not exits!", "height", tip.height, "b.bestChain.Tip().hash", common.ToHex(tip.hash)) 219 return nil, false, Err 220 } 221 parenttd, Err := chain.blockStore.GetTdByBlockHash(parentHash) 222 if parenttd == nil || Err != nil { 223 chainlog.Error("connectBestChain parenttd is not exits!", "height", block.Block.Height, "parentHash", common.ToHex(parentHash), "block.Block.hash", common.ToHex(block.Block.Hash(cfg))) 224 return nil, false, types.ErrParentTdNoExist 225 } 226 blocktd := new(big.Int).Add(node.Difficulty, parenttd) 227 228 chainlog.Debug("connectBestChain tip:", "hash", common.ToHex(tip.hash), "height", tip.height, "TD", difficulty.BigToCompact(tiptd)) 229 chainlog.Debug("connectBestChain node:", "hash", common.ToHex(node.hash), "height", node.height, "TD", difficulty.BigToCompact(blocktd)) 230 231 //优先选择总难度系数大的区块 232 //总难度系数,区块高度,出块时间以及父区块一致并开启最优区块比较功能时,通过共识模块来确定最优区块 233 iSideChain := blocktd.Cmp(tiptd) <= 0 234 if enBestBlockCmp && blocktd.Cmp(tiptd) == 0 && node.height == tip.height && util.CmpBestBlock(chain.client, block.Block, tip.hash) { 235 iSideChain = false 236 } 237 if iSideChain { 238 fork := chain.bestChain.FindFork(node) 239 if fork != nil && bytes.Equal(parentHash, fork.hash) { 240 chainlog.Info("connectBestChain FORK:", "Block hash", common.ToHex(node.hash), "fork.height", fork.height, "fork.hash", common.ToHex(fork.hash)) 241 } else { 242 chainlog.Info("connectBestChain extends a side chain:", "Block hash", common.ToHex(node.hash), "fork.height", fork.height, "fork.hash", common.ToHex(fork.hash)) 243 } 244 return nil, false, nil 245 } 246 247 //print 248 chainlog.Debug("connectBestChain tip", "height", tip.height, "hash", common.ToHex(tip.hash)) 249 chainlog.Debug("connectBestChain node", "height", node.height, "hash", common.ToHex(node.hash), "parentHash", common.ToHex(parentHash)) 250 chainlog.Debug("connectBestChain block", "height", block.Block.Height, "hash", common.ToHex(block.Block.Hash(cfg))) 251 252 // 获取需要重组的block node 253 detachNodes, attachNodes := chain.getReorganizeNodes(node) 254 255 // Reorganize the chain. 256 err := chain.reorganizeChain(detachNodes, attachNodes) 257 if err != nil { 258 return nil, false, err 259 } 260 261 return nil, true, nil 262 } 263 264 //将本block信息存储到数据库中,并更新bestchain的tip节点 265 func (chain *BlockChain) connectBlock(node *blockNode, blockdetail *types.BlockDetail) (*types.BlockDetail, error) { 266 //blockchain close 时不再处理block 267 if atomic.LoadInt32(&chain.isclosed) == 1 { 268 return nil, types.ErrIsClosed 269 } 270 271 // Make sure it's extending the end of the best chain. 272 parentHash := blockdetail.Block.GetParentHash() 273 if !bytes.Equal(parentHash, chain.bestChain.Tip().hash) { 274 chainlog.Error("connectBlock hash err", "height", blockdetail.Block.Height, "Tip.height", chain.bestChain.Tip().height) 275 return nil, types.ErrBlockHashNoMatch 276 } 277 278 sync := true 279 if atomic.LoadInt32(&chain.isbatchsync) == 0 { 280 sync = false 281 } 282 283 var err error 284 var lastSequence int64 285 286 block := blockdetail.Block 287 prevStateHash := chain.bestChain.Tip().statehash 288 errReturn := (node.pid != "self") 289 blockdetail, _, err = execBlock(chain.client, prevStateHash, block, errReturn, sync) 290 if err != nil { 291 //记录执行出错的block信息,需要过滤掉一些特殊的错误,不计入故障中,尝试再次执行 292 //快速下载时执行失败的区块不需要记录错误信息,并删除index中此区块的信息尝试通过普通模式再次下载执行 293 ok := IsRecordFaultErr(err) 294 295 if node.pid == "download" || (!ok && node.pid == "self") { 296 // 本节点产生的block由于api或者queue导致执行失败需要删除block在index中的记录, 297 // 返回错误信息给共识模块,由共识模块尝试再次发起block的执行 298 // 同步或者广播过来的情况会在下一个区块过来后重新触发此block的执行 299 chainlog.Debug("connectBlock DelNode!", "height", block.Height, "node.hash", common.ToHex(node.hash), "err", err) 300 chain.index.DelNode(node.hash) 301 } else { 302 chain.RecordFaultPeer(node.pid, block.Height, node.hash, err) 303 } 304 chainlog.Error("connectBlock ExecBlock is err!", "height", block.Height, "err", err) 305 return nil, err 306 } 307 cfg := chain.client.GetConfig() 308 //要更新node的信息 309 if node.pid == "self" { 310 prevhash := node.hash 311 node.statehash = blockdetail.Block.GetStateHash() 312 node.hash = blockdetail.Block.Hash(cfg) 313 chain.index.UpdateNode(prevhash, node) 314 } 315 316 // 写入磁盘 批量将block信息写入磁盘 317 newbatch := chain.blockStore.batch 318 newbatch.Reset() 319 newbatch.UpdateWriteSync(sync) 320 //保存tx信息到db中 321 beg := types.Now() 322 err = chain.blockStore.AddTxs(newbatch, blockdetail) 323 if err != nil { 324 chainlog.Error("connectBlock indexTxs:", "height", block.Height, "err", err) 325 return nil, err 326 } 327 txCost := types.Since(beg) 328 beg = types.Now() 329 //保存block信息到db中 330 lastSequence, err = chain.blockStore.SaveBlock(newbatch, blockdetail, node.sequence) 331 if err != nil { 332 chainlog.Error("connectBlock SaveBlock:", "height", block.Height, "err", err) 333 return nil, err 334 } 335 saveBlkCost := types.Since(beg) 336 //hashCache new add block 337 beg = types.Now() 338 chain.AddCacheBlock(blockdetail) 339 cacheCost := types.Since(beg) 340 341 //保存block的总难度到db中 342 difficulty := difficulty.CalcWork(block.Difficulty) 343 var blocktd *big.Int 344 if block.Height == 0 { 345 blocktd = difficulty 346 } else { 347 parenttd, err := chain.blockStore.GetTdByBlockHash(parentHash) 348 if err != nil { 349 chainlog.Error("connectBlock GetTdByBlockHash", "height", block.Height, "parentHash", common.ToHex(parentHash)) 350 return nil, err 351 } 352 blocktd = new(big.Int).Add(difficulty, parenttd) 353 } 354 355 err = chain.blockStore.SaveTdByBlockHash(newbatch, blockdetail.Block.Hash(cfg), blocktd) 356 if err != nil { 357 chainlog.Error("connectBlock SaveTdByBlockHash:", "height", block.Height, "err", err) 358 return nil, err 359 } 360 beg = types.Now() 361 err = newbatch.Write() 362 if err != nil { 363 chainlog.Error("connectBlock newbatch.Write", "err", err) 364 panic(err) 365 } 366 writeCost := types.Since(beg) 367 chainlog.Debug("ConnectBlock", "execLocal", txCost, "saveBlk", saveBlkCost, "cacheBlk", cacheCost, "writeBatch", writeCost) 368 chainlog.Debug("connectBlock info", "height", block.Height, "batchsync", sync, "hash", common.ToHex(blockdetail.Block.Hash(cfg))) 369 370 // 更新最新的高度和header 371 chain.blockStore.UpdateHeight2(blockdetail.GetBlock().GetHeight()) 372 chain.blockStore.UpdateLastBlock2(blockdetail.Block) 373 374 // 更新 best chain的tip节点 375 chain.bestChain.SetTip(node) 376 377 chain.query.updateStateHash(blockdetail.GetBlock().GetStateHash()) 378 379 err = chain.SendAddBlockEvent(blockdetail) 380 if err != nil { 381 chainlog.Debug("connectBlock SendAddBlockEvent", "err", err) 382 } 383 // 通知此block已经处理完,主要处理孤儿节点时需要设置 384 chain.syncTask.Done(blockdetail.Block.GetHeight()) 385 386 //广播此block到全网络 387 if node.broadcast && !chain.cfg.DisableBlockBroadcast { 388 if blockdetail.Block.BlockTime-types.Now().Unix() > FutureBlockDelayTime { 389 //将此block添加到futureblocks中延时广播 390 chain.futureBlocks.Add(string(blockdetail.Block.Hash(cfg)), blockdetail) 391 chainlog.Debug("connectBlock futureBlocks.Add", "height", block.Height, "hash", common.ToHex(blockdetail.Block.Hash(cfg)), "blocktime", blockdetail.Block.BlockTime, "curtime", types.Now().Unix()) 392 } else { 393 chain.SendBlockBroadcast(blockdetail) 394 } 395 } 396 397 //目前非平行链并开启isRecordBlockSequence功能和enablePushSubscribe 398 if chain.isRecordBlockSequence && chain.enablePushSubscribe { 399 chain.push.UpdateSeq(lastSequence) 400 chainlog.Debug("isRecordBlockSequence", "lastSequence", lastSequence, "height", block.Height) 401 } 402 return blockdetail, nil 403 } 404 405 //从主链中删除blocks 406 func (chain *BlockChain) disconnectBlock(node *blockNode, blockdetail *types.BlockDetail, sequence int64) error { 407 var lastSequence int64 408 // 只能从 best chain tip节点开始删除 409 if !bytes.Equal(node.hash, chain.bestChain.Tip().hash) { 410 chainlog.Error("disconnectBlock:", "height", blockdetail.Block.Height, "node.hash", common.ToHex(node.hash), "bestChain.top.hash", common.ToHex(chain.bestChain.Tip().hash)) 411 return types.ErrBlockHashNoMatch 412 } 413 414 //批量删除block的信息从磁盘中 415 newbatch := chain.blockStore.NewBatch(true) 416 417 //从db中删除tx相关的信息 418 err := chain.blockStore.DelTxs(newbatch, blockdetail) 419 if err != nil { 420 chainlog.Error("disconnectBlock DelTxs:", "height", blockdetail.Block.Height, "err", err) 421 return err 422 } 423 //优先删除缓存中的block信息 424 chain.DelCacheBlock(blockdetail.Block.Height, node.hash) 425 426 //从db中删除block相关的信息 427 lastSequence, err = chain.blockStore.DelBlock(newbatch, blockdetail, sequence) 428 if err != nil { 429 chainlog.Error("disconnectBlock DelBlock:", "height", blockdetail.Block.Height, "err", err) 430 return err 431 } 432 err = newbatch.Write() 433 if err != nil { 434 chainlog.Error("disconnectBlock newbatch.Write", "err", err) 435 panic(err) 436 } 437 //更新最新的高度和header为上一个块 438 chain.blockStore.UpdateHeight() 439 chain.blockStore.UpdateLastBlock(blockdetail.Block.ParentHash) 440 441 // 删除主链的tip节点,将其父节点升级成tip节点 442 chain.bestChain.DelTip(node) 443 444 //通知共识,mempool和钱包删除block 445 err = chain.SendDelBlockEvent(blockdetail) 446 if err != nil { 447 chainlog.Error("disconnectBlock SendDelBlockEvent", "err", err) 448 } 449 chain.query.updateStateHash(node.parent.statehash) 450 451 //确定node的父节点升级成tip节点 452 newtipnode := chain.bestChain.Tip() 453 454 if newtipnode != node.parent { 455 chainlog.Error("disconnectBlock newtipnode err:", "newtipnode.height", newtipnode.height, "node.parent.height", node.parent.height) 456 } 457 if !bytes.Equal(blockdetail.Block.GetParentHash(), chain.bestChain.Tip().hash) { 458 chainlog.Error("disconnectBlock", "newtipnode.height", newtipnode.height, "node.parent.height", node.parent.height) 459 chainlog.Error("disconnectBlock", "newtipnode.hash", common.ToHex(newtipnode.hash), "delblock.parent.hash", common.ToHex(blockdetail.Block.GetParentHash())) 460 } 461 462 chainlog.Debug("disconnectBlock success", "newtipnode.height", newtipnode.height, "node.parent.height", node.parent.height) 463 chainlog.Debug("disconnectBlock success", "newtipnode.hash", common.ToHex(newtipnode.hash), "delblock.parent.hash", common.ToHex(blockdetail.Block.GetParentHash())) 464 465 //目前非平行链并开启isRecordBlockSequence功能和enablePushSubscribe 466 if chain.isRecordBlockSequence && chain.enablePushSubscribe { 467 chain.push.UpdateSeq(lastSequence) 468 chainlog.Debug("isRecordBlockSequence", "lastSequence", lastSequence, "height", blockdetail.Block.Height) 469 } 470 471 return nil 472 } 473 474 //获取重组blockchain需要删除和添加节点 475 func (chain *BlockChain) getReorganizeNodes(node *blockNode) (*list.List, *list.List) { 476 attachNodes := list.New() 477 detachNodes := list.New() 478 479 // 查找到分叉的节点,并将分叉之后的block从index链push到attachNodes中 480 forkNode := chain.bestChain.FindFork(node) 481 for n := node; n != nil && n != forkNode; n = n.parent { 482 attachNodes.PushFront(n) 483 } 484 485 // 查找到分叉的节点,并将分叉之后的block从bestchain链push到attachNodes中 486 for n := chain.bestChain.Tip(); n != nil && n != forkNode; n = n.parent { 487 detachNodes.PushBack(n) 488 } 489 490 return detachNodes, attachNodes 491 } 492 493 //LoadBlockByHash 根据hash值从缓存中查询区块 494 func (chain *BlockChain) LoadBlockByHash(hash []byte) (block *types.BlockDetail, err error) { 495 496 //从缓存的最新区块中获取 497 block = chain.blockCache.GetBlockByHash(hash) 498 if block != nil { 499 return block, err 500 } 501 502 //从缓存的活跃区块中获取 503 block, _ = chain.blockStore.GetActiveBlock(string(hash)) 504 if block != nil { 505 return block, err 506 } 507 508 //从数据库中获取 509 block, err = chain.blockStore.LoadBlockByHash(hash) 510 511 //如果是主链区块需要添加到活跃区块的缓存中 512 if block != nil { 513 mainHash, _ := chain.blockStore.GetBlockHashByHeight(block.Block.GetHeight()) 514 if mainHash != nil && bytes.Equal(mainHash, hash) { 515 chain.blockStore.AddActiveBlock(string(hash), block) 516 } 517 } 518 return block, err 519 } 520 521 //重组blockchain 522 func (chain *BlockChain) reorganizeChain(detachNodes, attachNodes *list.List) error { 523 detachBlocks := make([]*types.BlockDetail, 0, detachNodes.Len()) 524 attachBlocks := make([]*types.BlockDetail, 0, attachNodes.Len()) 525 526 //通过node中的blockhash获取block信息从db中 527 cfg := chain.client.GetConfig() 528 for e := detachNodes.Front(); e != nil; e = e.Next() { 529 n := e.Value.(*blockNode) 530 block, err := chain.LoadBlockByHash(n.hash) 531 532 // 需要删除的blocks 533 if block != nil && err == nil { 534 detachBlocks = append(detachBlocks, block) 535 chainlog.Debug("reorganizeChain detachBlocks ", "height", block.Block.Height, "hash", common.ToHex(block.Block.Hash(cfg))) 536 } else { 537 chainlog.Error("reorganizeChain detachBlocks fail", "height", n.height, "hash", common.ToHex(n.hash), "err", err) 538 return err 539 } 540 } 541 542 for e := attachNodes.Front(); e != nil; e = e.Next() { 543 n := e.Value.(*blockNode) 544 block, err := chain.LoadBlockByHash(n.hash) 545 546 // 需要加载到db的blocks 547 if block != nil && err == nil { 548 attachBlocks = append(attachBlocks, block) 549 chainlog.Debug("reorganizeChain attachBlocks ", "height", block.Block.Height, "hash", common.ToHex(block.Block.Hash(cfg))) 550 } else { 551 chainlog.Error("reorganizeChain attachBlocks fail", "height", n.height, "hash", common.ToHex(n.hash), "err", err) 552 return err 553 } 554 } 555 556 // Disconnect blocks from the main chain. 557 for i, e := 0, detachNodes.Front(); e != nil; i, e = i+1, e.Next() { 558 n := e.Value.(*blockNode) 559 block := detachBlocks[i] 560 561 // Update the database and chain state. 562 err := chain.disconnectBlock(n, block, n.sequence) 563 if err != nil { 564 return err 565 } 566 } 567 568 // Connect the new best chain blocks. 569 for i, e := 0, attachNodes.Front(); e != nil; i, e = i+1, e.Next() { 570 n := e.Value.(*blockNode) 571 block := attachBlocks[i] 572 573 // Update the database and chain state. 574 _, err := chain.connectBlock(n, block) 575 if err != nil { 576 return err 577 } 578 } 579 580 // Log the point where the chain forked and old and new best chain 581 // heads. 582 if attachNodes.Front() != nil { 583 firstAttachNode := attachNodes.Front().Value.(*blockNode) 584 chainlog.Debug("REORGANIZE: Chain forks at hash", "hash", common.ToHex(firstAttachNode.parent.hash), "height", firstAttachNode.parent.height) 585 586 } 587 if detachNodes.Front() != nil { 588 firstDetachNode := detachNodes.Front().Value.(*blockNode) 589 chainlog.Debug("REORGANIZE: Old best chain head was hash", "hash", common.ToHex(firstDetachNode.hash), "height", firstDetachNode.parent.height) 590 591 } 592 if attachNodes.Back() != nil { 593 lastAttachNode := attachNodes.Back().Value.(*blockNode) 594 chainlog.Debug("REORGANIZE: New best chain head is hash", "hash", common.ToHex(lastAttachNode.hash), "height", lastAttachNode.parent.height) 595 } 596 return nil 597 } 598 599 //ProcessDelParaChainBlock 只能从 best chain tip节点开始删除,目前只提供给平行链使用 600 func (chain *BlockChain) ProcessDelParaChainBlock(broadcast bool, blockdetail *types.BlockDetail, pid string, sequence int64) (*types.BlockDetail, bool, bool, error) { 601 602 //获取当前的tip节点 603 tipnode := chain.bestChain.Tip() 604 blockHash := blockdetail.Block.Hash(chain.client.GetConfig()) 605 606 if !bytes.Equal(blockHash, chain.bestChain.Tip().hash) { 607 chainlog.Error("ProcessDelParaChainBlock:", "delblockheight", blockdetail.Block.Height, "delblockHash", common.ToHex(blockHash), "bestChain.top.hash", common.ToHex(chain.bestChain.Tip().hash)) 608 return nil, false, false, types.ErrBlockHashNoMatch 609 } 610 err := chain.disconnectBlock(tipnode, blockdetail, sequence) 611 if err != nil { 612 return nil, false, false, err 613 } 614 //平行链回滚可能出现 向同一高度写哈希相同的区块, 615 // 主链中对应的节点信息已经在disconnectBlock处理函数中删除了 616 // 这里还需要删除index链中对应的节点信息 617 chain.index.DelNode(blockHash) 618 619 return nil, true, false, nil 620 } 621 622 // IsRecordFaultErr 检测此错误是否要记录到故障错误中 623 func IsRecordFaultErr(err error) bool { 624 return err != types.ErrFutureBlock && !api.IsGrpcError(err) && !api.IsQueueError(err) 625 }