// 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 }
// 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 }