chainio.go raw

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