github.com/palcoin-project/palcd@v1.0.0/blockchain/chainio.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 "bytes" 9 "encoding/binary" 10 "fmt" 11 "math/big" 12 "sync" 13 "time" 14 15 "github.com/palcoin-project/palcd/chaincfg/chainhash" 16 "github.com/palcoin-project/palcd/database" 17 "github.com/palcoin-project/palcd/wire" 18 "github.com/palcoin-project/palcutil" 19 ) 20 21 const ( 22 // blockHdrSize is the size of a block header. This is simply the 23 // constant from wire and is only provided here for convenience since 24 // wire.MaxBlockHeaderPayload is quite long. 25 blockHdrSize = wire.MaxBlockHeaderPayload 26 27 // latestUtxoSetBucketVersion is the current version of the utxo set 28 // bucket that is used to track all unspent outputs. 29 latestUtxoSetBucketVersion = 2 30 31 // latestSpendJournalBucketVersion is the current version of the spend 32 // journal bucket that is used to track all spent transactions for use 33 // in reorgs. 34 latestSpendJournalBucketVersion = 1 35 ) 36 37 var ( 38 // blockIndexBucketName is the name of the db bucket used to house to the 39 // block headers and contextual information. 40 blockIndexBucketName = []byte("blockheaderidx") 41 42 // hashIndexBucketName is the name of the db bucket used to house to the 43 // block hash -> block height index. 44 hashIndexBucketName = []byte("hashidx") 45 46 // heightIndexBucketName is the name of the db bucket used to house to 47 // the block height -> block hash index. 48 heightIndexBucketName = []byte("heightidx") 49 50 // chainStateKeyName is the name of the db key used to store the best 51 // chain state. 52 chainStateKeyName = []byte("chainstate") 53 54 // spendJournalVersionKeyName is the name of the db key used to store 55 // the version of the spend journal currently in the database. 56 spendJournalVersionKeyName = []byte("spendjournalversion") 57 58 // spendJournalBucketName is the name of the db bucket used to house 59 // transactions outputs that are spent in each block. 60 spendJournalBucketName = []byte("spendjournal") 61 62 // utxoSetVersionKeyName is the name of the db key used to store the 63 // version of the utxo set currently in the database. 64 utxoSetVersionKeyName = []byte("utxosetversion") 65 66 // utxoSetBucketName is the name of the db bucket used to house the 67 // unspent transaction output set. 68 utxoSetBucketName = []byte("utxosetv2") 69 70 // byteOrder is the preferred byte order used for serializing numeric 71 // fields for storage in the database. 72 byteOrder = binary.LittleEndian 73 ) 74 75 // errNotInMainChain signifies that a block hash or height that is not in the 76 // main chain was requested. 77 type errNotInMainChain string 78 79 // Error implements the error interface. 80 func (e errNotInMainChain) Error() string { 81 return string(e) 82 } 83 84 // isNotInMainChainErr returns whether or not the passed error is an 85 // errNotInMainChain error. 86 func isNotInMainChainErr(err error) bool { 87 _, ok := err.(errNotInMainChain) 88 return ok 89 } 90 91 // errDeserialize signifies that a problem was encountered when deserializing 92 // data. 93 type errDeserialize string 94 95 // Error implements the error interface. 96 func (e errDeserialize) Error() string { 97 return string(e) 98 } 99 100 // isDeserializeErr returns whether or not the passed error is an errDeserialize 101 // error. 102 func isDeserializeErr(err error) bool { 103 _, ok := err.(errDeserialize) 104 return ok 105 } 106 107 // isDbBucketNotFoundErr returns whether or not the passed error is a 108 // database.Error with an error code of database.ErrBucketNotFound. 109 func isDbBucketNotFoundErr(err error) bool { 110 dbErr, ok := err.(database.Error) 111 return ok && dbErr.ErrorCode == database.ErrBucketNotFound 112 } 113 114 // dbFetchVersion fetches an individual version with the given key from the 115 // metadata bucket. It is primarily used to track versions on entities such as 116 // buckets. It returns zero if the provided key does not exist. 117 func dbFetchVersion(dbTx database.Tx, key []byte) uint32 { 118 serialized := dbTx.Metadata().Get(key) 119 if serialized == nil { 120 return 0 121 } 122 123 return byteOrder.Uint32(serialized) 124 } 125 126 // dbPutVersion uses an existing database transaction to update the provided 127 // key in the metadata bucket to the given version. It is primarily used to 128 // track versions on entities such as buckets. 129 func dbPutVersion(dbTx database.Tx, key []byte, version uint32) error { 130 var serialized [4]byte 131 byteOrder.PutUint32(serialized[:], version) 132 return dbTx.Metadata().Put(key, serialized[:]) 133 } 134 135 // dbFetchOrCreateVersion uses an existing database transaction to attempt to 136 // fetch the provided key from the metadata bucket as a version and in the case 137 // it doesn't exist, it adds the entry with the provided default version and 138 // returns that. This is useful during upgrades to automatically handle loading 139 // and adding version keys as necessary. 140 func dbFetchOrCreateVersion(dbTx database.Tx, key []byte, defaultVersion uint32) (uint32, error) { 141 version := dbFetchVersion(dbTx, key) 142 if version == 0 { 143 version = defaultVersion 144 err := dbPutVersion(dbTx, key, version) 145 if err != nil { 146 return 0, err 147 } 148 } 149 150 return version, nil 151 } 152 153 // ----------------------------------------------------------------------------- 154 // The transaction spend journal consists of an entry for each block connected 155 // to the main chain which contains the transaction outputs the block spends 156 // serialized such that the order is the reverse of the order they were spent. 157 // 158 // This is required because reorganizing the chain necessarily entails 159 // disconnecting blocks to get back to the point of the fork which implies 160 // unspending all of the transaction outputs that each block previously spent. 161 // Since the utxo set, by definition, only contains unspent transaction outputs, 162 // the spent transaction outputs must be resurrected from somewhere. There is 163 // more than one way this could be done, however this is the most straight 164 // forward method that does not require having a transaction index and unpruned 165 // blockchain. 166 // 167 // NOTE: This format is NOT self describing. The additional details such as 168 // the number of entries (transaction inputs) are expected to come from the 169 // block itself and the utxo set (for legacy entries). The rationale in doing 170 // this is to save space. This is also the reason the spent outputs are 171 // serialized in the reverse order they are spent because later transactions are 172 // allowed to spend outputs from earlier ones in the same block. 173 // 174 // The reserved field below used to keep track of the version of the containing 175 // transaction when the height in the header code was non-zero, however the 176 // height is always non-zero now, but keeping the extra reserved field allows 177 // backwards compatibility. 178 // 179 // The serialized format is: 180 // 181 // [<header code><reserved><compressed txout>],... 182 // 183 // Field Type Size 184 // header code VLQ variable 185 // reserved byte 1 186 // compressed txout 187 // compressed amount VLQ variable 188 // compressed script []byte variable 189 // 190 // The serialized header code format is: 191 // bit 0 - containing transaction is a coinbase 192 // bits 1-x - height of the block that contains the spent txout 193 // 194 // Example 1: 195 // From block 170 in main blockchain. 196 // 197 // 1300320511db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5c 198 // <><><------------------------------------------------------------------> 199 // | | | 200 // | reserved compressed txout 201 // header code 202 // 203 // - header code: 0x13 (coinbase, height 9) 204 // - reserved: 0x00 205 // - compressed txout 0: 206 // - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC) 207 // - 0x05: special script type pay-to-pubkey 208 // - 0x11...5c: x-coordinate of the pubkey 209 // 210 // Example 2: 211 // Adapted from block 100025 in main blockchain. 212 // 213 // 8b99700091f20f006edbc6c4d31bae9f1ccc38538a114bf42de65e868b99700086c64700b2fb57eadf61e106a100a7445a8c3f67898841ec 214 // <----><><----------------------------------------------><----><><----------------------------------------------> 215 // | | | | | | 216 // | reserved compressed txout | reserved compressed txout 217 // header code header code 218 // 219 // - Last spent output: 220 // - header code: 0x8b9970 (not coinbase, height 100024) 221 // - reserved: 0x00 222 // - compressed txout: 223 // - 0x91f20f: VLQ-encoded compressed amount for 34405000000 (344.05 BTC) 224 // - 0x00: special script type pay-to-pubkey-hash 225 // - 0x6e...86: pubkey hash 226 // - Second to last spent output: 227 // - header code: 0x8b9970 (not coinbase, height 100024) 228 // - reserved: 0x00 229 // - compressed txout: 230 // - 0x86c647: VLQ-encoded compressed amount for 13761000000 (137.61 BTC) 231 // - 0x00: special script type pay-to-pubkey-hash 232 // - 0xb2...ec: pubkey hash 233 // ----------------------------------------------------------------------------- 234 235 // SpentTxOut contains a spent transaction output and potentially additional 236 // contextual information such as whether or not it was contained in a coinbase 237 // transaction, the version of the transaction it was contained in, and which 238 // block height the containing transaction was included in. As described in 239 // the comments above, the additional contextual information will only be valid 240 // when this spent txout is spending the last unspent output of the containing 241 // transaction. 242 type SpentTxOut struct { 243 // Amount is the amount of the output. 244 Amount int64 245 246 // PkScipt is the the public key script for the output. 247 PkScript []byte 248 249 // Height is the height of the the block containing the creating tx. 250 Height int32 251 252 // Denotes if the creating tx is a coinbase. 253 IsCoinBase bool 254 } 255 256 // FetchSpendJournal attempts to retrieve the spend journal, or the set of 257 // outputs spent for the target block. This provides a view of all the outputs 258 // that will be consumed once the target block is connected to the end of the 259 // main chain. 260 // 261 // This function is safe for concurrent access. 262 func (b *BlockChain) FetchSpendJournal(targetBlock *palcutil.Block) ([]SpentTxOut, error) { 263 b.chainLock.RLock() 264 defer b.chainLock.RUnlock() 265 266 var spendEntries []SpentTxOut 267 err := b.db.View(func(dbTx database.Tx) error { 268 var err error 269 270 spendEntries, err = dbFetchSpendJournalEntry(dbTx, targetBlock) 271 return err 272 }) 273 if err != nil { 274 return nil, err 275 } 276 277 return spendEntries, nil 278 } 279 280 // spentTxOutHeaderCode returns the calculated header code to be used when 281 // serializing the provided stxo entry. 282 func spentTxOutHeaderCode(stxo *SpentTxOut) uint64 { 283 // As described in the serialization format comments, the header code 284 // encodes the height shifted over one bit and the coinbase flag in the 285 // lowest bit. 286 headerCode := uint64(stxo.Height) << 1 287 if stxo.IsCoinBase { 288 headerCode |= 0x01 289 } 290 291 return headerCode 292 } 293 294 // spentTxOutSerializeSize returns the number of bytes it would take to 295 // serialize the passed stxo according to the format described above. 296 func spentTxOutSerializeSize(stxo *SpentTxOut) int { 297 size := serializeSizeVLQ(spentTxOutHeaderCode(stxo)) 298 if stxo.Height > 0 { 299 // The legacy v1 spend journal format conditionally tracked the 300 // containing transaction version when the height was non-zero, 301 // so this is required for backwards compat. 302 size += serializeSizeVLQ(0) 303 } 304 return size + compressedTxOutSize(uint64(stxo.Amount), stxo.PkScript) 305 } 306 307 // putSpentTxOut serializes the passed stxo according to the format described 308 // above directly into the passed target byte slice. The target byte slice must 309 // be at least large enough to handle the number of bytes returned by the 310 // SpentTxOutSerializeSize function or it will panic. 311 func putSpentTxOut(target []byte, stxo *SpentTxOut) int { 312 headerCode := spentTxOutHeaderCode(stxo) 313 offset := putVLQ(target, headerCode) 314 if stxo.Height > 0 { 315 // The legacy v1 spend journal format conditionally tracked the 316 // containing transaction version when the height was non-zero, 317 // so this is required for backwards compat. 318 offset += putVLQ(target[offset:], 0) 319 } 320 return offset + putCompressedTxOut(target[offset:], uint64(stxo.Amount), 321 stxo.PkScript) 322 } 323 324 // decodeSpentTxOut decodes the passed serialized stxo entry, possibly followed 325 // by other data, into the passed stxo struct. It returns the number of bytes 326 // read. 327 func decodeSpentTxOut(serialized []byte, stxo *SpentTxOut) (int, error) { 328 // Ensure there are bytes to decode. 329 if len(serialized) == 0 { 330 return 0, errDeserialize("no serialized bytes") 331 } 332 333 // Deserialize the header code. 334 code, offset := deserializeVLQ(serialized) 335 if offset >= len(serialized) { 336 return offset, errDeserialize("unexpected end of data after " + 337 "header code") 338 } 339 340 // Decode the header code. 341 // 342 // Bit 0 indicates containing transaction is a coinbase. 343 // Bits 1-x encode height of containing transaction. 344 stxo.IsCoinBase = code&0x01 != 0 345 stxo.Height = int32(code >> 1) 346 if stxo.Height > 0 { 347 // The legacy v1 spend journal format conditionally tracked the 348 // containing transaction version when the height was non-zero, 349 // so this is required for backwards compat. 350 _, bytesRead := deserializeVLQ(serialized[offset:]) 351 offset += bytesRead 352 if offset >= len(serialized) { 353 return offset, errDeserialize("unexpected end of data " + 354 "after reserved") 355 } 356 } 357 358 // Decode the compressed txout. 359 amount, pkScript, bytesRead, err := decodeCompressedTxOut( 360 serialized[offset:]) 361 offset += bytesRead 362 if err != nil { 363 return offset, errDeserialize(fmt.Sprintf("unable to decode "+ 364 "txout: %v", err)) 365 } 366 stxo.Amount = int64(amount) 367 stxo.PkScript = pkScript 368 return offset, nil 369 } 370 371 // deserializeSpendJournalEntry decodes the passed serialized byte slice into a 372 // slice of spent txouts according to the format described in detail above. 373 // 374 // Since the serialization format is not self describing, as noted in the 375 // format comments, this function also requires the transactions that spend the 376 // txouts. 377 func deserializeSpendJournalEntry(serialized []byte, txns []*wire.MsgTx) ([]SpentTxOut, error) { 378 // Calculate the total number of stxos. 379 var numStxos int 380 for _, tx := range txns { 381 numStxos += len(tx.TxIn) 382 } 383 384 // When a block has no spent txouts there is nothing to serialize. 385 if len(serialized) == 0 { 386 // Ensure the block actually has no stxos. This should never 387 // happen unless there is database corruption or an empty entry 388 // erroneously made its way into the database. 389 if numStxos != 0 { 390 return nil, AssertError(fmt.Sprintf("mismatched spend "+ 391 "journal serialization - no serialization for "+ 392 "expected %d stxos", numStxos)) 393 } 394 395 return nil, nil 396 } 397 398 // Loop backwards through all transactions so everything is read in 399 // reverse order to match the serialization order. 400 stxoIdx := numStxos - 1 401 offset := 0 402 stxos := make([]SpentTxOut, numStxos) 403 for txIdx := len(txns) - 1; txIdx > -1; txIdx-- { 404 tx := txns[txIdx] 405 406 // Loop backwards through all of the transaction inputs and read 407 // the associated stxo. 408 for txInIdx := len(tx.TxIn) - 1; txInIdx > -1; txInIdx-- { 409 txIn := tx.TxIn[txInIdx] 410 stxo := &stxos[stxoIdx] 411 stxoIdx-- 412 413 n, err := decodeSpentTxOut(serialized[offset:], stxo) 414 offset += n 415 if err != nil { 416 return nil, errDeserialize(fmt.Sprintf("unable "+ 417 "to decode stxo for %v: %v", 418 txIn.PreviousOutPoint, err)) 419 } 420 } 421 } 422 423 return stxos, nil 424 } 425 426 // serializeSpendJournalEntry serializes all of the passed spent txouts into a 427 // single byte slice according to the format described in detail above. 428 func serializeSpendJournalEntry(stxos []SpentTxOut) []byte { 429 if len(stxos) == 0 { 430 return nil 431 } 432 433 // Calculate the size needed to serialize the entire journal entry. 434 var size int 435 for i := range stxos { 436 size += spentTxOutSerializeSize(&stxos[i]) 437 } 438 serialized := make([]byte, size) 439 440 // Serialize each individual stxo directly into the slice in reverse 441 // order one after the other. 442 var offset int 443 for i := len(stxos) - 1; i > -1; i-- { 444 offset += putSpentTxOut(serialized[offset:], &stxos[i]) 445 } 446 447 return serialized 448 } 449 450 // dbFetchSpendJournalEntry fetches the spend journal entry for the passed block 451 // and deserializes it into a slice of spent txout entries. 452 // 453 // NOTE: Legacy entries will not have the coinbase flag or height set unless it 454 // was the final output spend in the containing transaction. It is up to the 455 // caller to handle this properly by looking the information up in the utxo set. 456 func dbFetchSpendJournalEntry(dbTx database.Tx, block *palcutil.Block) ([]SpentTxOut, error) { 457 // Exclude the coinbase transaction since it can't spend anything. 458 spendBucket := dbTx.Metadata().Bucket(spendJournalBucketName) 459 serialized := spendBucket.Get(block.Hash()[:]) 460 blockTxns := block.MsgBlock().Transactions[1:] 461 stxos, err := deserializeSpendJournalEntry(serialized, blockTxns) 462 if err != nil { 463 // Ensure any deserialization errors are returned as database 464 // corruption errors. 465 if isDeserializeErr(err) { 466 return nil, database.Error{ 467 ErrorCode: database.ErrCorruption, 468 Description: fmt.Sprintf("corrupt spend "+ 469 "information for %v: %v", block.Hash(), 470 err), 471 } 472 } 473 474 return nil, err 475 } 476 477 return stxos, nil 478 } 479 480 // dbPutSpendJournalEntry uses an existing database transaction to update the 481 // spend journal entry for the given block hash using the provided slice of 482 // spent txouts. The spent txouts slice must contain an entry for every txout 483 // the transactions in the block spend in the order they are spent. 484 func dbPutSpendJournalEntry(dbTx database.Tx, blockHash *chainhash.Hash, stxos []SpentTxOut) error { 485 spendBucket := dbTx.Metadata().Bucket(spendJournalBucketName) 486 serialized := serializeSpendJournalEntry(stxos) 487 return spendBucket.Put(blockHash[:], serialized) 488 } 489 490 // dbRemoveSpendJournalEntry uses an existing database transaction to remove the 491 // spend journal entry for the passed block hash. 492 func dbRemoveSpendJournalEntry(dbTx database.Tx, blockHash *chainhash.Hash) error { 493 spendBucket := dbTx.Metadata().Bucket(spendJournalBucketName) 494 return spendBucket.Delete(blockHash[:]) 495 } 496 497 // ----------------------------------------------------------------------------- 498 // The unspent transaction output (utxo) set consists of an entry for each 499 // unspent output using a format that is optimized to reduce space using domain 500 // specific compression algorithms. This format is a slightly modified version 501 // of the format used in Bitcoin Core. 502 // 503 // Each entry is keyed by an outpoint as specified below. It is important to 504 // note that the key encoding uses a VLQ, which employs an MSB encoding so 505 // iteration of utxos when doing byte-wise comparisons will produce them in 506 // order. 507 // 508 // The serialized key format is: 509 // <hash><output index> 510 // 511 // Field Type Size 512 // hash chainhash.Hash chainhash.HashSize 513 // output index VLQ variable 514 // 515 // The serialized value format is: 516 // 517 // <header code><compressed txout> 518 // 519 // Field Type Size 520 // header code VLQ variable 521 // compressed txout 522 // compressed amount VLQ variable 523 // compressed script []byte variable 524 // 525 // The serialized header code format is: 526 // bit 0 - containing transaction is a coinbase 527 // bits 1-x - height of the block that contains the unspent txout 528 // 529 // Example 1: 530 // From tx in main blockchain: 531 // Blk 1, 0e3e2357e806b6cdb1f70b54c3a3a17b6714ee1f0e68bebb44a74b1efd512098:0 532 // 533 // 03320496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52 534 // <><------------------------------------------------------------------> 535 // | | 536 // header code compressed txout 537 // 538 // - header code: 0x03 (coinbase, height 1) 539 // - compressed txout: 540 // - 0x32: VLQ-encoded compressed amount for 5000000000 (50 BTC) 541 // - 0x04: special script type pay-to-pubkey 542 // - 0x96...52: x-coordinate of the pubkey 543 // 544 // Example 2: 545 // From tx in main blockchain: 546 // Blk 113931, 4a16969aa4764dd7507fc1de7f0baa4850a246de90c45e59a3207f9a26b5036f:2 547 // 548 // 8cf316800900b8025be1b3efc63b0ad48e7f9f10e87544528d58 549 // <----><------------------------------------------> 550 // | | 551 // header code compressed txout 552 // 553 // - header code: 0x8cf316 (not coinbase, height 113931) 554 // - compressed txout: 555 // - 0x8009: VLQ-encoded compressed amount for 15000000 (0.15 BTC) 556 // - 0x00: special script type pay-to-pubkey-hash 557 // - 0xb8...58: pubkey hash 558 // 559 // Example 3: 560 // From tx in main blockchain: 561 // Blk 338156, 1b02d1c8cfef60a189017b9a420c682cf4a0028175f2f563209e4ff61c8c3620:22 562 // 563 // a8a2588ba5b9e763011dd46a006572d820e448e12d2bbb38640bc718e6 564 // <----><--------------------------------------------------> 565 // | | 566 // header code compressed txout 567 // 568 // - header code: 0xa8a258 (not coinbase, height 338156) 569 // - compressed txout: 570 // - 0x8ba5b9e763: VLQ-encoded compressed amount for 366875659 (3.66875659 BTC) 571 // - 0x01: special script type pay-to-script-hash 572 // - 0x1d...e6: script hash 573 // ----------------------------------------------------------------------------- 574 575 // maxUint32VLQSerializeSize is the maximum number of bytes a max uint32 takes 576 // to serialize as a VLQ. 577 var maxUint32VLQSerializeSize = serializeSizeVLQ(1<<32 - 1) 578 579 // outpointKeyPool defines a concurrent safe free list of byte slices used to 580 // provide temporary buffers for outpoint database keys. 581 var outpointKeyPool = sync.Pool{ 582 New: func() interface{} { 583 b := make([]byte, chainhash.HashSize+maxUint32VLQSerializeSize) 584 return &b // Pointer to slice to avoid boxing alloc. 585 }, 586 } 587 588 // outpointKey returns a key suitable for use as a database key in the utxo set 589 // while making use of a free list. A new buffer is allocated if there are not 590 // already any available on the free list. The returned byte slice should be 591 // returned to the free list by using the recycleOutpointKey function when the 592 // caller is done with it _unless_ the slice will need to live for longer than 593 // the caller can calculate such as when used to write to the database. 594 func outpointKey(outpoint wire.OutPoint) *[]byte { 595 // A VLQ employs an MSB encoding, so they are useful not only to reduce 596 // the amount of storage space, but also so iteration of utxos when 597 // doing byte-wise comparisons will produce them in order. 598 key := outpointKeyPool.Get().(*[]byte) 599 idx := uint64(outpoint.Index) 600 *key = (*key)[:chainhash.HashSize+serializeSizeVLQ(idx)] 601 copy(*key, outpoint.Hash[:]) 602 putVLQ((*key)[chainhash.HashSize:], idx) 603 return key 604 } 605 606 // recycleOutpointKey puts the provided byte slice, which should have been 607 // obtained via the outpointKey function, back on the free list. 608 func recycleOutpointKey(key *[]byte) { 609 outpointKeyPool.Put(key) 610 } 611 612 // utxoEntryHeaderCode returns the calculated header code to be used when 613 // serializing the provided utxo entry. 614 func utxoEntryHeaderCode(entry *UtxoEntry) (uint64, error) { 615 if entry.IsSpent() { 616 return 0, AssertError("attempt to serialize spent utxo header") 617 } 618 619 // As described in the serialization format comments, the header code 620 // encodes the height shifted over one bit and the coinbase flag in the 621 // lowest bit. 622 headerCode := uint64(entry.BlockHeight()) << 1 623 if entry.IsCoinBase() { 624 headerCode |= 0x01 625 } 626 627 return headerCode, nil 628 } 629 630 // serializeUtxoEntry returns the entry serialized to a format that is suitable 631 // for long-term storage. The format is described in detail above. 632 func serializeUtxoEntry(entry *UtxoEntry) ([]byte, error) { 633 // Spent outputs have no serialization. 634 if entry.IsSpent() { 635 return nil, nil 636 } 637 638 // Encode the header code. 639 headerCode, err := utxoEntryHeaderCode(entry) 640 if err != nil { 641 return nil, err 642 } 643 644 // Calculate the size needed to serialize the entry. 645 size := serializeSizeVLQ(headerCode) + 646 compressedTxOutSize(uint64(entry.Amount()), entry.PkScript()) 647 648 // Serialize the header code followed by the compressed unspent 649 // transaction output. 650 serialized := make([]byte, size) 651 offset := putVLQ(serialized, headerCode) 652 offset += putCompressedTxOut(serialized[offset:], uint64(entry.Amount()), 653 entry.PkScript()) 654 655 return serialized, nil 656 } 657 658 // deserializeUtxoEntry decodes a utxo entry from the passed serialized byte 659 // slice into a new UtxoEntry using a format that is suitable for long-term 660 // storage. The format is described in detail above. 661 func deserializeUtxoEntry(serialized []byte) (*UtxoEntry, error) { 662 // Deserialize the header code. 663 code, offset := deserializeVLQ(serialized) 664 if offset >= len(serialized) { 665 return nil, errDeserialize("unexpected end of data after header") 666 } 667 668 // Decode the header code. 669 // 670 // Bit 0 indicates whether the containing transaction is a coinbase. 671 // Bits 1-x encode height of containing transaction. 672 isCoinBase := code&0x01 != 0 673 blockHeight := int32(code >> 1) 674 675 // Decode the compressed unspent transaction output. 676 amount, pkScript, _, err := decodeCompressedTxOut(serialized[offset:]) 677 if err != nil { 678 return nil, errDeserialize(fmt.Sprintf("unable to decode "+ 679 "utxo: %v", err)) 680 } 681 682 entry := &UtxoEntry{ 683 amount: int64(amount), 684 pkScript: pkScript, 685 blockHeight: blockHeight, 686 packedFlags: 0, 687 } 688 if isCoinBase { 689 entry.packedFlags |= tfCoinBase 690 } 691 692 return entry, nil 693 } 694 695 // dbFetchUtxoEntryByHash attempts to find and fetch a utxo for the given hash. 696 // It uses a cursor and seek to try and do this as efficiently as possible. 697 // 698 // When there are no entries for the provided hash, nil will be returned for the 699 // both the entry and the error. 700 func dbFetchUtxoEntryByHash(dbTx database.Tx, hash *chainhash.Hash) (*UtxoEntry, error) { 701 // Attempt to find an entry by seeking for the hash along with a zero 702 // index. Due to the fact the keys are serialized as <hash><index>, 703 // where the index uses an MSB encoding, if there are any entries for 704 // the hash at all, one will be found. 705 cursor := dbTx.Metadata().Bucket(utxoSetBucketName).Cursor() 706 key := outpointKey(wire.OutPoint{Hash: *hash, Index: 0}) 707 ok := cursor.Seek(*key) 708 recycleOutpointKey(key) 709 if !ok { 710 return nil, nil 711 } 712 713 // An entry was found, but it could just be an entry with the next 714 // highest hash after the requested one, so make sure the hashes 715 // actually match. 716 cursorKey := cursor.Key() 717 if len(cursorKey) < chainhash.HashSize { 718 return nil, nil 719 } 720 if !bytes.Equal(hash[:], cursorKey[:chainhash.HashSize]) { 721 return nil, nil 722 } 723 724 return deserializeUtxoEntry(cursor.Value()) 725 } 726 727 // dbFetchUtxoEntry uses an existing database transaction to fetch the specified 728 // transaction output from the utxo set. 729 // 730 // When there is no entry for the provided output, nil will be returned for both 731 // the entry and the error. 732 func dbFetchUtxoEntry(dbTx database.Tx, outpoint wire.OutPoint) (*UtxoEntry, error) { 733 // Fetch the unspent transaction output information for the passed 734 // transaction output. Return now when there is no entry. 735 key := outpointKey(outpoint) 736 utxoBucket := dbTx.Metadata().Bucket(utxoSetBucketName) 737 serializedUtxo := utxoBucket.Get(*key) 738 recycleOutpointKey(key) 739 if serializedUtxo == nil { 740 return nil, nil 741 } 742 743 // A non-nil zero-length entry means there is an entry in the database 744 // for a spent transaction output which should never be the case. 745 if len(serializedUtxo) == 0 { 746 return nil, AssertError(fmt.Sprintf("database contains entry "+ 747 "for spent tx output %v", outpoint)) 748 } 749 750 // Deserialize the utxo entry and return it. 751 entry, err := deserializeUtxoEntry(serializedUtxo) 752 if err != nil { 753 // Ensure any deserialization errors are returned as database 754 // corruption errors. 755 if isDeserializeErr(err) { 756 return nil, database.Error{ 757 ErrorCode: database.ErrCorruption, 758 Description: fmt.Sprintf("corrupt utxo entry "+ 759 "for %v: %v", outpoint, err), 760 } 761 } 762 763 return nil, err 764 } 765 766 return entry, nil 767 } 768 769 // dbPutUtxoView uses an existing database transaction to update the utxo set 770 // in the database based on the provided utxo view contents and state. In 771 // particular, only the entries that have been marked as modified are written 772 // to the database. 773 func dbPutUtxoView(dbTx database.Tx, view *UtxoViewpoint) error { 774 utxoBucket := dbTx.Metadata().Bucket(utxoSetBucketName) 775 for outpoint, entry := range view.entries { 776 // No need to update the database if the entry was not modified. 777 if entry == nil || !entry.isModified() { 778 continue 779 } 780 781 // Remove the utxo entry if it is spent. 782 if entry.IsSpent() { 783 key := outpointKey(outpoint) 784 err := utxoBucket.Delete(*key) 785 recycleOutpointKey(key) 786 if err != nil { 787 return err 788 } 789 790 continue 791 } 792 793 // Serialize and store the utxo entry. 794 serialized, err := serializeUtxoEntry(entry) 795 if err != nil { 796 return err 797 } 798 key := outpointKey(outpoint) 799 err = utxoBucket.Put(*key, serialized) 800 // NOTE: The key is intentionally not recycled here since the 801 // database interface contract prohibits modifications. It will 802 // be garbage collected normally when the database is done with 803 // it. 804 if err != nil { 805 return err 806 } 807 } 808 809 return nil 810 } 811 812 // ----------------------------------------------------------------------------- 813 // The block index consists of two buckets with an entry for every block in the 814 // main chain. One bucket is for the hash to height mapping and the other is 815 // for the height to hash mapping. 816 // 817 // The serialized format for values in the hash to height bucket is: 818 // <height> 819 // 820 // Field Type Size 821 // height uint32 4 bytes 822 // 823 // The serialized format for values in the height to hash bucket is: 824 // <hash> 825 // 826 // Field Type Size 827 // hash chainhash.Hash chainhash.HashSize 828 // ----------------------------------------------------------------------------- 829 830 // dbPutBlockIndex uses an existing database transaction to update or add the 831 // block index entries for the hash to height and height to hash mappings for 832 // the provided values. 833 func dbPutBlockIndex(dbTx database.Tx, hash *chainhash.Hash, height int32) error { 834 // Serialize the height for use in the index entries. 835 var serializedHeight [4]byte 836 byteOrder.PutUint32(serializedHeight[:], uint32(height)) 837 838 // Add the block hash to height mapping to the index. 839 meta := dbTx.Metadata() 840 hashIndex := meta.Bucket(hashIndexBucketName) 841 if err := hashIndex.Put(hash[:], serializedHeight[:]); err != nil { 842 return err 843 } 844 845 // Add the block height to hash mapping to the index. 846 heightIndex := meta.Bucket(heightIndexBucketName) 847 return heightIndex.Put(serializedHeight[:], hash[:]) 848 } 849 850 // dbRemoveBlockIndex uses an existing database transaction remove block index 851 // entries from the hash to height and height to hash mappings for the provided 852 // values. 853 func dbRemoveBlockIndex(dbTx database.Tx, hash *chainhash.Hash, height int32) error { 854 // Remove the block hash to height mapping. 855 meta := dbTx.Metadata() 856 hashIndex := meta.Bucket(hashIndexBucketName) 857 if err := hashIndex.Delete(hash[:]); err != nil { 858 return err 859 } 860 861 // Remove the block height to hash mapping. 862 var serializedHeight [4]byte 863 byteOrder.PutUint32(serializedHeight[:], uint32(height)) 864 heightIndex := meta.Bucket(heightIndexBucketName) 865 return heightIndex.Delete(serializedHeight[:]) 866 } 867 868 // dbFetchHeightByHash uses an existing database transaction to retrieve the 869 // height for the provided hash from the index. 870 func dbFetchHeightByHash(dbTx database.Tx, hash *chainhash.Hash) (int32, error) { 871 meta := dbTx.Metadata() 872 hashIndex := meta.Bucket(hashIndexBucketName) 873 serializedHeight := hashIndex.Get(hash[:]) 874 if serializedHeight == nil { 875 str := fmt.Sprintf("block %s is not in the main chain", hash) 876 return 0, errNotInMainChain(str) 877 } 878 879 return int32(byteOrder.Uint32(serializedHeight)), nil 880 } 881 882 // dbFetchHashByHeight uses an existing database transaction to retrieve the 883 // hash for the provided height from the index. 884 func dbFetchHashByHeight(dbTx database.Tx, height int32) (*chainhash.Hash, error) { 885 var serializedHeight [4]byte 886 byteOrder.PutUint32(serializedHeight[:], uint32(height)) 887 888 meta := dbTx.Metadata() 889 heightIndex := meta.Bucket(heightIndexBucketName) 890 hashBytes := heightIndex.Get(serializedHeight[:]) 891 if hashBytes == nil { 892 str := fmt.Sprintf("no block at height %d exists", height) 893 return nil, errNotInMainChain(str) 894 } 895 896 var hash chainhash.Hash 897 copy(hash[:], hashBytes) 898 return &hash, nil 899 } 900 901 // ----------------------------------------------------------------------------- 902 // The best chain state consists of the best block hash and height, the total 903 // number of transactions up to and including those in the best block, and the 904 // accumulated work sum up to and including the best block. 905 // 906 // The serialized format is: 907 // 908 // <block hash><block height><total txns><work sum length><work sum> 909 // 910 // Field Type Size 911 // block hash chainhash.Hash chainhash.HashSize 912 // block height uint32 4 bytes 913 // total txns uint64 8 bytes 914 // work sum length uint32 4 bytes 915 // work sum big.Int work sum length 916 // ----------------------------------------------------------------------------- 917 918 // bestChainState represents the data to be stored the database for the current 919 // best chain state. 920 type bestChainState struct { 921 hash chainhash.Hash 922 height uint32 923 totalTxns uint64 924 workSum *big.Int 925 } 926 927 // serializeBestChainState returns the serialization of the passed block best 928 // chain state. This is data to be stored in the chain state bucket. 929 func serializeBestChainState(state bestChainState) []byte { 930 // Calculate the full size needed to serialize the chain state. 931 workSumBytes := state.workSum.Bytes() 932 workSumBytesLen := uint32(len(workSumBytes)) 933 serializedLen := chainhash.HashSize + 4 + 8 + 4 + workSumBytesLen 934 935 // Serialize the chain state. 936 serializedData := make([]byte, serializedLen) 937 copy(serializedData[0:chainhash.HashSize], state.hash[:]) 938 offset := uint32(chainhash.HashSize) 939 byteOrder.PutUint32(serializedData[offset:], state.height) 940 offset += 4 941 byteOrder.PutUint64(serializedData[offset:], state.totalTxns) 942 offset += 8 943 byteOrder.PutUint32(serializedData[offset:], workSumBytesLen) 944 offset += 4 945 copy(serializedData[offset:], workSumBytes) 946 return serializedData 947 } 948 949 // deserializeBestChainState deserializes the passed serialized best chain 950 // state. This is data stored in the chain state bucket and is updated after 951 // every block is connected or disconnected form the main chain. 952 // block. 953 func deserializeBestChainState(serializedData []byte) (bestChainState, error) { 954 // Ensure the serialized data has enough bytes to properly deserialize 955 // the hash, height, total transactions, and work sum length. 956 if len(serializedData) < chainhash.HashSize+16 { 957 return bestChainState{}, database.Error{ 958 ErrorCode: database.ErrCorruption, 959 Description: "corrupt best chain state", 960 } 961 } 962 963 state := bestChainState{} 964 copy(state.hash[:], serializedData[0:chainhash.HashSize]) 965 offset := uint32(chainhash.HashSize) 966 state.height = byteOrder.Uint32(serializedData[offset : offset+4]) 967 offset += 4 968 state.totalTxns = byteOrder.Uint64(serializedData[offset : offset+8]) 969 offset += 8 970 workSumBytesLen := byteOrder.Uint32(serializedData[offset : offset+4]) 971 offset += 4 972 973 // Ensure the serialized data has enough bytes to deserialize the work 974 // sum. 975 if uint32(len(serializedData[offset:])) < workSumBytesLen { 976 return bestChainState{}, database.Error{ 977 ErrorCode: database.ErrCorruption, 978 Description: "corrupt best chain state", 979 } 980 } 981 workSumBytes := serializedData[offset : offset+workSumBytesLen] 982 state.workSum = new(big.Int).SetBytes(workSumBytes) 983 984 return state, nil 985 } 986 987 // dbPutBestState uses an existing database transaction to update the best chain 988 // state with the given parameters. 989 func dbPutBestState(dbTx database.Tx, snapshot *BestState, workSum *big.Int) error { 990 // Serialize the current best chain state. 991 serializedData := serializeBestChainState(bestChainState{ 992 hash: snapshot.Hash, 993 height: uint32(snapshot.Height), 994 totalTxns: snapshot.TotalTxns, 995 workSum: workSum, 996 }) 997 998 // Store the current best chain state into the database. 999 return dbTx.Metadata().Put(chainStateKeyName, serializedData) 1000 } 1001 1002 // createChainState initializes both the database and the chain state to the 1003 // genesis block. This includes creating the necessary buckets and inserting 1004 // the genesis block, so it must only be called on an uninitialized database. 1005 func (b *BlockChain) createChainState() error { 1006 // Create a new node from the genesis block and set it as the best node. 1007 genesisBlock := palcutil.NewBlock(b.chainParams.GenesisBlock) 1008 genesisBlock.SetHeight(0) 1009 header := &genesisBlock.MsgBlock().Header 1010 node := newBlockNode(header, nil) 1011 node.status = statusDataStored | statusValid 1012 b.bestChain.SetTip(node) 1013 1014 // Add the new node to the index which is used for faster lookups. 1015 b.index.addNode(node) 1016 1017 // Initialize the state related to the best block. Since it is the 1018 // genesis block, use its timestamp for the median time. 1019 numTxns := uint64(len(genesisBlock.MsgBlock().Transactions)) 1020 blockSize := uint64(genesisBlock.MsgBlock().SerializeSize()) 1021 blockWeight := uint64(GetBlockWeight(genesisBlock)) 1022 b.stateSnapshot = newBestState(node, blockSize, blockWeight, numTxns, 1023 numTxns, time.Unix(node.timestamp, 0)) 1024 1025 // Create the initial the database chain state including creating the 1026 // necessary index buckets and inserting the genesis block. 1027 err := b.db.Update(func(dbTx database.Tx) error { 1028 meta := dbTx.Metadata() 1029 1030 // Create the bucket that houses the block index data. 1031 _, err := meta.CreateBucket(blockIndexBucketName) 1032 if err != nil { 1033 return err 1034 } 1035 1036 // Create the bucket that houses the chain block hash to height 1037 // index. 1038 _, err = meta.CreateBucket(hashIndexBucketName) 1039 if err != nil { 1040 return err 1041 } 1042 1043 // Create the bucket that houses the chain block height to hash 1044 // index. 1045 _, err = meta.CreateBucket(heightIndexBucketName) 1046 if err != nil { 1047 return err 1048 } 1049 1050 // Create the bucket that houses the spend journal data and 1051 // store its version. 1052 _, err = meta.CreateBucket(spendJournalBucketName) 1053 if err != nil { 1054 return err 1055 } 1056 err = dbPutVersion(dbTx, utxoSetVersionKeyName, 1057 latestUtxoSetBucketVersion) 1058 if err != nil { 1059 return err 1060 } 1061 1062 // Create the bucket that houses the utxo set and store its 1063 // version. Note that the genesis block coinbase transaction is 1064 // intentionally not inserted here since it is not spendable by 1065 // consensus rules. 1066 _, err = meta.CreateBucket(utxoSetBucketName) 1067 if err != nil { 1068 return err 1069 } 1070 err = dbPutVersion(dbTx, spendJournalVersionKeyName, 1071 latestSpendJournalBucketVersion) 1072 if err != nil { 1073 return err 1074 } 1075 1076 // Save the genesis block to the block index database. 1077 err = dbStoreBlockNode(dbTx, node) 1078 if err != nil { 1079 return err 1080 } 1081 1082 // Add the genesis block hash to height and height to hash 1083 // mappings to the index. 1084 err = dbPutBlockIndex(dbTx, &node.hash, node.height) 1085 if err != nil { 1086 return err 1087 } 1088 1089 // Store the current best chain state into the database. 1090 err = dbPutBestState(dbTx, b.stateSnapshot, node.workSum) 1091 if err != nil { 1092 return err 1093 } 1094 1095 // Store the genesis block into the database. 1096 return dbStoreBlock(dbTx, genesisBlock) 1097 }) 1098 return err 1099 } 1100 1101 // initChainState attempts to load and initialize the chain state from the 1102 // database. When the db does not yet contain any chain state, both it and the 1103 // chain state are initialized to the genesis block. 1104 func (b *BlockChain) initChainState() error { 1105 // Determine the state of the chain database. We may need to initialize 1106 // everything from scratch or upgrade certain buckets. 1107 var initialized, hasBlockIndex bool 1108 err := b.db.View(func(dbTx database.Tx) error { 1109 initialized = dbTx.Metadata().Get(chainStateKeyName) != nil 1110 hasBlockIndex = dbTx.Metadata().Bucket(blockIndexBucketName) != nil 1111 return nil 1112 }) 1113 if err != nil { 1114 return err 1115 } 1116 1117 if !initialized { 1118 // At this point the database has not already been initialized, so 1119 // initialize both it and the chain state to the genesis block. 1120 return b.createChainState() 1121 } 1122 1123 if !hasBlockIndex { 1124 err := migrateBlockIndex(b.db) 1125 if err != nil { 1126 return nil 1127 } 1128 } 1129 1130 // Attempt to load the chain state from the database. 1131 err = b.db.View(func(dbTx database.Tx) error { 1132 // Fetch the stored chain state from the database metadata. 1133 // When it doesn't exist, it means the database hasn't been 1134 // initialized for use with chain yet, so break out now to allow 1135 // that to happen under a writable database transaction. 1136 serializedData := dbTx.Metadata().Get(chainStateKeyName) 1137 log.Tracef("Serialized chain state: %x", serializedData) 1138 state, err := deserializeBestChainState(serializedData) 1139 if err != nil { 1140 return err 1141 } 1142 1143 // Load all of the headers from the data for the known best 1144 // chain and construct the block index accordingly. Since the 1145 // number of nodes are already known, perform a single alloc 1146 // for them versus a whole bunch of little ones to reduce 1147 // pressure on the GC. 1148 log.Infof("Loading block index...") 1149 1150 blockIndexBucket := dbTx.Metadata().Bucket(blockIndexBucketName) 1151 1152 var i int32 1153 var lastNode *blockNode 1154 cursor := blockIndexBucket.Cursor() 1155 for ok := cursor.First(); ok; ok = cursor.Next() { 1156 header, status, err := deserializeBlockRow(cursor.Value()) 1157 if err != nil { 1158 return err 1159 } 1160 1161 // Determine the parent block node. Since we iterate block headers 1162 // in order of height, if the blocks are mostly linear there is a 1163 // very good chance the previous header processed is the parent. 1164 var parent *blockNode 1165 if lastNode == nil { 1166 blockHash := header.BlockHash() 1167 if !blockHash.IsEqual(b.chainParams.GenesisHash) { 1168 return AssertError(fmt.Sprintf("initChainState: Expected "+ 1169 "first entry in block index to be genesis block, "+ 1170 "found %s", blockHash)) 1171 } 1172 } else if header.PrevBlock == lastNode.hash { 1173 // Since we iterate block headers in order of height, if the 1174 // blocks are mostly linear there is a very good chance the 1175 // previous header processed is the parent. 1176 parent = lastNode 1177 } else { 1178 parent = b.index.LookupNode(&header.PrevBlock) 1179 if parent == nil { 1180 return AssertError(fmt.Sprintf("initChainState: Could "+ 1181 "not find parent for block %s", header.BlockHash())) 1182 } 1183 } 1184 1185 // Initialize the block node for the block, connect it, 1186 // and add it to the block index. 1187 node := new(blockNode) 1188 initBlockNode(node, header, parent) 1189 node.status = status 1190 b.index.addNode(node) 1191 1192 lastNode = node 1193 i++ 1194 } 1195 1196 // Set the best chain view to the stored best state. 1197 tip := b.index.LookupNode(&state.hash) 1198 if tip == nil { 1199 return AssertError(fmt.Sprintf("initChainState: cannot find "+ 1200 "chain tip %s in block index", state.hash)) 1201 } 1202 b.bestChain.SetTip(tip) 1203 1204 // Load the raw block bytes for the best block. 1205 blockBytes, err := dbTx.FetchBlock(&state.hash) 1206 if err != nil { 1207 return err 1208 } 1209 var block wire.MsgBlock 1210 err = block.Deserialize(bytes.NewReader(blockBytes)) 1211 if err != nil { 1212 return err 1213 } 1214 1215 // As a final consistency check, we'll run through all the 1216 // nodes which are ancestors of the current chain tip, and mark 1217 // them as valid if they aren't already marked as such. This 1218 // is a safe assumption as all the block before the current tip 1219 // are valid by definition. 1220 for iterNode := tip; iterNode != nil; iterNode = iterNode.parent { 1221 // If this isn't already marked as valid in the index, then 1222 // we'll mark it as valid now to ensure consistency once 1223 // we're up and running. 1224 if !iterNode.status.KnownValid() { 1225 log.Infof("Block %v (height=%v) ancestor of "+ 1226 "chain tip not marked as valid, "+ 1227 "upgrading to valid for consistency", 1228 iterNode.hash, iterNode.height) 1229 1230 b.index.SetStatusFlags(iterNode, statusValid) 1231 } 1232 } 1233 1234 // Initialize the state related to the best block. 1235 blockSize := uint64(len(blockBytes)) 1236 blockWeight := uint64(GetBlockWeight(palcutil.NewBlock(&block))) 1237 numTxns := uint64(len(block.Transactions)) 1238 b.stateSnapshot = newBestState(tip, blockSize, blockWeight, 1239 numTxns, state.totalTxns, tip.CalcPastMedianTime()) 1240 1241 return nil 1242 }) 1243 if err != nil { 1244 return err 1245 } 1246 1247 // As we might have updated the index after it was loaded, we'll 1248 // attempt to flush the index to the DB. This will only result in a 1249 // write if the elements are dirty, so it'll usually be a noop. 1250 return b.index.flushToDB() 1251 } 1252 1253 // deserializeBlockRow parses a value in the block index bucket into a block 1254 // header and block status bitfield. 1255 func deserializeBlockRow(blockRow []byte) (*wire.BlockHeader, blockStatus, error) { 1256 buffer := bytes.NewReader(blockRow) 1257 1258 var header wire.BlockHeader 1259 err := header.Deserialize(buffer) 1260 if err != nil { 1261 return nil, statusNone, err 1262 } 1263 1264 statusByte, err := buffer.ReadByte() 1265 if err != nil { 1266 return nil, statusNone, err 1267 } 1268 1269 return &header, blockStatus(statusByte), nil 1270 } 1271 1272 // dbFetchHeaderByHash uses an existing database transaction to retrieve the 1273 // block header for the provided hash. 1274 func dbFetchHeaderByHash(dbTx database.Tx, hash *chainhash.Hash) (*wire.BlockHeader, error) { 1275 headerBytes, err := dbTx.FetchBlockHeader(hash) 1276 if err != nil { 1277 return nil, err 1278 } 1279 1280 var header wire.BlockHeader 1281 err = header.Deserialize(bytes.NewReader(headerBytes)) 1282 if err != nil { 1283 return nil, err 1284 } 1285 1286 return &header, nil 1287 } 1288 1289 // dbFetchHeaderByHeight uses an existing database transaction to retrieve the 1290 // block header for the provided height. 1291 func dbFetchHeaderByHeight(dbTx database.Tx, height int32) (*wire.BlockHeader, error) { 1292 hash, err := dbFetchHashByHeight(dbTx, height) 1293 if err != nil { 1294 return nil, err 1295 } 1296 1297 return dbFetchHeaderByHash(dbTx, hash) 1298 } 1299 1300 // dbFetchBlockByNode uses an existing database transaction to retrieve the 1301 // raw block for the provided node, deserialize it, and return a palcutil.Block 1302 // with the height set. 1303 func dbFetchBlockByNode(dbTx database.Tx, node *blockNode) (*palcutil.Block, error) { 1304 // Load the raw block bytes from the database. 1305 blockBytes, err := dbTx.FetchBlock(&node.hash) 1306 if err != nil { 1307 return nil, err 1308 } 1309 1310 // Create the encapsulated block and set the height appropriately. 1311 block, err := palcutil.NewBlockFromBytes(blockBytes) 1312 if err != nil { 1313 return nil, err 1314 } 1315 block.SetHeight(node.height) 1316 1317 return block, nil 1318 } 1319 1320 // dbStoreBlockNode stores the block header and validation status to the block 1321 // index bucket. This overwrites the current entry if there exists one. 1322 func dbStoreBlockNode(dbTx database.Tx, node *blockNode) error { 1323 // Serialize block data to be stored. 1324 w := bytes.NewBuffer(make([]byte, 0, blockHdrSize+1)) 1325 header := node.Header() 1326 err := header.Serialize(w) 1327 if err != nil { 1328 return err 1329 } 1330 err = w.WriteByte(byte(node.status)) 1331 if err != nil { 1332 return err 1333 } 1334 value := w.Bytes() 1335 1336 // Write block header data to block index bucket. 1337 blockIndexBucket := dbTx.Metadata().Bucket(blockIndexBucketName) 1338 key := blockIndexKey(&node.hash, uint32(node.height)) 1339 return blockIndexBucket.Put(key, value) 1340 } 1341 1342 // dbStoreBlock stores the provided block in the database if it is not already 1343 // there. The full block data is written to ffldb. 1344 func dbStoreBlock(dbTx database.Tx, block *palcutil.Block) error { 1345 hasBlock, err := dbTx.HasBlock(block.Hash()) 1346 if err != nil { 1347 return err 1348 } 1349 if hasBlock { 1350 return nil 1351 } 1352 return dbTx.StoreBlock(block) 1353 } 1354 1355 // blockIndexKey generates the binary key for an entry in the block index 1356 // bucket. The key is composed of the block height encoded as a big-endian 1357 // 32-bit unsigned int followed by the 32 byte block hash. 1358 func blockIndexKey(blockHash *chainhash.Hash, blockHeight uint32) []byte { 1359 indexKey := make([]byte, chainhash.HashSize+4) 1360 binary.BigEndian.PutUint32(indexKey[0:4], blockHeight) 1361 copy(indexKey[4:chainhash.HashSize+4], blockHash[:]) 1362 return indexKey 1363 } 1364 1365 // BlockByHeight returns the block at the given height in the main chain. 1366 // 1367 // This function is safe for concurrent access. 1368 func (b *BlockChain) BlockByHeight(blockHeight int32) (*palcutil.Block, error) { 1369 // Lookup the block height in the best chain. 1370 node := b.bestChain.NodeByHeight(blockHeight) 1371 if node == nil { 1372 str := fmt.Sprintf("no block at height %d exists", blockHeight) 1373 return nil, errNotInMainChain(str) 1374 } 1375 1376 // Load the block from the database and return it. 1377 var block *palcutil.Block 1378 err := b.db.View(func(dbTx database.Tx) error { 1379 var err error 1380 block, err = dbFetchBlockByNode(dbTx, node) 1381 return err 1382 }) 1383 return block, err 1384 } 1385 1386 // BlockByHash returns the block from the main chain with the given hash with 1387 // the appropriate chain height set. 1388 // 1389 // This function is safe for concurrent access. 1390 func (b *BlockChain) BlockByHash(hash *chainhash.Hash) (*palcutil.Block, error) { 1391 // Lookup the block hash in block index and ensure it is in the best 1392 // chain. 1393 node := b.index.LookupNode(hash) 1394 if node == nil || !b.bestChain.Contains(node) { 1395 str := fmt.Sprintf("block %s is not in the main chain", hash) 1396 return nil, errNotInMainChain(str) 1397 } 1398 1399 // Load the block from the database and return it. 1400 var block *palcutil.Block 1401 err := b.db.View(func(dbTx database.Tx) error { 1402 var err error 1403 block, err = dbFetchBlockByNode(dbTx, node) 1404 return err 1405 }) 1406 return block, err 1407 }