// FilterTransactionsByAddress returns all transactions currently in the // mempool that either create an output to the passed address or spend a // previously created ouput to the address. func (mp *txMemPool) FilterTransactionsByAddress(addr coinutil.Address) ([]*coinutil.Tx, error) { // Protect concurrent access. mp.RLock() defer mp.RUnlock() if txs, exists := mp.addrindex[addr.EncodeAddress()]; exists { addressTxs := make([]*coinutil.Tx, 0, len(txs)) for txHash := range txs { if txD, exists := mp.pool[txHash]; exists { addressTxs = append(addressTxs, txD.Tx) } } return addressTxs, nil } return nil, fmt.Errorf("address does not have any transactions in the pool") }
// TotalReceivedForAddr iterates through a wallet's transaction history, // returning the total amount of bitcoins received for a single wallet // address. func (w *Wallet) TotalReceivedForAddr(addr coinutil.Address, minConf int32) (coinutil.Amount, error) { syncBlock := w.Manager.SyncedTo() var ( addrStr = addr.EncodeAddress() amount coinutil.Amount stopHeight int32 ) if minConf > 0 { stopHeight = syncBlock.Height - minConf + 1 } else { stopHeight = -1 } err := w.TxStore.RangeTransactions(0, stopHeight, func(details []wtxmgr.TxDetails) (bool, error) { for i := range details { detail := &details[i] for _, cred := range detail.Credits { pkScript := detail.MsgTx.TxOut[cred.Index].PkScript _, addrs, _, err := txscript.ExtractPkScriptAddrs( pkScript, w.chainParams) // An error creating addresses from the output script only // indicates a non-standard script, so ignore this credit. if err != nil { continue } for _, a := range addrs { if addrStr == a.EncodeAddress() { amount += cred.Amount break } } } } return false, nil }) return amount, err }
// PayToAddrScript creates a new script to pay a transaction output to a the // specified address. func PayToAddrScript(addr coinutil.Address) ([]byte, error) { switch addr := addr.(type) { case *coinutil.AddressPubKeyHash: if addr == nil { return nil, ErrUnsupportedAddress } return payToPubKeyHashScript(addr.ScriptAddress()) case *coinutil.AddressScriptHash: if addr == nil { return nil, ErrUnsupportedAddress } return payToScriptHashScript(addr.ScriptAddress()) case *coinutil.AddressPubKey: if addr == nil { return nil, ErrUnsupportedAddress } return payToPubKeyScript(addr.ScriptAddress()) } return nil, ErrUnsupportedAddress }
// FetchTxsForAddr looks up and returns all transactions which either // spend from a previously created output of the passed address, or // create a new output locked to the passed address. The, `limit` parameter // should be the max number of transactions to be returned. Additionally, if the // caller wishes to seek forward in the results some amount, the 'seek' // represents how many results to skip. func (db *LevelDb) FetchTxsForAddr(addr coinutil.Address, skip int, limit int, reverse bool) ([]*database.TxListReply, int, error) { db.dbLock.Lock() defer db.dbLock.Unlock() // Enforce constraints for skip and limit. if skip < 0 { return nil, 0, errors.New("offset for skip must be positive") } if limit < 0 { return nil, 0, errors.New("value for limit must be positive") } // Parse address type, bailing on an unknown type. var addrKey []byte switch addr := addr.(type) { case *coinutil.AddressPubKeyHash: hash160 := addr.Hash160() addrKey = hash160[:] case *coinutil.AddressScriptHash: hash160 := addr.Hash160() addrKey = hash160[:] case *coinutil.AddressPubKey: hash160 := addr.AddressPubKeyHash().Hash160() addrKey = hash160[:] default: return nil, 0, database.ErrUnsupportedAddressType } // Create the prefix for our search. addrPrefix := make([]byte, 23, 23) copy(addrPrefix[0:3], addrIndexKeyPrefix) copy(addrPrefix[3:23], addrKey) iter := db.lDb.NewIterator(bytesPrefix(addrPrefix), nil) skipped := 0 if reverse { // Go to the last element if reverse iterating. iter.Last() // Skip "one past" the last element so the loops below don't // miss the last element due to Prev() being called first. // We can safely ignore iterator exhaustion since the loops // below will see there's no keys anyway. iter.Next() } for skip != 0 && advanceIterator(iter, reverse) { skip-- skipped++ } // Iterate through all address indexes that match the targeted prefix. var replies []*database.TxListReply var rawIndex [12]byte for advanceIterator(iter, reverse) && limit != 0 { copy(rawIndex[:], iter.Key()[23:35]) addrIndex := unpackTxIndex(rawIndex) tx, blkSha, blkHeight, _, err := db.fetchTxDataByLoc(addrIndex.blkHeight, addrIndex.txoffset, addrIndex.txlen, []byte{}) if err != nil { // Eat a possible error due to a potential re-org. continue } txSha := tx.TxSha() txReply := &database.TxListReply{Sha: &txSha, Tx: tx, BlkSha: blkSha, Height: blkHeight, TxSpent: []bool{}, Err: err} replies = append(replies, txReply) limit-- } iter.Release() if err := iter.Error(); err != nil { return nil, 0, err } return replies, skipped, nil }