InsertReceiptChain attempts to complete an already existing header chain with transaction and receipt data.
(blockChain types.Blocks, receiptChain []types.Receipts)
| 956 | // InsertReceiptChain attempts to complete an already existing header chain with |
| 957 | // transaction and receipt data. |
| 958 | func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) { |
| 959 | bc.wg.Add(1) |
| 960 | defer bc.wg.Done() |
| 961 | |
| 962 | // Do a sanity check that the provided chain is actually ordered and linked |
| 963 | for i := 1; i < len(blockChain); i++ { |
| 964 | if blockChain[i].NumberU64() != blockChain[i-1].NumberU64()+1 || blockChain[i].ParentHash() != blockChain[i-1].Hash() { |
| 965 | log.Error("Non contiguous receipt insert", "number", blockChain[i].Number(), "hash", blockChain[i].Hash().Hex(), "parent", blockChain[i].ParentHash().Hex(), |
| 966 | "prevnumber", blockChain[i-1].Number(), "prevhash", blockChain[i-1].Hash().Hex()) |
| 967 | return 0, fmt.Errorf("non contiguous insert: item %d is #%d [%x…], item %d is #%d [%x…] (parent [%x…])", i-1, blockChain[i-1].NumberU64(), |
| 968 | blockChain[i-1].Hash().Bytes()[:4], i, blockChain[i].NumberU64(), blockChain[i].Hash().Bytes()[:4], blockChain[i].ParentHash().Bytes()[:4]) |
| 969 | } |
| 970 | } |
| 971 | |
| 972 | var ( |
| 973 | stats = struct{ processed, ignored int32 }{} |
| 974 | start = time.Now() |
| 975 | bytes = 0 |
| 976 | batch = bc.db.NewBatch() |
| 977 | ) |
| 978 | for i, block := range blockChain { |
| 979 | receipts := receiptChain[i] |
| 980 | // Short circuit insertion if shutting down or processing failed |
| 981 | if atomic.LoadInt32(&bc.procInterrupt) == 1 { |
| 982 | return 0, nil |
| 983 | } |
| 984 | // Short circuit if the owner header is unknown |
| 985 | if !bc.HasHeader(block.Hash(), block.NumberU64()) { |
| 986 | return i, fmt.Errorf("containing header #%d [%x…] unknown", block.Number(), block.Hash().Bytes()[:4]) |
| 987 | } |
| 988 | // Skip if the entire data is already known |
| 989 | if bc.HasBlock(block.Hash(), block.NumberU64()) { |
| 990 | stats.ignored++ |
| 991 | continue |
| 992 | } |
| 993 | // Compute all the non-consensus fields of the receipts |
| 994 | if err := SetReceiptsData(bc.chainConfig, block, receipts); err != nil { |
| 995 | return i, fmt.Errorf("failed to set receipts data: %v", err) |
| 996 | } |
| 997 | // Write all the data out into the database |
| 998 | rawdb.WriteBody(batch, block.Hash(), block.NumberU64(), block.Body()) |
| 999 | rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receipts) |
| 1000 | rawdb.WriteTxLookupEntries(batch, block) |
| 1001 | |
| 1002 | stats.processed++ |
| 1003 | |
| 1004 | if batch.ValueSize() >= database.IdealBatchSize { |
| 1005 | if err := batch.Write(); err != nil { |
| 1006 | return 0, err |
| 1007 | } |
| 1008 | bytes += batch.ValueSize() |
| 1009 | batch.Reset() |
| 1010 | } |
| 1011 | } |
| 1012 | if batch.ValueSize() > 0 { |
| 1013 | bytes += batch.ValueSize() |
| 1014 | if err := batch.Write(); err != nil { |
| 1015 | return 0, err |
nothing calls this directly
no test coverage detected