本文整理汇总了Golang中github.com/decred/dcrutil.Block.Height方法的典型用法代码示例。如果您正苦于以下问题:Golang Block.Height方法的具体用法?Golang Block.Height怎么用?Golang Block.Height使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类github.com/decred/dcrutil.Block
的用法示例。
在下文中一共展示了Block.Height方法的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Golang代码示例。
示例1: LogBlockHeight
// LogBlockHeight logs a new block height as an information message to show
// progress to the user. In order to prevent spam, it limits logging to one
// message every 10 seconds with duration and totals included.
func (b *blockProgressLogger) LogBlockHeight(block *dcrutil.Block) {
b.Lock()
defer b.Unlock()
b.receivedLogBlocks++
b.receivedLogTx += int64(len(block.MsgBlock().Transactions))
now := time.Now()
duration := now.Sub(b.lastBlockLogTime)
if duration < time.Second*10 {
return
}
// Truncate the duration to 10s of milliseconds.
durationMillis := int64(duration / time.Millisecond)
tDuration := 10 * time.Millisecond * time.Duration(durationMillis/10)
// Log information about new block height.
blockStr := "blocks"
if b.receivedLogBlocks == 1 {
blockStr = "block"
}
txStr := "transactions"
if b.receivedLogTx == 1 {
txStr = "transaction"
}
b.subsystemLogger.Infof("%s %d %s in the last %s (%d %s, height %d, %s)",
b.progressAction, b.receivedLogBlocks, blockStr, tDuration, b.receivedLogTx,
txStr, block.Height(), block.MsgBlock().Header.Timestamp)
b.receivedLogBlocks = 0
b.receivedLogTx = 0
b.lastBlockLogTime = now
}
示例2: dbIndexDisconnectBlock
// dbIndexDisconnectBlock removes all of the index entries associated with the
// given block using the provided indexer and updates the tip of the indexer
// accordingly. An error will be returned if the current tip for the indexer is
// not the passed block.
func dbIndexDisconnectBlock(dbTx database.Tx, indexer Indexer, block, parent *dcrutil.Block, view *blockchain.UtxoViewpoint) error {
// Assert that the block being disconnected is the current tip of the
// index.
idxKey := indexer.Key()
curTipHash, _, err := dbFetchIndexerTip(dbTx, idxKey)
if err != nil {
return err
}
if !curTipHash.IsEqual(block.Sha()) {
return AssertError(fmt.Sprintf("dbIndexDisconnectBlock must "+
"be called with the block at the current index tip "+
"(%s, tip %s, block %s)", indexer.Name(),
curTipHash, block.Sha()))
}
// Notify the indexer with the disconnected block so it can remove all
// of the appropriate entries.
if err := indexer.DisconnectBlock(dbTx, block, parent, view); err != nil {
return err
}
// Update the current index tip.
prevHash := &block.MsgBlock().Header.PrevBlock
return dbPutIndexerTip(dbTx, idxKey, prevHash, uint32(block.Height())-1)
}
示例3: submitBlock
// submitBlock submits the passed block to network after ensuring it passes all
// of the consensus validation rules.
func (m *CPUMiner) submitBlock(block *dcrutil.Block) bool {
m.submitBlockLock.Lock()
defer m.submitBlockLock.Unlock()
_, latestHeight := m.server.blockManager.chainState.Best()
// Be sure to set this so ProcessBlock doesn't fail! - Decred
block.SetHeight(latestHeight + 1)
// Process this block using the same rules as blocks coming from other
// nodes. This will in turn relay it to the network like normal.
isOrphan, err := m.server.blockManager.ProcessBlock(block, blockchain.BFNone)
if err != nil {
// Anything other than a rule violation is an unexpected error,
// so log that error as an internal error.
if rErr, ok := err.(blockchain.RuleError); !ok {
minrLog.Errorf("Unexpected error while processing "+
"block submitted via CPU miner: %v", err)
return false
} else {
// Occasionally errors are given out for timing errors with
// ResetMinDifficulty and high block works that is above
// the target. Feed these to debug.
if m.server.chainParams.ResetMinDifficulty &&
rErr.ErrorCode == blockchain.ErrHighHash {
minrLog.Debugf("Block submitted via CPU miner rejected "+
"because of ResetMinDifficulty time sync failure: %v",
err)
return false
} else {
// Other rule errors should be reported.
minrLog.Errorf("Block submitted via CPU miner rejected: %v", err)
return false
}
}
}
if isOrphan {
minrLog.Errorf("Block submitted via CPU miner is an orphan building "+
"on parent %v", block.MsgBlock().Header.PrevBlock)
return false
}
// The block was accepted.
coinbaseTxOuts := block.MsgBlock().Transactions[0].TxOut
coinbaseTxGenerated := int64(0)
for _, out := range coinbaseTxOuts {
coinbaseTxGenerated += out.Value
}
minrLog.Infof("Block submitted via CPU miner accepted (hash %s, "+
"height %v, amount %v)",
block.Sha(),
block.Height(),
dcrutil.Amount(coinbaseTxGenerated))
return true
}
示例4: DebugBlockString
// DebugBlockString dumps a verbose message containing information about
// the transactions of a block.
func DebugBlockString(block *dcrutil.Block) string {
if block == nil {
return "block pointer nil"
}
var buffer bytes.Buffer
hash := block.Sha()
str := fmt.Sprintf("Block Header: %v Height: %v \n",
hash, block.Height())
buffer.WriteString(str)
str = fmt.Sprintf("Block contains %v regular transactions "+
"and %v stake transactions \n",
len(block.Transactions()),
len(block.STransactions()))
buffer.WriteString(str)
str = fmt.Sprintf("List of regular transactions \n")
buffer.WriteString(str)
for i, tx := range block.Transactions() {
str = fmt.Sprintf("Index: %v, Hash: %v \n", i, tx.Sha())
buffer.WriteString(str)
}
if len(block.STransactions()) == 0 {
return buffer.String()
}
str = fmt.Sprintf("List of stake transactions \n")
buffer.WriteString(str)
for i, stx := range block.STransactions() {
txTypeStr := ""
txType := stake.DetermineTxType(stx)
switch txType {
case stake.TxTypeSStx:
txTypeStr = "SStx"
case stake.TxTypeSSGen:
txTypeStr = "SSGen"
case stake.TxTypeSSRtx:
txTypeStr = "SSRtx"
default:
txTypeStr = "Error"
}
str = fmt.Sprintf("Index: %v, Type: %v, Hash: %v \n",
i, txTypeStr, stx.Sha())
buffer.WriteString(str)
}
return buffer.String()
}
示例5: InsertBlock
// InsertBlock synchronously queues a newly solved block to have its
// transactions indexed by address.
func (a *addrIndexer) InsertBlock(block *dcrutil.Block, parent *dcrutil.Block) error {
addrIndex, err := a.indexBlockAddrs(block, parent)
if err != nil {
return fmt.Errorf("Unable to index transactions of"+
" block: %v", err)
}
err = a.server.db.UpdateAddrIndexForBlock(block.Sha(),
block.Height(),
addrIndex)
if err != nil {
return fmt.Errorf("Unable to insert block: %v", err.Error())
}
return nil
}
示例6: connectTxTree
// connectTxTree lets you connect an arbitrary TxTree to a txStore to push it
// forward in history.
// TxTree true == TxTreeRegular
// TxTree false == TxTreeStake
func connectTxTree(txStore TxStore,
block *dcrutil.Block,
txTree bool) {
var transactions []*dcrutil.Tx
if txTree {
transactions = block.Transactions()
} else {
transactions = block.STransactions()
}
// Loop through all of the transactions in the block to see if any of
// them are ones we need to update and spend based on the results map.
for i, tx := range transactions {
// Update the transaction store with the transaction information
// if it's one of the requested transactions.
msgTx := tx.MsgTx()
if txD, exists := txStore[*tx.Sha()]; exists {
txD.Tx = tx
txD.BlockHeight = block.Height()
txD.BlockIndex = uint32(i)
txD.Spent = make([]bool, len(msgTx.TxOut))
txD.Err = nil
}
// Spend the origin transaction output.
for _, txIn := range msgTx.TxIn {
originHash := &txIn.PreviousOutPoint.Hash
originIndex := txIn.PreviousOutPoint.Index
if originTx, exists := txStore[*originHash]; exists {
if originTx.Spent == nil {
continue
}
if originIndex >= uint32(len(originTx.Spent)) {
continue
}
originTx.Spent[originIndex] = true
}
}
}
return
}
示例7: dbIndexConnectBlock
// dbIndexConnectBlock adds all of the index entries associated with the
// given block using the provided indexer and updates the tip of the indexer
// accordingly. An error will be returned if the current tip for the indexer is
// not the previous block for the passed block.
func dbIndexConnectBlock(dbTx database.Tx, indexer Indexer, block, parent *dcrutil.Block, view *blockchain.UtxoViewpoint) error {
// Assert that the block being connected properly connects to the
// current tip of the index.
idxKey := indexer.Key()
curTipHash, _, err := dbFetchIndexerTip(dbTx, idxKey)
if err != nil {
return err
}
if !curTipHash.IsEqual(&block.MsgBlock().Header.PrevBlock) {
return AssertError(fmt.Sprintf("dbIndexConnectBlock must be "+
"called with a block that extends the current index "+
"tip (%s, tip %s, block %s)", indexer.Name(),
curTipHash, block.Sha()))
}
// Notify the indexer with the connected block so it can index it.
if err := indexer.ConnectBlock(dbTx, block, parent, view); err != nil {
return err
}
// Update the current index tip.
return dbPutIndexerTip(dbTx, idxKey, block.Sha(), uint32(block.Height()))
}
示例8: connectTransactions
// connectTransactions updates the view by adding all new utxos created by all
// of the transactions in the passed block, marking all utxos the transactions
// spend as spent, and setting the best hash for the view to the passed block.
// In addition, when the 'stxos' argument is not nil, it will be updated to
// append an entry for each spent txout.
func (b *BlockChain) connectTransactions(view *UtxoViewpoint, block *dcrutil.Block,
parent *dcrutil.Block, stxos *[]spentTxOut) error {
regularTxTreeValid := dcrutil.IsFlagSet16(block.MsgBlock().Header.VoteBits,
dcrutil.BlockValid)
thisNodeStakeViewpoint := ViewpointPrevInvalidStake
if regularTxTreeValid {
thisNodeStakeViewpoint = ViewpointPrevValidStake
}
if parent != nil && block.Height() != 0 {
view.SetStakeViewpoint(ViewpointPrevValidInitial)
err := view.fetchInputUtxos(b.db, block, parent)
if err != nil {
return err
}
mBlock := block.MsgBlock()
votebits := mBlock.Header.VoteBits
regularTxTreeValid := dcrutil.IsFlagSet16(votebits, dcrutil.BlockValid)
if regularTxTreeValid {
for i, tx := range parent.Transactions() {
err := view.connectTransaction(tx, parent.Height(), uint32(i),
stxos)
if err != nil {
return err
}
}
}
}
for i, stx := range block.STransactions() {
view.SetStakeViewpoint(thisNodeStakeViewpoint)
err := view.fetchInputUtxos(b.db, block, parent)
if err != nil {
return err
}
err = view.connectTransaction(stx, block.Height(), uint32(i), stxos)
if err != nil {
return err
}
}
// Update the best hash for view to include this block since all of its
// transactions have been connected.
view.SetBestHash(block.Sha())
return nil
}
示例9: InsertBlock
// InsertBlock inserts raw block and transaction data from a block into the
// database. The first block inserted into the database will be treated as the
// genesis block. Every subsequent block insert requires the referenced parent
// block to already exist.
func (db *LevelDb) InsertBlock(block *dcrutil.Block) (height int64, rerr error) {
// Be careful with this function on syncs. It contains decred changes.
// Obtain the previous block first so long as it's not the genesis block
var blockPrev *dcrutil.Block
// Decred: WARNING. This function assumes that all block insertion calls have
// dcrutil.blocks passed to them with block.blockHeight set correctly. However,
// loading the genesis block in btcd didn't do this (via block manager); pre-
// production it should be established that all calls to this function pass
// blocks with block.blockHeight set correctly.
if block.Height() != 0 {
var errBlockPrev error
blockPrev, errBlockPrev = db.FetchBlockBySha(&block.MsgBlock().Header.PrevBlock)
if errBlockPrev != nil {
blockSha := block.Sha()
log.Warnf("Failed to fetch parent block of block %v", blockSha)
return 0, errBlockPrev
}
}
db.dbLock.Lock()
defer db.dbLock.Unlock()
defer func() {
if rerr == nil {
rerr = db.processBatches()
} else {
db.lBatch().Reset()
}
}()
blocksha := block.Sha()
mblock := block.MsgBlock()
rawMsg, err := block.Bytes()
if err != nil {
log.Warnf("Failed to obtain raw block sha %v", blocksha)
return 0, err
}
_, sTxLoc, err := block.TxLoc()
if err != nil {
log.Warnf("Failed to obtain raw block sha %v, stxloc %v", blocksha, sTxLoc)
return 0, err
}
// Insert block into database
newheight, err := db.insertBlockData(blocksha, &mblock.Header.PrevBlock,
rawMsg)
if err != nil {
log.Warnf("Failed to insert block %v %v %v", blocksha,
&mblock.Header.PrevBlock, err)
return 0, err
}
// Get data necessary to process regular tx tree of parent block if it's not
// the genesis block.
var mBlockPrev *wire.MsgBlock
var txLoc []wire.TxLoc
if blockPrev != nil {
blockShaPrev := blockPrev.Sha()
mBlockPrev = blockPrev.MsgBlock()
txLoc, _, err = blockPrev.TxLoc()
if err != nil {
log.Warnf("Failed to obtain raw block sha %v, txloc %v", blockShaPrev, txLoc)
return 0, err
}
}
// Insert the regular tx of the parent block into the tx database if the vote
// bits enable it, and if it's not the genesis block.
votebits := mblock.Header.VoteBits
if dcrutil.IsFlagSet16(votebits, dcrutil.BlockValid) && blockPrev != nil {
for txidx, tx := range mBlockPrev.Transactions {
txsha, err := blockPrev.TxSha(txidx)
if err != nil {
log.Warnf("failed to compute tx name block %v idx %v err %v", blocksha, txidx, err)
return 0, err
}
spentbuflen := (len(tx.TxOut) + 7) / 8
spentbuf := make([]byte, spentbuflen, spentbuflen)
if len(tx.TxOut)%8 != 0 {
for i := uint(len(tx.TxOut) % 8); i < 8; i++ {
spentbuf[spentbuflen-1] |= (byte(1) << i)
}
}
// newheight-1 instead of newheight below, as the tx is actually found
// in the parent.
//fmt.Printf("insert tx %v into db at height %v\n", txsha, newheight)
err = db.insertTx(txsha, newheight-1, uint32(txidx), txLoc[txidx].TxStart, txLoc[txidx].TxLen, spentbuf)
if err != nil {
log.Warnf("block %v idx %v failed to insert tx %v %v err %v", blocksha, newheight-1, &txsha, txidx, err)
return 0, err
//.........这里部分代码省略.........
示例10: dbAddTxIndexEntries
// dbAddTxIndexEntries uses an existing database transaction to add a
// transaction index entry for every transaction in the passed block.
func dbAddTxIndexEntries(dbTx database.Tx, block, parent *dcrutil.Block, blockID uint32) error {
// The offset and length of the transactions within the serialized
// block, for the regular transactions of the parent (if added)
// and the stake transactions of the current block.
regularTxTreeValid := dcrutil.IsFlagSet16(block.MsgBlock().Header.VoteBits,
dcrutil.BlockValid)
var parentRegularTxs []*dcrutil.Tx
var parentTxLocs []wire.TxLoc
var parentBlockID uint32
if regularTxTreeValid && block.Height() > 1 {
var err error
parentRegularTxs = parent.Transactions()
parentTxLocs, _, err = parent.TxLoc()
if err != nil {
return err
}
parentSha := parent.Sha()
parentBlockID, err = dbFetchBlockIDByHash(dbTx, *parentSha)
if err != nil {
return err
}
}
_, blockStxLocs, err := block.TxLoc()
if err != nil {
return err
}
allTxs := append(parentRegularTxs, block.STransactions()...)
allTxsLocs := append(parentTxLocs, blockStxLocs...)
stakeTxStartIdx := len(parentRegularTxs)
// As an optimization, allocate a single slice big enough to hold all
// of the serialized transaction index entries for the block and
// serialize them directly into the slice. Then, pass the appropriate
// subslice to the database to be written. This approach significantly
// cuts down on the number of required allocations.
offset := 0
serializedValues := make([]byte, len(allTxs)*txEntrySize)
blockIDToUse := parentBlockID
for i, tx := range allTxs {
// Switch to using the newest block ID for the stake transactions,
// since these are not from the parent.
if i == stakeTxStartIdx {
blockIDToUse = blockID
}
putTxIndexEntry(serializedValues[offset:], blockIDToUse, allTxsLocs[i])
endOffset := offset + txEntrySize
txSha := tx.Sha()
err := dbPutTxIndexEntry(dbTx, *txSha,
serializedValues[offset:endOffset:endOffset])
if err != nil {
return err
}
offset += txEntrySize
}
return nil
}
示例11: ProcessBlock
// ProcessBlock is the main workhorse for handling insertion of new blocks into
// the block chain. It includes functionality such as rejecting duplicate
// blocks, ensuring blocks follow all rules, orphan handling, and insertion into
// the block chain along with best chain selection and reorganization.
//
// It returns a first bool specifying whether or not the block is on on a fork
// or on a side chain. True means it's on the main chain.
//
// This function is safe for concurrent access.
func (b *BlockChain) ProcessBlock(block *dcrutil.Block, flags BehaviorFlags) (bool, bool, error) {
b.chainLock.Lock()
defer b.chainLock.Unlock()
fastAdd := flags&BFFastAdd == BFFastAdd
dryRun := flags&BFDryRun == BFDryRun
blockHash := block.Sha()
log.Tracef("Processing block %v", blockHash)
currentTime := time.Now()
defer func() {
elapsedTime := time.Since(currentTime)
log.Debugf("Block %v (height %v) finished processing in %s",
blockHash, block.Height(), elapsedTime)
}()
// The block must not already exist in the main chain or side chains.
exists, err := b.blockExists(blockHash)
if err != nil {
return false, false, err
}
if exists {
str := fmt.Sprintf("already have block %v", blockHash)
return false, false, ruleError(ErrDuplicateBlock, str)
}
// The block must not already exist as an orphan.
if _, exists := b.orphans[*blockHash]; exists {
str := fmt.Sprintf("already have block (orphan) %v", blockHash)
return false, false, ruleError(ErrDuplicateBlock, str)
}
// Perform preliminary sanity checks on the block and its transactions.
err = checkBlockSanity(block, b.timeSource, flags, b.chainParams)
if err != nil {
return false, false, err
}
// Find the previous checkpoint and perform some additional checks based
// on the checkpoint. This provides a few nice properties such as
// preventing old side chain blocks before the last checkpoint,
// rejecting easy to mine, but otherwise bogus, blocks that could be
// used to eat memory, and ensuring expected (versus claimed) proof of
// work requirements since the previous checkpoint are met.
blockHeader := &block.MsgBlock().Header
checkpointBlock, err := b.findPreviousCheckpoint()
if err != nil {
return false, false, err
}
if checkpointBlock != nil {
// Ensure the block timestamp is after the checkpoint timestamp.
checkpointHeader := &checkpointBlock.MsgBlock().Header
checkpointTime := checkpointHeader.Timestamp
if blockHeader.Timestamp.Before(checkpointTime) {
str := fmt.Sprintf("block %v has timestamp %v before "+
"last checkpoint timestamp %v", blockHash,
blockHeader.Timestamp, checkpointTime)
return false, false, ruleError(ErrCheckpointTimeTooOld, str)
}
if !fastAdd {
// Even though the checks prior to now have already ensured the
// proof of work exceeds the claimed amount, the claimed amount
// is a field in the block header which could be forged. This
// check ensures the proof of work is at least the minimum
// expected based on elapsed time since the last checkpoint and
// maximum adjustment allowed by the retarget rules.
duration := blockHeader.Timestamp.Sub(checkpointTime)
requiredTarget := CompactToBig(b.calcEasiestDifficulty(
checkpointHeader.Bits, duration))
currentTarget := CompactToBig(blockHeader.Bits)
if currentTarget.Cmp(requiredTarget) > 0 {
str := fmt.Sprintf("block target difficulty of %064x "+
"is too low when compared to the previous "+
"checkpoint", currentTarget)
return false, false, ruleError(ErrDifficultyTooLow, str)
}
}
}
// Handle orphan blocks.
prevHash := &blockHeader.PrevBlock
prevHashExists, err := b.blockExists(prevHash)
if err != nil {
return false, false, err
}
if !prevHashExists {
if !dryRun {
log.Infof("Adding orphan block %v with parent %v",
blockHash, prevHash)
b.addOrphanBlock(block)
//.........这里部分代码省略.........
示例12: findWhereDoubleSpent
// findWhereDoubleSpent determines where a tx was previously doublespent.
// VERY INTENSIVE BLOCKCHAIN SCANNING, USE TO DEBUG SIMULATED BLOCKCHAINS
// ONLY.
func (b *BlockChain) findWhereDoubleSpent(block *dcrutil.Block) error {
height := int64(1)
heightEnd := block.Height()
hashes, err := b.db.FetchHeightRange(height, heightEnd)
if err != nil {
return err
}
var allTxs []*dcrutil.Tx
txs := block.Transactions()[1:]
stxs := block.STransactions()
allTxs = append(txs, stxs...)
for _, hash := range hashes {
curBlock, err := b.getBlockFromHash(&hash)
if err != nil {
return err
}
log.Errorf("Cur block %v", curBlock.Height())
for _, localTx := range allTxs {
for _, localTxIn := range localTx.MsgTx().TxIn {
for _, tx := range curBlock.Transactions()[1:] {
for _, txIn := range tx.MsgTx().TxIn {
if txIn.PreviousOutPoint == localTxIn.PreviousOutPoint {
log.Errorf("Double spend of {hash: %v, idx: %v,"+
" tree: %b}, previously found in tx %v "+
"of block %v txtree regular",
txIn.PreviousOutPoint.Hash,
txIn.PreviousOutPoint.Index,
txIn.PreviousOutPoint.Tree,
tx.Sha(),
hash)
}
}
}
for _, tx := range curBlock.STransactions() {
for _, txIn := range tx.MsgTx().TxIn {
if txIn.PreviousOutPoint == localTxIn.PreviousOutPoint {
log.Errorf("Double spend of {hash: %v, idx: %v,"+
" tree: %b}, previously found in tx %v "+
"of block %v txtree stake\n",
txIn.PreviousOutPoint.Hash,
txIn.PreviousOutPoint.Index,
txIn.PreviousOutPoint.Tree,
tx.Sha(),
hash)
}
}
}
}
}
}
for _, localTx := range stxs {
for _, localTxIn := range localTx.MsgTx().TxIn {
for _, tx := range txs {
for _, txIn := range tx.MsgTx().TxIn {
if txIn.PreviousOutPoint == localTxIn.PreviousOutPoint {
log.Errorf("Double spend of {hash: %v, idx: %v,"+
" tree: %b}, previously found in tx %v "+
"of cur block stake txtree\n",
txIn.PreviousOutPoint.Hash,
txIn.PreviousOutPoint.Index,
txIn.PreviousOutPoint.Tree,
tx.Sha())
}
}
}
}
}
return nil
}
示例13: ConnectBlock
// ConnectBlock is invoked by the index manager when a new block has been
// connected to the main chain. This indexer adds a mapping for each address
// the transactions in the block involve.
//
// This is part of the Indexer interface.
func (idx *AddrIndex) ConnectBlock(dbTx database.Tx, block, parent *dcrutil.Block,
view *blockchain.UtxoViewpoint) error {
// The offset and length of the transactions within the serialized
// block for the regular transactions of the previous block, if
// applicable.
regularTxTreeValid := dcrutil.IsFlagSet16(block.MsgBlock().Header.VoteBits,
dcrutil.BlockValid)
var parentTxLocs []wire.TxLoc
var parentBlockID uint32
if regularTxTreeValid && block.Height() > 1 {
var err error
parentTxLocs, _, err = parent.TxLoc()
if err != nil {
return err
}
parentSha := parent.Sha()
parentBlockID, err = dbFetchBlockIDByHash(dbTx, *parentSha)
if err != nil {
return err
}
}
// The offset and length of the transactions within the serialized
// block for the added stake transactions.
_, blockStxLocs, err := block.TxLoc()
if err != nil {
return err
}
// Nothing to index, just return.
if len(parentTxLocs)+len(blockStxLocs) == 0 {
return nil
}
// Get the internal block ID associated with the block.
blockSha := block.Sha()
blockID, err := dbFetchBlockIDByHash(dbTx, *blockSha)
if err != nil {
return err
}
// Build all of the address to transaction mappings in a local map.
addrsToTxns := make(writeIndexData)
idx.indexBlock(addrsToTxns, block, parent, view)
// Add all of the index entries for each address.
stakeIdxsStart := len(parentTxLocs)
allTxLocs := append(parentTxLocs, blockStxLocs...)
addrIdxBucket := dbTx.Metadata().Bucket(addrIndexKey)
for addrKey, txIdxs := range addrsToTxns {
for _, txIdx := range txIdxs {
// Switch to using the newest block ID for the stake transactions,
// since these are not from the parent. Offset the index to be
// correct for the location in this given block.
blockIDToUse := parentBlockID
if txIdx >= stakeIdxsStart {
blockIDToUse = blockID
}
err := dbPutAddrIndexEntry(addrIdxBucket, addrKey,
blockIDToUse, allTxLocs[txIdx])
if err != nil {
return err
}
}
}
return nil
}
示例14: indexBlockAddrs
// indexBlockAddrs returns a populated index of the all the transactions in the
// passed block based on the addresses involved in each transaction.
func (a *addrIndexer) indexBlockAddrs(blk *dcrutil.Block,
parent *dcrutil.Block) (database.BlockAddrIndex, error) {
var addrIndex database.BlockAddrIndex
_, stxLocs, err := blk.TxLoc()
if err != nil {
return nil, err
}
txTreeRegularValid := dcrutil.IsFlagSet16(blk.MsgBlock().Header.VoteBits,
dcrutil.BlockValid)
// Add regular transactions iff the block was validated.
if txTreeRegularValid {
txLocs, _, err := parent.TxLoc()
if err != nil {
return nil, err
}
for txIdx, tx := range parent.Transactions() {
// Tx's offset and length in the block.
locInBlock := &txLocs[txIdx]
// Coinbases don't have any inputs.
if !blockchain.IsCoinBase(tx) {
// Index the SPK's of each input's previous outpoint
// transaction.
for _, txIn := range tx.MsgTx().TxIn {
prevOutTx, err := a.lookupTransaction(
txIn.PreviousOutPoint.Hash,
blk,
parent)
inputOutPoint := prevOutTx.TxOut[txIn.PreviousOutPoint.Index]
toAppend, err := convertToAddrIndex(inputOutPoint.Version,
inputOutPoint.PkScript, parent.Height(), locInBlock)
if err != nil {
adxrLog.Tracef("Error converting tx txin %v: %v",
txIn.PreviousOutPoint.Hash, err)
continue
}
addrIndex = append(addrIndex, toAppend...)
}
}
for _, txOut := range tx.MsgTx().TxOut {
toAppend, err := convertToAddrIndex(txOut.Version, txOut.PkScript,
parent.Height(), locInBlock)
if err != nil {
adxrLog.Tracef("Error converting tx txout %v: %v",
tx.MsgTx().TxSha(), err)
continue
}
addrIndex = append(addrIndex, toAppend...)
}
}
}
// Add stake transactions.
for stxIdx, stx := range blk.STransactions() {
// Tx's offset and length in the block.
locInBlock := &stxLocs[stxIdx]
isSSGen, _ := stake.IsSSGen(stx)
// Index the SPK's of each input's previous outpoint
// transaction.
for i, txIn := range stx.MsgTx().TxIn {
// Stakebases don't have any inputs.
if isSSGen && i == 0 {
continue
}
// Lookup and fetch the referenced output's tx.
prevOutTx, err := a.lookupTransaction(
txIn.PreviousOutPoint.Hash,
blk,
parent)
inputOutPoint := prevOutTx.TxOut[txIn.PreviousOutPoint.Index]
toAppend, err := convertToAddrIndex(inputOutPoint.Version,
inputOutPoint.PkScript, blk.Height(), locInBlock)
if err != nil {
adxrLog.Tracef("Error converting stx txin %v: %v",
txIn.PreviousOutPoint.Hash, err)
continue
}
addrIndex = append(addrIndex, toAppend...)
}
for _, txOut := range stx.MsgTx().TxOut {
toAppend, err := convertToAddrIndex(txOut.Version, txOut.PkScript,
blk.Height(), locInBlock)
if err != nil {
adxrLog.Tracef("Error converting stx txout %v: %v",
stx.MsgTx().TxSha(), err)
continue
}
addrIndex = append(addrIndex, toAppend...)
}
//.........这里部分代码省略.........
示例15: insertBlock
// insertBlock is the internal function which implements the public
// InsertBlock. See the comment for InsertBlock for more details.
//
// This function MUST be called with the tmdb lock held (for writes).
func (tmdb *TicketDB) insertBlock(block *dcrutil.Block) (SStxMemMap,
SStxMemMap, SStxMemMap, error) {
height := block.Height()
if height < tmdb.StakeEnabledHeight {
return nil, nil, nil, nil
}
// Sanity check: Does the number of tickets in ticketMap equal the number
// of tickets indicated in the header?
poolSizeBlock := int(block.MsgBlock().Header.PoolSize)
poolSize := 0
for i := 0; i < BucketsSize; i++ {
poolSize += len(tmdb.maps.ticketMap[i])
}
if poolSize != poolSizeBlock {
return nil, nil, nil, fmt.Errorf("ticketpoolsize in block %v not "+
"equal to the calculated ticketpoolsize, indicating database "+
"corruption (got %v, want %v)",
block.Sha(),
poolSizeBlock,
poolSize)
}
// Create the block in the spentTicketMap.
tmdb.maybeInsertBlock(block.Height())
// Iterate through all the SSGen (vote) tx in the block and add them to
// a map of tickets that were actually used. The rest of the tickets in
// the buckets were then considered missed --> missedTicketMap.
// Note that it doesn't really matter what value you set usedTickets to,
// it's just a map of tickets that were actually used in the block. It
// would probably be more efficient to use an array.
usedTickets := make(map[chainhash.Hash]struct{})
spendingHashes := make(map[chainhash.Hash]chainhash.Hash)
revocations := make(map[chainhash.Hash]struct{})
for _, staketx := range block.STransactions() {
if is, _ := IsSSGen(staketx); is {
msgTx := staketx.MsgTx()
sstxIn := msgTx.TxIn[1] // sstx input
sstxHash := sstxIn.PreviousOutPoint.Hash
usedTickets[sstxHash] = struct{}{}
spendingHashes[sstxHash] = *staketx.Sha()
}
if is, _ := IsSSRtx(staketx); is {
msgTx := staketx.MsgTx()
sstxIn := msgTx.TxIn[0] // sstx input
sstxHash := sstxIn.PreviousOutPoint.Hash
revocations[sstxHash] = struct{}{}
}
}
// Spend or miss all the necessary tickets and do some sanity checks.
parentBlock, err := tmdb.database.FetchBlockBySha(
&block.MsgBlock().Header.PrevBlock)
if err != nil {
return nil, nil, nil, err
}
spentAndMissedTickets, err := tmdb.spendTickets(parentBlock,
usedTickets,
spendingHashes)
if err != nil {
return nil, nil, nil, err
}
// Expire all old tickets, and stick them into the spent and missed ticket
// map too.
expiredTickets, err := tmdb.expireTickets(height)
if err != nil {
return nil, nil, nil, err
}
if len(expiredTickets) > 0 && len(spentAndMissedTickets) == 0 {
return nil, nil, nil, fmt.Errorf("tried to expire tickets before " +
"stake validation height! TicketExpiry may be too small")
}
if len(expiredTickets) > 0 {
for hash, ticket := range expiredTickets {
spentAndMissedTickets[hash] = ticket
}
}
revokedTickets, err := tmdb.revokeTickets(revocations)
if err != nil {
return nil, nil, nil, err
}
newTickets, err := tmdb.pushMatureTicketsAtHeight(block.Height())
if err != nil {
return nil, nil, nil, err
}
log.Debugf("Connected block %v (height %v) to the ticket database",
//.........这里部分代码省略.........