github.com/intfoundation/intchain@v0.0.0-20220727031208-4316ad31ca73/miner/unconfirmed.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package miner 18 19 import ( 20 "container/ring" 21 "sync" 22 23 "github.com/intfoundation/intchain/common" 24 "github.com/intfoundation/intchain/core/types" 25 "github.com/intfoundation/intchain/log" 26 ) 27 28 // headerRetriever is used by the unconfirmed block set to verify whether a previously 29 // mined block is part of the canonical chain or not. 30 type headerRetriever interface { 31 // GetHeaderByNumber retrieves the canonical header associated with a block number. 32 GetHeaderByNumber(number uint64) *types.Header 33 } 34 35 // unconfirmedBlock is a small collection of metadata about a locally mined block 36 // that is placed into a unconfirmed set for canonical chain inclusion tracking. 37 type unconfirmedBlock struct { 38 index uint64 39 hash common.Hash 40 } 41 42 // unconfirmedBlocks implements a data structure to maintain locally mined blocks 43 // have have not yet reached enough maturity to guarantee chain inclusion. It is 44 // used by the miner to provide logs to the user when a previously mined block 45 // has a high enough guarantee to not be reorged out of the canonical chain. 46 type unconfirmedBlocks struct { 47 chain headerRetriever // Blockchain to verify canonical status through 48 depth uint // Depth after which to discard previous blocks 49 blocks *ring.Ring // Block infos to allow canonical chain cross checks 50 lock sync.RWMutex // Protects the fields from concurrent access 51 logger log.Logger 52 } 53 54 // newUnconfirmedBlocks returns new data structure to track currently unconfirmed blocks. 55 func newUnconfirmedBlocks(chain headerRetriever, depth uint, logger log.Logger) *unconfirmedBlocks { 56 return &unconfirmedBlocks{ 57 chain: chain, 58 depth: depth, 59 logger: logger, 60 } 61 } 62 63 // Insert adds a new block to the set of unconfirmed ones. 64 func (set *unconfirmedBlocks) Insert(index uint64, hash common.Hash) { 65 // If a new block was mined locally, shift out any old enough blocks 66 set.Shift(index) 67 68 // Create the new item as its own ring 69 item := ring.New(1) 70 item.Value = &unconfirmedBlock{ 71 index: index, 72 hash: hash, 73 } 74 // Set as the initial ring or append to the end 75 set.lock.Lock() 76 defer set.lock.Unlock() 77 78 if set.blocks == nil { 79 set.blocks = item 80 } else { 81 set.blocks.Move(-1).Link(item) 82 } 83 // Display a log for the user to notify of a new mined block unconfirmed 84 set.logger.Info("🔨 mined potential block", "number", index, "hash", hash) 85 } 86 87 // Shift drops all unconfirmed blocks from the set which exceed the unconfirmed sets depth 88 // allowance, checking them against the canonical chain for inclusion or staleness 89 // report. 90 func (set *unconfirmedBlocks) Shift(height uint64) { 91 set.lock.Lock() 92 defer set.lock.Unlock() 93 94 for set.blocks != nil { 95 // Retrieve the next unconfirmed block and abort if too fresh 96 next := set.blocks.Value.(*unconfirmedBlock) 97 if next.index+uint64(set.depth) > height { 98 break 99 } 100 // Block seems to exceed depth allowance, check for canonical status 101 header := set.chain.GetHeaderByNumber(next.index) 102 switch { 103 case header == nil: 104 set.logger.Warn("Failed to retrieve header of mined block", "number", next.index, "hash", next.hash) 105 case header.Hash() == next.hash: 106 set.logger.Info("🔗 block reached canonical chain", "number", next.index, "hash", next.hash) 107 default: 108 set.logger.Info("⑂ block became a side fork", "number", next.index, "hash", next.hash) 109 } 110 // Drop the block out of the ring 111 if set.blocks.Value == set.blocks.Next().Value { 112 set.blocks = nil 113 } else { 114 set.blocks = set.blocks.Move(-1) 115 set.blocks.Unlink(1) 116 set.blocks = set.blocks.Move(1) 117 } 118 } 119 }