github.com/palcoin-project/palcd@v1.0.0/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/palcoin-project/palcd/chaincfg" 14 "github.com/palcoin-project/palcd/chaincfg/chainhash" 15 "github.com/palcoin-project/palcd/database" 16 "github.com/palcoin-project/palcd/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 97 // status is a bitfield representing the validation state of the block. The 98 // status field, unlike the other fields, may be written to and so should 99 // only be accessed using the concurrent-safe NodeStatus method on 100 // blockIndex once the node has been added to the global index. 101 status blockStatus 102 } 103 104 // initBlockNode initializes a block node from the given header and parent node, 105 // calculating the height and workSum from the respective fields on the parent. 106 // This function is NOT safe for concurrent access. It must only be called when 107 // initially creating a node. 108 func initBlockNode(node *blockNode, blockHeader *wire.BlockHeader, parent *blockNode) { 109 *node = blockNode{ 110 hash: blockHeader.BlockHash(), 111 workSum: CalcWork(blockHeader.Bits), 112 version: blockHeader.Version, 113 bits: blockHeader.Bits, 114 nonce: blockHeader.Nonce, 115 timestamp: blockHeader.Timestamp.Unix(), 116 merkleRoot: blockHeader.MerkleRoot, 117 } 118 if parent != nil { 119 node.parent = parent 120 node.height = parent.height + 1 121 node.workSum = node.workSum.Add(parent.workSum, node.workSum) 122 } 123 } 124 125 // newBlockNode returns a new block node for the given block header and parent 126 // node, calculating the height and workSum from the respective fields on the 127 // parent. This function is NOT safe for concurrent access. 128 func newBlockNode(blockHeader *wire.BlockHeader, parent *blockNode) *blockNode { 129 var node blockNode 130 initBlockNode(&node, blockHeader, parent) 131 return &node 132 } 133 134 // Header constructs a block header from the node and returns it. 135 // 136 // This function is safe for concurrent access. 137 func (node *blockNode) Header() wire.BlockHeader { 138 // No lock is needed because all accessed fields are immutable. 139 prevHash := &zeroHash 140 if node.parent != nil { 141 prevHash = &node.parent.hash 142 } 143 return wire.BlockHeader{ 144 Version: node.version, 145 PrevBlock: *prevHash, 146 MerkleRoot: node.merkleRoot, 147 Timestamp: time.Unix(node.timestamp, 0), 148 Bits: node.bits, 149 Nonce: node.nonce, 150 } 151 } 152 153 // Ancestor returns the ancestor block node at the provided height by following 154 // the chain backwards from this node. The returned block will be nil when a 155 // height is requested that is after the height of the passed node or is less 156 // than zero. 157 // 158 // This function is safe for concurrent access. 159 func (node *blockNode) Ancestor(height int32) *blockNode { 160 if height < 0 || height > node.height { 161 return nil 162 } 163 164 n := node 165 for ; n != nil && n.height != height; n = n.parent { 166 // Intentionally left blank 167 } 168 169 return n 170 } 171 172 // RelativeAncestor returns the ancestor block node a relative 'distance' blocks 173 // before this node. This is equivalent to calling Ancestor with the node's 174 // height minus provided distance. 175 // 176 // This function is safe for concurrent access. 177 func (node *blockNode) RelativeAncestor(distance int32) *blockNode { 178 return node.Ancestor(node.height - distance) 179 } 180 181 // CalcPastMedianTime calculates the median time of the previous few blocks 182 // prior to, and including, the block node. 183 // 184 // This function is safe for concurrent access. 185 func (node *blockNode) CalcPastMedianTime() time.Time { 186 // Create a slice of the previous few block timestamps used to calculate 187 // the median per the number defined by the constant medianTimeBlocks. 188 timestamps := make([]int64, medianTimeBlocks) 189 numNodes := 0 190 iterNode := node 191 for i := 0; i < medianTimeBlocks && iterNode != nil; i++ { 192 timestamps[i] = iterNode.timestamp 193 numNodes++ 194 195 iterNode = iterNode.parent 196 } 197 198 // Prune the slice to the actual number of available timestamps which 199 // will be fewer than desired near the beginning of the block chain 200 // and sort them. 201 timestamps = timestamps[:numNodes] 202 sort.Sort(timeSorter(timestamps)) 203 204 // NOTE: The consensus rules incorrectly calculate the median for even 205 // numbers of blocks. A true median averages the middle two elements 206 // for a set with an even number of elements in it. Since the constant 207 // for the previous number of blocks to be used is odd, this is only an 208 // issue for a few blocks near the beginning of the chain. I suspect 209 // this is an optimization even though the result is slightly wrong for 210 // a few of the first blocks since after the first few blocks, there 211 // will always be an odd number of blocks in the set per the constant. 212 // 213 // This code follows suit to ensure the same rules are used, however, be 214 // aware that should the medianTimeBlocks constant ever be changed to an 215 // even number, this code will be wrong. 216 medianTimestamp := timestamps[numNodes/2] 217 return time.Unix(medianTimestamp, 0) 218 } 219 220 // blockIndex provides facilities for keeping track of an in-memory index of the 221 // block chain. Although the name block chain suggests a single chain of 222 // blocks, it is actually a tree-shaped structure where any node can have 223 // multiple children. However, there can only be one active branch which does 224 // indeed form a chain from the tip all the way back to the genesis block. 225 type blockIndex struct { 226 // The following fields are set when the instance is created and can't 227 // be changed afterwards, so there is no need to protect them with a 228 // separate mutex. 229 db database.DB 230 chainParams *chaincfg.Params 231 232 sync.RWMutex 233 index map[chainhash.Hash]*blockNode 234 dirty map[*blockNode]struct{} 235 } 236 237 // newBlockIndex returns a new empty instance of a block index. The index will 238 // be dynamically populated as block nodes are loaded from the database and 239 // manually added. 240 func newBlockIndex(db database.DB, chainParams *chaincfg.Params) *blockIndex { 241 return &blockIndex{ 242 db: db, 243 chainParams: chainParams, 244 index: make(map[chainhash.Hash]*blockNode), 245 dirty: make(map[*blockNode]struct{}), 246 } 247 } 248 249 // HaveBlock returns whether or not the block index contains the provided hash. 250 // 251 // This function is safe for concurrent access. 252 func (bi *blockIndex) HaveBlock(hash *chainhash.Hash) bool { 253 bi.RLock() 254 _, hasBlock := bi.index[*hash] 255 bi.RUnlock() 256 return hasBlock 257 } 258 259 // LookupNode returns the block node identified by the provided hash. It will 260 // return nil if there is no entry for the hash. 261 // 262 // This function is safe for concurrent access. 263 func (bi *blockIndex) LookupNode(hash *chainhash.Hash) *blockNode { 264 bi.RLock() 265 node := bi.index[*hash] 266 bi.RUnlock() 267 return node 268 } 269 270 // AddNode adds the provided node to the block index and marks it as dirty. 271 // Duplicate entries are not checked so it is up to caller to avoid adding them. 272 // 273 // This function is safe for concurrent access. 274 func (bi *blockIndex) AddNode(node *blockNode) { 275 bi.Lock() 276 bi.addNode(node) 277 bi.dirty[node] = struct{}{} 278 bi.Unlock() 279 } 280 281 // addNode adds the provided node to the block index, but does not mark it as 282 // dirty. This can be used while initializing the block index. 283 // 284 // This function is NOT safe for concurrent access. 285 func (bi *blockIndex) addNode(node *blockNode) { 286 bi.index[node.hash] = node 287 } 288 289 // NodeStatus provides concurrent-safe access to the status field of a node. 290 // 291 // This function is safe for concurrent access. 292 func (bi *blockIndex) NodeStatus(node *blockNode) blockStatus { 293 bi.RLock() 294 status := node.status 295 bi.RUnlock() 296 return status 297 } 298 299 // SetStatusFlags flips the provided status flags on the block node to on, 300 // regardless of whether they were on or off previously. This does not unset any 301 // flags currently on. 302 // 303 // This function is safe for concurrent access. 304 func (bi *blockIndex) SetStatusFlags(node *blockNode, flags blockStatus) { 305 bi.Lock() 306 node.status |= flags 307 bi.dirty[node] = struct{}{} 308 bi.Unlock() 309 } 310 311 // UnsetStatusFlags flips the provided status flags on the block node to off, 312 // regardless of whether they were on or off previously. 313 // 314 // This function is safe for concurrent access. 315 func (bi *blockIndex) UnsetStatusFlags(node *blockNode, flags blockStatus) { 316 bi.Lock() 317 node.status &^= flags 318 bi.dirty[node] = struct{}{} 319 bi.Unlock() 320 } 321 322 // flushToDB writes all dirty block nodes to the database. If all writes 323 // succeed, this clears the dirty set. 324 func (bi *blockIndex) flushToDB() error { 325 bi.Lock() 326 if len(bi.dirty) == 0 { 327 bi.Unlock() 328 return nil 329 } 330 331 err := bi.db.Update(func(dbTx database.Tx) error { 332 for node := range bi.dirty { 333 err := dbStoreBlockNode(dbTx, node) 334 if err != nil { 335 return err 336 } 337 } 338 return nil 339 }) 340 341 // If write was successful, clear the dirty set. 342 if err == nil { 343 bi.dirty = make(map[*blockNode]struct{}) 344 } 345 346 bi.Unlock() 347 return err 348 }