Пример #1
0
// 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...)
		}
	}

	return addrIndex, nil
}
Пример #2
0
// traceDevPremineOuts returns a list of outpoints that are part of the dev
// premine coins and are ancestors of the inputs to the passed transaction hash.
func traceDevPremineOuts(client *dcrrpcclient.Client, txHash *chainhash.Hash) ([]wire.OutPoint, error) {
	// Trace the lineage of all inputs to the provided transaction back to
	// the coinbase outputs that generated them and add those outpoints to
	// a list.  Also, keep track of all of the processed transactions in
	// order to avoid processing duplicates.
	knownCoinbases := make(map[chainhash.Hash]struct{})
	processedHashes := make(map[chainhash.Hash]struct{})
	coinbaseOuts := make([]wire.OutPoint, 0, 10)
	processOuts := []wire.OutPoint{{Hash: *txHash}}
	for len(processOuts) > 0 {
		// Grab the first outpoint to process and skip it if it has
		// already been traced.
		outpoint := processOuts[0]
		processOuts = processOuts[1:]
		if _, exists := processedHashes[outpoint.Hash]; exists {
			if _, exists := knownCoinbases[outpoint.Hash]; exists {
				coinbaseOuts = append(coinbaseOuts, outpoint)
			}
			continue
		}
		processedHashes[outpoint.Hash] = struct{}{}

		// Request the transaction for the outpoint from the server.
		tx, err := client.GetRawTransaction(&outpoint.Hash)
		if err != nil {
			return nil, fmt.Errorf("failed to get transaction %v: %v",
				&outpoint.Hash, err)
		}

		// Add the outpoint to the coinbase outputs list when it is part
		// of a coinbase transaction.  Also, keep track of the fact the
		// transaction is a coinbase to use when avoiding duplicate
		// checks.
		if blockchain.IsCoinBase(tx) {
			knownCoinbases[outpoint.Hash] = struct{}{}
			coinbaseOuts = append(coinbaseOuts, outpoint)
			continue
		}

		// Add the inputs to the transaction to the list of transactions
		// to load and continue tracing.
		//
		// However, skip the first input to stake generation txns since
		// they are creating new coins.  The remaining inputs to a
		// stake generation transaction still need to be traced since
		// they represent the coins that purchased the ticket.
		txIns := tx.MsgTx().TxIn
		isSSGen, _ := stake.IsSSGen(tx.MsgTx())
		if isSSGen {
			txIns = txIns[1:]
		}
		for _, txIn := range txIns {
			processOuts = append(processOuts, txIn.PreviousOutPoint)
		}
	}

	// Add any of the outputs that are dev premine outputs to a list.
	var devPremineOuts []wire.OutPoint
	for _, coinbaseOut := range coinbaseOuts {
		if isDevPremineOut(coinbaseOut) {
			devPremineOuts = append(devPremineOuts, coinbaseOut)
		}
	}

	return devPremineOuts, nil
}