github.com/lbryio/lbcd@v0.22.119/blockchain/blockindex.go (about) 1 // Copyright (c) 2015-2017 The btcsuite developers 2 // Use of this source code is governed by an ISC 3 // license that can be found in the LICENSE file. 4 5 package blockchain 6 7 import ( 8 "math/big" 9 "sort" 10 "sync" 11 "time" 12 13 "github.com/lbryio/lbcd/chaincfg" 14 "github.com/lbryio/lbcd/chaincfg/chainhash" 15 "github.com/lbryio/lbcd/database" 16 "github.com/lbryio/lbcd/wire" 17 ) 18 19 // blockStatus is a bit field representing the validation state of the block. 20 type blockStatus byte 21 22 const ( 23 // statusDataStored indicates that the block's payload is stored on disk. 24 statusDataStored blockStatus = 1 << iota 25 26 // statusValid indicates that the block has been fully validated. 27 statusValid 28 29 // statusValidateFailed indicates that the block has failed validation. 30 statusValidateFailed 31 32 // statusInvalidAncestor indicates that one of the block's ancestors has 33 // has failed validation, thus the block is also invalid. 34 statusInvalidAncestor 35 36 // statusNone indicates that the block has no validation state flags set. 37 // 38 // NOTE: This must be defined last in order to avoid influencing iota. 39 statusNone blockStatus = 0 40 ) 41 42 // HaveData returns whether the full block data is stored in the database. This 43 // will return false for a block node where only the header is downloaded or 44 // kept. 45 func (status blockStatus) HaveData() bool { 46 return status&statusDataStored != 0 47 } 48 49 // KnownValid returns whether the block is known to be valid. This will return 50 // false for a valid block that has not been fully validated yet. 51 func (status blockStatus) KnownValid() bool { 52 return status&statusValid != 0 53 } 54 55 // KnownInvalid returns whether the block is known to be invalid. This may be 56 // because the block itself failed validation or any of its ancestors is 57 // invalid. This will return false for invalid blocks that have not been proven 58 // invalid yet. 59 func (status blockStatus) KnownInvalid() bool { 60 return status&(statusValidateFailed|statusInvalidAncestor) != 0 61 } 62 63 // blockNode represents a block within the block chain and is primarily used to 64 // aid in selecting the best chain to be the main chain. The main chain is 65 // stored into the block database. 66 type blockNode struct { 67 // NOTE: Additions, deletions, or modifications to the order of the 68 // definitions in this struct should not be changed without considering 69 // how it affects alignment on 64-bit platforms. The current order is 70 // specifically crafted to result in minimal padding. There will be 71 // hundreds of thousands of these in memory, so a few extra bytes of 72 // padding adds up. 73 74 // parent is the parent block for this node. 75 parent *blockNode 76 77 // hash is the double sha 256 of the block. 78 hash chainhash.Hash 79 80 // workSum is the total amount of work in the chain up to and including 81 // this node. 82 workSum *big.Int 83 84 // height is the position in the block chain. 85 height int32 86 87 // Some fields from block headers to aid in best chain selection and 88 // reconstructing headers from memory. These must be treated as 89 // immutable and are intentionally ordered to avoid padding on 64-bit 90 // platforms. 91 version int32 92 bits uint32 93 nonce uint32 94 timestamp int64 95 merkleRoot chainhash.Hash 96 claimTrie chainhash.Hash 97 98 // status is a bitfield representing the validation state of the block. The 99 // status field, unlike the other fields, may be written to and so should 100 // only be accessed using the concurrent-safe NodeStatus method on 101 // blockIndex once the node has been added to the global index. 102 status blockStatus 103 } 104 105 // initBlockNode initializes a block node from the given header and parent node, 106 // calculating the height and workSum from the respective fields on the parent. 107 // This function is NOT safe for concurrent access. It must only be called when 108 // initially creating a node. 109 func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parent *blockNode) { 110 *node = blockNode{ 111 hash: blockHeader.BlockHash(), 112 workSum: CalcWork(blockHeader.Bits), 113 version: blockHeader.Version, 114 bits: blockHeader.Bits, 115 nonce: blockHeader.Nonce, 116 timestamp: blockHeader.Timestamp.Unix(), 117 merkleRoot: blockHeader.MerkleRoot, 118 claimTrie: blockHeader.ClaimTrie, 119 } 120 if parent != nil { 121 node.parent = parent 122 node.height = parent.height + 1 123 node.workSum = node.workSum.Add(parent.workSum, node.workSum) 124 } 125 } 126 127 // newBlockNode returns a new block node for the given block header and parent 128 // node, calculating the height and workSum from the respective fields on the 129 // parent. This function is NOT safe for concurrent access. 130 func newBlockNode(blockHeader *wire.BlockHeader, parent *blockNode) *blockNode { 131 var node blockNode 132 initBlockNode(&node, blockHeader, parent) 133 return &node 134 } 135 136 // Header constructs a block header from the node and returns it. 137 // 138 // This function is safe for concurrent access. 139 func (node *blockNode) Header() wire.BlockHeader { 140 // No lock is needed because all accessed fields are immutable. 141 prevHash := &zeroHash 142 if node.parent != nil { 143 prevHash = &node.parent.hash 144 } 145 return wire.BlockHeader{ 146 Version: node.version, 147 PrevBlock: *prevHash, 148 MerkleRoot: node.merkleRoot, 149 ClaimTrie: node.claimTrie, 150 Timestamp: time.Unix(node.timestamp, 0), 151 Bits: node.bits, 152 Nonce: node.nonce, 153 } 154 } 155 156 // Ancestor returns the ancestor block node at the provided height by following 157 // the chain backwards from this node. The returned block will be nil when a 158 // height is requested that is after the height of the passed node or is less 159 // than zero. 160 // 161 // This function is safe for concurrent access. 162 func (node *blockNode) Ancestor(height int32) *blockNode { 163 if height < 0 || height > node.height { 164 return nil 165 } 166 167 n := node 168 for ; n != nil && n.height != height; n = n.parent { 169 // Intentionally left blank 170 } 171 172 return n 173 } 174 175 // RelativeAncestor returns the ancestor block node a relative 'distance' blocks 176 // before this node. This is equivalent to calling Ancestor with the node's 177 // height minus provided distance. 178 // 179 // This function is safe for concurrent access. 180 func (node *blockNode) RelativeAncestor(distance int32) *blockNode { 181 return node.Ancestor(node.height - distance) 182 } 183 184 // CalcPastMedianTime calculates the median time of the previous few blocks 185 // prior to, and including, the block node. 186 // 187 // This function is safe for concurrent access. 188 func (node *blockNode) CalcPastMedianTime() time.Time { 189 // Create a slice of the previous few block timestamps used to calculate 190 // the median per the number defined by the constant medianTimeBlocks. 191 timestamps := make([]int64, medianTimeBlocks) 192 numNodes := 0 193 iterNode := node 194 for i := 0; i < medianTimeBlocks && iterNode != nil; i++ { 195 timestamps[i] = iterNode.timestamp 196 numNodes++ 197 198 iterNode = iterNode.parent 199 } 200 201 // Prune the slice to the actual number of available timestamps which 202 // will be fewer than desired near the beginning of the block chain 203 // and sort them. 204 timestamps = timestamps[:numNodes] 205 sort.Sort(timeSorter(timestamps)) 206 207 // NOTE: The consensus rules incorrectly calculate the median for even 208 // numbers of blocks. A true median averages the middle two elements 209 // for a set with an even number of elements in it. Since the constant 210 // for the previous number of blocks to be used is odd, this is only an 211 // issue for a few blocks near the beginning of the chain. I suspect 212 // this is an optimization even though the result is slightly wrong for 213 // a few of the first blocks since after the first few blocks, there 214 // will always be an odd number of blocks in the set per the constant. 215 // 216 // This code follows suit to ensure the same rules are used, however, be 217 // aware that should the medianTimeBlocks constant ever be changed to an 218 // even number, this code will be wrong. 219 medianTimestamp := timestamps[numNodes/2] 220 return time.Unix(medianTimestamp, 0) 221 } 222 223 // blockIndex provides facilities for keeping track of an in-memory index of the 224 // block chain. Although the name block chain suggests a single chain of 225 // blocks, it is actually a tree-shaped structure where any node can have 226 // multiple children. However, there can only be one active branch which does 227 // indeed form a chain from the tip all the way back to the genesis block. 228 type blockIndex struct { 229 // The following fields are set when the instance is created and can't 230 // be changed afterwards, so there is no need to protect them with a 231 // separate mutex. 232 db database.DB 233 chainParams *chaincfg.Params 234 235 sync.RWMutex 236 index map[chainhash.Hash]*blockNode 237 dirty map[*blockNode]struct{} 238 } 239 240 // newBlockIndex returns a new empty instance of a block index. The index will 241 // be dynamically populated as block nodes are loaded from the database and 242 // manually added. 243 func newBlockIndex(db database.DB, chainParams *chaincfg.Params) *blockIndex { 244 return &blockIndex{ 245 db: db, 246 chainParams: chainParams, 247 index: make(map[chainhash.Hash]*blockNode), 248 dirty: make(map[*blockNode]struct{}), 249 } 250 } 251 252 // HaveBlock returns whether or not the block index contains the provided hash. 253 // 254 // This function is safe for concurrent access. 255 func (bi *blockIndex) HaveBlock(hash *chainhash.Hash) bool { 256 bi.RLock() 257 _, hasBlock := bi.index[*hash] 258 bi.RUnlock() 259 return hasBlock 260 } 261 262 // LookupNode returns the block node identified by the provided hash. It will 263 // return nil if there is no entry for the hash. 264 // 265 // This function is safe for concurrent access. 266 func (bi *blockIndex) LookupNode(hash *chainhash.Hash) *blockNode { 267 bi.RLock() 268 node := bi.index[*hash] 269 bi.RUnlock() 270 return node 271 } 272 273 // AddNode adds the provided node to the block index and marks it as dirty. 274 // Duplicate entries are not checked so it is up to caller to avoid adding them. 275 // 276 // This function is safe for concurrent access. 277 func (bi *blockIndex) AddNode(node *blockNode) { 278 bi.Lock() 279 bi.addNode(node) 280 bi.dirty[node] = struct{}{} 281 bi.Unlock() 282 } 283 284 // addNode adds the provided node to the block index, but does not mark it as 285 // dirty. This can be used while initializing the block index. 286 // 287 // This function is NOT safe for concurrent access. 288 func (bi *blockIndex) addNode(node *blockNode) { 289 bi.index[node.hash] = node 290 } 291 292 // NodeStatus provides concurrent-safe access to the status field of a node. 293 // 294 // This function is safe for concurrent access. 295 func (bi *blockIndex) NodeStatus(node *blockNode) blockStatus { 296 bi.RLock() 297 status := node.status 298 bi.RUnlock() 299 return status 300 } 301 302 // SetStatusFlags flips the provided status flags on the block node to on, 303 // regardless of whether they were on or off previously. This does not unset any 304 // flags currently on. 305 // 306 // This function is safe for concurrent access. 307 func (bi *blockIndex) SetStatusFlags(node *blockNode, flags blockStatus) { 308 bi.Lock() 309 node.status |= flags 310 bi.dirty[node] = struct{}{} 311 bi.Unlock() 312 } 313 314 // UnsetStatusFlags flips the provided status flags on the block node to off, 315 // regardless of whether they were on or off previously. 316 // 317 // This function is safe for concurrent access. 318 func (bi *blockIndex) UnsetStatusFlags(node *blockNode, flags blockStatus) { 319 bi.Lock() 320 node.status &^= flags 321 bi.dirty[node] = struct{}{} 322 bi.Unlock() 323 } 324 325 // flushToDB writes all dirty block nodes to the database. If all writes 326 // succeed, this clears the dirty set. 327 func (bi *blockIndex) flushToDB() error { 328 bi.Lock() 329 if len(bi.dirty) == 0 { 330 bi.Unlock() 331 return nil 332 } 333 334 err := bi.db.Update(func(dbTx database.Tx) error { 335 for node := range bi.dirty { 336 err := dbStoreBlockNode(dbTx, node) 337 if err != nil { 338 return err 339 } 340 } 341 return nil 342 }) 343 344 // If write was successful, clear the dirty set. 345 if err == nil { 346 bi.dirty = make(map[*blockNode]struct{}) 347 } 348 349 bi.Unlock() 350 return err 351 }