本文整理匯總了Golang中github.com/decred/dcrutil.IsFlagSet16函數的典型用法代碼示例。如果您正苦於以下問題:Golang IsFlagSet16函數的具體用法?Golang IsFlagSet16怎麽用?Golang IsFlagSet16使用的例子?那麽, 這裏精選的函數代碼示例或許可以為您提供幫助。
在下文中一共展示了IsFlagSet16函數的15個代碼示例,這些例子默認根據受歡迎程度排序。您可以為喜歡或者感覺有用的代碼點讚,您的評價將有助於係統推薦出更棒的Golang代碼示例。
示例1: 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
}
示例2: lookupTransaction
// lookupTransaction is a special transaction lookup function that searches
// the database, the block, and its parent for a transaction. This is needed
// because indexBlockAddrs is called AFTER a block is added/removed in the
// blockchain in blockManager, necessitating that the blocks internally be
// searched for inputs for any given transaction too. Additionally, it's faster
// to get the tx from the blocks here since they're already
func (a *addrIndexer) lookupTransaction(txHash chainhash.Hash, blk *dcrutil.Block,
parent *dcrutil.Block) (*wire.MsgTx, error) {
// Search the previous block and parent first.
txTreeRegularValid := dcrutil.IsFlagSet16(blk.MsgBlock().Header.VoteBits,
dcrutil.BlockValid)
// Search the regular tx tree of this and the last block if the
// tx tree regular was validated.
if txTreeRegularValid {
for _, stx := range parent.STransactions() {
if stx.Sha().IsEqual(&txHash) {
return stx.MsgTx(), nil
}
}
for _, tx := range parent.Transactions() {
if tx.Sha().IsEqual(&txHash) {
return tx.MsgTx(), nil
}
}
for _, tx := range blk.Transactions() {
if tx.Sha().IsEqual(&txHash) {
return tx.MsgTx(), nil
}
}
} else {
// Just search this block's regular tx tree and the previous
// block's stake tx tree.
for _, stx := range parent.STransactions() {
if stx.Sha().IsEqual(&txHash) {
return stx.MsgTx(), nil
}
}
for _, tx := range blk.Transactions() {
if tx.Sha().IsEqual(&txHash) {
return tx.MsgTx(), nil
}
}
}
// Lookup and fetch the referenced output's tx in the database.
txList, err := a.server.db.FetchTxBySha(&txHash)
if err != nil {
adxrLog.Errorf("Error fetching tx %v: %v",
txHash, err)
return nil, err
}
if len(txList) == 0 {
return nil, fmt.Errorf("transaction %v not found",
txHash)
}
return txList[len(txList)-1].Tx, nil
}
示例3: DropAfterBlockBySha
// DropAfterBlockBySha removes any blocks from the database after the given
// block. This is different than a simple truncate since the spend information
// for each block must also be unwound. This is part of the database.Db interface
// implementation.
func (db *MemDb) DropAfterBlockBySha(sha *chainhash.Hash) error {
db.Lock()
defer db.Unlock()
if db.closed {
return ErrDbClosed
}
// Begin by attempting to find the height associated with the passed
// hash.
height, exists := db.blocksBySha[*sha]
if !exists {
return fmt.Errorf("block %v does not exist in the database",
sha)
}
// The spend information has to be undone in reverse order, so loop
// backwards from the last block through the block just after the passed
// block. While doing this unspend all transactions in each block and
// remove the block.
endHeight := int64(len(db.blocks) - 1)
for i := endHeight; i > height; i-- {
blk := db.blocks[i]
blkprev := db.blocks[i-1]
// Unspend the stake tx in the current block
for _, tx := range blk.STransactions {
txSha := tx.TxSha()
db.removeTx(tx, &txSha)
}
// Check to see if the regular txs of the parent were even included; if
// they are, unspend all of these regular tx too
votebits := blk.Header.VoteBits
if dcrutil.IsFlagSet16(votebits, dcrutil.BlockValid) && height != 0 {
// Unspend the regular tx in the previous block
for _, tx := range blkprev.Transactions {
txSha := tx.TxSha()
db.removeTx(tx, &txSha)
}
}
db.blocks[i] = nil
db.blocks = db.blocks[:i]
}
return nil
}
示例4: CalculateAddedSubsidy
// CalculateAddedSubsidy calculates the amount of subsidy added by a block
// and its parent. The blocks passed to this function MUST be valid blocks
// that have already been confirmed to abide by the consensus rules of the
// network, or the function might panic.
func CalculateAddedSubsidy(block, parent *dcrutil.Block) int64 {
var subsidy int64
regularTxTreeValid := dcrutil.IsFlagSet16(block.MsgBlock().Header.VoteBits,
dcrutil.BlockValid)
if regularTxTreeValid {
subsidy += parent.MsgBlock().Transactions[0].TxIn[0].ValueIn
}
for _, stx := range block.MsgBlock().STransactions {
if isSSGen, _ := stake.IsSSGen(stx); isSSGen {
subsidy += stx.TxIn[0].ValueIn
}
}
return subsidy
}
示例5: testExistsTxSha
// testExistsTxSha ensures ExistsTxSha conforms to the interface contract.
func testExistsTxSha(tc *testContext) bool {
var blockPrev *dcrutil.Block = nil
// 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 dcrd 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 tc.block.Height() != 0 {
var errBlockPrev error
blockPrev, errBlockPrev = tc.db.FetchBlockBySha(&tc.block.MsgBlock().Header.PrevBlock)
if errBlockPrev != nil {
blockSha := tc.block.Sha()
tc.t.Errorf("Failed to fetch parent block of block %v", blockSha)
}
}
votebits := tc.block.MsgBlock().Header.VoteBits
if dcrutil.IsFlagSet16(votebits, dcrutil.BlockValid) && blockPrev != nil {
for i, tx := range blockPrev.Transactions() {
// The transaction must exist in the database.
txHash := tx.Sha()
exists, err := tc.db.ExistsTxSha(txHash)
if err != nil {
tc.t.Errorf("ExistsTxSha (%s): block #%d (%s) tx #%d "+
"(%s) unexpected error: %v", tc.dbType,
tc.blockHeight, tc.blockHash, i, txHash, err)
return false
}
if !exists {
_, err := tc.db.FetchTxBySha(txHash)
if err != nil {
tc.t.Errorf("ExistsTxSha (%s): block #%d (%s) "+
"tx #%d (%s) does not exist", tc.dbType,
tc.blockHeight, tc.blockHash, i, txHash)
}
return false
}
}
}
return true
}
示例6: 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, parent *dcrutil.Block) {
b.Lock()
defer b.Unlock()
b.receivedLogBlocks++
regularTxTreeValid := dcrutil.IsFlagSet16(block.MsgBlock().Header.VoteBits,
dcrutil.BlockValid)
if regularTxTreeValid {
b.receivedLogTx += int64(len(parent.MsgBlock().Transactions))
}
b.receivedLogTx += int64(len(block.MsgBlock().STransactions))
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
}
示例7: dbRemoveTxIndexEntries
// dbRemoveTxIndexEntries uses an existing database transaction to remove the
// latest transaction entry for every transaction in the passed block.
func dbRemoveTxIndexEntries(dbTx database.Tx, block, parent *dcrutil.Block) error {
regularTxTreeValid := dcrutil.IsFlagSet16(block.MsgBlock().Header.VoteBits,
dcrutil.BlockValid)
if regularTxTreeValid {
for _, tx := range parent.Transactions() {
txSha := tx.Sha()
err := dbRemoveTxIndexEntry(dbTx, *txSha)
if err != nil {
return err
}
}
}
for _, tx := range block.STransactions() {
txSha := tx.Sha()
err := dbRemoveTxIndexEntry(dbTx, *txSha)
if err != nil {
return err
}
}
return nil
}
示例8: 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
}
示例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: DropAfterBlockBySha
// DropAfterBlockBySha will remove any blocks from the database after
// the given block.
func (db *LevelDb) DropAfterBlockBySha(sha *chainhash.Hash) (rerr error) {
db.dbLock.Lock()
defer db.dbLock.Unlock()
defer func() {
if rerr == nil {
rerr = db.processBatches()
} else {
db.lBatch().Reset()
}
}()
startheight := db.nextBlock - 1
keepidx, err := db.getBlkLoc(sha)
if err != nil {
// should the error here be normalized ?
log.Tracef("block loc failed %v ", sha)
return err
}
for height := startheight; height > keepidx; height = height - 1 {
var blk *dcrutil.Block
blksha, buf, err := db.getBlkByHeight(height)
if err != nil {
return err
}
blk, err = dcrutil.NewBlockFromBytes(buf)
if err != nil {
return err
}
// Obtain previous block sha and buffer
var blkprev *dcrutil.Block
_, bufprev, errprev := db.getBlkByHeight(height - 1) // discard blkshaprev
if errprev != nil {
return errprev
}
// Do the same thing for the parent block
blkprev, errprev = dcrutil.NewBlockFromBytes(bufprev)
if errprev != nil {
return errprev
}
// Unspend the stake tx in the current block
for _, tx := range blk.MsgBlock().STransactions {
err = db.unSpend(tx)
if err != nil {
return err
}
}
// rather than iterate the list of tx backward, do it twice.
for _, tx := range blk.STransactions() {
var txUo txUpdateObj
txUo.delete = true
db.txUpdateMap[*tx.Sha()] = &txUo
}
// Check to see if the regular txs of the parent were even included; if
// they are, unspend all of these regular tx too
votebits := blk.MsgBlock().Header.VoteBits
if dcrutil.IsFlagSet16(votebits, dcrutil.BlockValid) && height != 0 {
// Unspend the regular tx in the current block
for _, tx := range blkprev.MsgBlock().Transactions {
err = db.unSpend(tx)
if err != nil {
return err
}
}
// rather than iterate the list of tx backward, do it twice.
for _, tx := range blkprev.Transactions() {
var txUo txUpdateObj
txUo.delete = true
db.txUpdateMap[*tx.Sha()] = &txUo
}
}
db.lBatch().Delete(shaBlkToKey(blksha))
db.lBatch().Delete(int64ToKey(height))
}
// update the last block cache
db.lastBlkShaCached = true
db.lastBlkSha = *sha
db.lastBlkIdx = keepidx
db.nextBlock = keepidx + 1
return nil
}
示例11: makeUtxoView
// makeUtxoView creates a mock unspent transaction output view by using the
// transaction index in order to look up all inputs referenced by the
// transactions in the block. This is sometimes needed when catching indexes up
// because many of the txouts could actually already be spent however the
// associated scripts are still required to index them.
func makeUtxoView(dbTx database.Tx, block, parent *dcrutil.Block) (*blockchain.UtxoViewpoint, error) {
view := blockchain.NewUtxoViewpoint()
regularTxTreeValid := dcrutil.IsFlagSet16(block.MsgBlock().Header.VoteBits,
dcrutil.BlockValid)
if regularTxTreeValid {
for txIdx, tx := range parent.Transactions() {
// Coinbases do not reference any inputs. Since the block is
// required to have already gone through full validation, it has
// already been proven on the first transaction in the block is
// a coinbase.
if txIdx == 0 {
continue
}
// Use the transaction index to load all of the referenced
// inputs and add their outputs to the view.
for _, txIn := range tx.MsgTx().TxIn {
// Skip already fetched outputs.
originOut := &txIn.PreviousOutPoint
if view.LookupEntry(&originOut.Hash) != nil {
continue
}
originTx, err := dbFetchTx(dbTx, originOut.Hash)
if err != nil {
return nil, err
}
view.AddTxOuts(dcrutil.NewTx(originTx),
int64(wire.NullBlockHeight), wire.NullBlockIndex)
}
}
}
for _, tx := range block.STransactions() {
msgTx := tx.MsgTx()
isSSGen, _ := stake.IsSSGen(msgTx)
// Use the transaction index to load all of the referenced
// inputs and add their outputs to the view.
for i, txIn := range msgTx.TxIn {
// Skip stakebases.
if isSSGen && i == 0 {
continue
}
originOut := &txIn.PreviousOutPoint
if view.LookupEntry(&originOut.Hash) != nil {
continue
}
originTx, err := dbFetchTx(dbTx, originOut.Hash)
if err != nil {
return nil, err
}
view.AddTxOuts(dcrutil.NewTx(originTx), int64(wire.NullBlockHeight),
wire.NullBlockIndex)
}
}
return view, nil
}
示例12: disconnectTransactions
// disconnectTransactions updates the passed map by undoing transaction and
// spend information for all transactions in the passed block. Only
// transactions in the passed map are updated.
func disconnectTransactions(txStore TxStore, block *dcrutil.Block, parent *dcrutil.Block) error {
// Loop through all of the stake transactions in the block to see if any of
// them are ones that need to be undone based on the transaction store.
for _, tx := range block.STransactions() {
// Clear this transaction from the transaction store if needed.
// Only clear it rather than deleting it because the transaction
// connect code relies on its presence to decide whether or not
// to update the store and any transactions which exist on both
// sides of a fork would otherwise not be updated.
if txD, exists := txStore[*tx.Sha()]; exists {
txD.Tx = nil
txD.BlockHeight = int64(wire.NullBlockHeight)
txD.BlockIndex = wire.NullBlockIndex
txD.Spent = nil
txD.Err = database.ErrTxShaMissing
}
// Unspend the origin transaction output.
for _, txIn := range tx.MsgTx().TxIn {
originHash := &txIn.PreviousOutPoint.Hash
originIndex := txIn.PreviousOutPoint.Index
originTx, exists := txStore[*originHash]
if exists && originTx.Tx != nil && originTx.Err == nil {
if originTx.Spent == nil {
continue
}
if originIndex >= uint32(len(originTx.Spent)) {
continue
}
originTx.Spent[originIndex] = false
}
}
}
// There is no regular tx from before the genesis block, so ignore the genesis
// block for the next step.
if parent != nil && block.Height() != 0 {
mBlock := block.MsgBlock()
votebits := mBlock.Header.VoteBits
regularTxTreeValid := dcrutil.IsFlagSet16(votebits, dcrutil.BlockValid)
// Only bother to unspend transactions if the parent's tx tree was
// validated. Otherwise, these transactions were never in the blockchain's
// history in the first place.
if regularTxTreeValid {
// Loop through all of the regular transactions in the block to see if
// any of them are ones that need to be undone based on the
// transaction store.
for _, tx := range parent.Transactions() {
// Clear this transaction from the transaction store if needed.
// Only clear it rather than deleting it because the transaction
// connect code relies on its presence to decide whether or not
// to update the store and any transactions which exist on both
// sides of a fork would otherwise not be updated.
if txD, exists := txStore[*tx.Sha()]; exists {
txD.Tx = nil
txD.BlockHeight = int64(wire.NullBlockHeight)
txD.BlockIndex = wire.NullBlockIndex
txD.Spent = nil
txD.Err = database.ErrTxShaMissing
}
// Unspend the origin transaction output.
for _, txIn := range tx.MsgTx().TxIn {
originHash := &txIn.PreviousOutPoint.Hash
originIndex := txIn.PreviousOutPoint.Index
originTx, exists := txStore[*originHash]
if exists && originTx.Tx != nil && originTx.Err == nil {
if originTx.Spent == nil {
continue
}
if originIndex >= uint32(len(originTx.Spent)) {
continue
}
originTx.Spent[originIndex] = false
}
}
}
}
}
return nil
}
示例13: connectTransactions
func connectTransactions(txStore TxStore, block *dcrutil.Block, parent *dcrutil.Block) error {
// There is no regular tx from before the genesis block, so ignore the genesis
// block for the next step.
if parent != nil && block.Height() != 0 {
mBlock := block.MsgBlock()
votebits := mBlock.Header.VoteBits
regularTxTreeValid := dcrutil.IsFlagSet16(votebits, dcrutil.BlockValid)
// Only add the transactions in the event that the parent block's regular
// tx were validated.
if regularTxTreeValid {
// Loop through all of the regular 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 parent.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() - 1
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
}
}
}
}
}
// Loop through all of the stake 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 block.STransactions() {
// 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 nil
}
示例14: testUnspentInsertStakeTree
// insert every block in the test chain
// after each insert, fetch all the tx affected by the latest
// block and verify that the the tx is spent/unspent
// new tx should be fully unspent, referenced tx should have
// the associated txout set to spent.
// checks tx tree stake only
func testUnspentInsertStakeTree(t *testing.T) {
// Ignore db remove errors since it means we didn't have an old one.
dbname := fmt.Sprintf("tstdbuspnt1")
dbnamever := dbname + ".ver"
_ = os.RemoveAll(dbname)
_ = os.RemoveAll(dbnamever)
db, err := database.CreateDB("leveldb", dbname)
if err != nil {
t.Errorf("Failed to open test database %v", err)
return
}
defer os.RemoveAll(dbname)
defer os.RemoveAll(dbnamever)
defer func() {
if err := db.Close(); err != nil {
t.Errorf("Close: unexpected error: %v", err)
}
}()
blocks := loadblocks(t)
endtest:
for height := int64(0); height < int64(len(blocks))-1; height++ {
block := blocks[height]
var txneededList []*chainhash.Hash
var txlookupList []*chainhash.Hash
var txOutList []*chainhash.Hash
var txInList []*wire.OutPoint
spentFromParent := make(map[wire.OutPoint]struct{})
for _, tx := range block.MsgBlock().STransactions {
for _, txin := range tx.TxIn {
if txin.PreviousOutPoint.Index == uint32(4294967295) {
continue
}
origintxsha := &txin.PreviousOutPoint.Hash
exists, err := db.ExistsTxSha(origintxsha)
if err != nil {
t.Errorf("ExistsTxSha: unexpected error %v ", err)
}
if !exists {
// Check and see if the outpoint references txtreeregular of
// the previous block. If it does, make sure nothing in tx
// treeregular spends it in flight. Then check make sure it's
// not currently spent for this block. If it isn't, mark it
// spent and skip lookup in the db below, since the db won't
// yet be able to add it as it's still to be inserted.
spentFromParentReg := false
parent := blocks[height-1]
parentValid := dcrutil.IsFlagSet16(dcrutil.BlockValid, block.MsgBlock().Header.VoteBits)
if parentValid {
for _, prtx := range parent.Transactions() {
// Check and make sure it's not being spent in this tx
// tree first by an in flight tx. Mark it spent if it
// is so it fails the check below.
for _, prtxCheck := range parent.Transactions() {
for _, prTxIn := range prtxCheck.MsgTx().TxIn {
if prTxIn.PreviousOutPoint == txin.PreviousOutPoint {
spentFromParent[txin.PreviousOutPoint] = struct{}{}
}
}
}
// If it is in the tree, make sure it's not already spent
// somewhere else and mark it spent. Set the flag below
// so we skip lookup.
if prtx.Sha().IsEqual(origintxsha) {
if _, spent := spentFromParent[txin.PreviousOutPoint]; !spent {
spentFromParent[txin.PreviousOutPoint] = struct{}{}
spentFromParentReg = true
}
}
}
}
if !spentFromParentReg {
t.Errorf("referenced tx not found %v %v", origintxsha, height)
} else {
continue
}
}
txInList = append(txInList, &txin.PreviousOutPoint)
txneededList = append(txneededList, origintxsha)
txlookupList = append(txlookupList, origintxsha)
}
txshaname := tx.TxSha()
txlookupList = append(txlookupList, &txshaname)
txOutList = append(txOutList, &txshaname)
}
txneededmap := map[chainhash.Hash]*database.TxListReply{}
txlist := db.FetchUnSpentTxByShaList(txneededList)
for _, txe := range txlist {
if txe.Err != nil {
//.........這裏部分代碼省略.........
示例15: indexBlock
// indexBlock extract all of the standard addresses from all of the transactions
// in the passed block and maps each of them to the assocaited transaction using
// the passed map.
func (idx *AddrIndex) indexBlock(data writeIndexData, block, parent *dcrutil.Block, view *blockchain.UtxoViewpoint) {
regularTxTreeValid := dcrutil.IsFlagSet16(block.MsgBlock().Header.VoteBits,
dcrutil.BlockValid)
var stakeStartIdx int
if regularTxTreeValid {
for txIdx, tx := range parent.Transactions() {
// Coinbases do not reference any inputs. Since the block is
// required to have already gone through full validation, it has
// already been proven on the first transaction in the block is
// a coinbase.
if txIdx != 0 {
for _, txIn := range tx.MsgTx().TxIn {
// The view should always have the input since
// the index contract requires it, however, be
// safe and simply ignore any missing entries.
origin := &txIn.PreviousOutPoint
entry := view.LookupEntry(&origin.Hash)
if entry == nil {
log.Warnf("Missing input %v for tx %v while "+
"indexing block %v (height %v)\n", origin.Hash,
tx.Sha(), block.Sha(), block.Height())
continue
}
version := entry.ScriptVersionByIndex(origin.Index)
pkScript := entry.PkScriptByIndex(origin.Index)
txType := entry.TransactionType()
idx.indexPkScript(data, version, pkScript, txIdx,
txType == stake.TxTypeSStx)
}
}
for _, txOut := range tx.MsgTx().TxOut {
idx.indexPkScript(data, txOut.Version, txOut.PkScript, txIdx,
false)
}
}
stakeStartIdx = len(parent.Transactions())
}
for txIdx, tx := range block.STransactions() {
msgTx := tx.MsgTx()
thisTxOffset := txIdx + stakeStartIdx
isSSGen, _ := stake.IsSSGen(msgTx)
for i, txIn := range msgTx.TxIn {
// Skip stakebases.
if isSSGen && i == 0 {
continue
}
// The view should always have the input since
// the index contract requires it, however, be
// safe and simply ignore any missing entries.
origin := &txIn.PreviousOutPoint
entry := view.LookupEntry(&origin.Hash)
if entry == nil {
log.Warnf("Missing input %v for tx %v while "+
"indexing block %v (height %v)\n", origin.Hash,
tx.Sha(), block.Sha(), block.Height())
continue
}
version := entry.ScriptVersionByIndex(origin.Index)
pkScript := entry.PkScriptByIndex(origin.Index)
txType := entry.TransactionType()
idx.indexPkScript(data, version, pkScript, thisTxOffset,
txType == stake.TxTypeSStx)
}
isSStx, _ := stake.IsSStx(msgTx)
for _, txOut := range msgTx.TxOut {
idx.indexPkScript(data, txOut.Version, txOut.PkScript,
thisTxOffset, isSStx)
}
}
}