Exemplo n.º 1
0
// addrToKey converts known address types to an addrindex key.  An error is
// returned for unsupported types.
func addrToKey(addr dcrutil.Address, params *chaincfg.Params) ([addrKeySize]byte, error) {
	switch addr := addr.(type) {
	case *dcrutil.AddressPubKeyHash:
		switch addr.DSA(params) {
		case chainec.ECTypeSecp256k1:
			var result [addrKeySize]byte
			result[0] = addrKeyTypePubKeyHash
			copy(result[1:], addr.Hash160()[:])
			return result, nil
		case chainec.ECTypeEdwards:
			var result [addrKeySize]byte
			result[0] = addrKeyTypePubKeyHashEdwards
			copy(result[1:], addr.Hash160()[:])
			return result, nil
		case chainec.ECTypeSecSchnorr:
			var result [addrKeySize]byte
			result[0] = addrKeyTypePubKeyHashSchnorr
			copy(result[1:], addr.Hash160()[:])
			return result, nil
		}

	case *dcrutil.AddressScriptHash:
		var result [addrKeySize]byte
		result[0] = addrKeyTypeScriptHash
		copy(result[1:], addr.Hash160()[:])
		return result, nil

	case *dcrutil.AddressSecpPubKey:
		var result [addrKeySize]byte
		result[0] = addrKeyTypePubKeyHash
		copy(result[1:], addr.AddressPubKeyHash().Hash160()[:])
		return result, nil

	case *dcrutil.AddressEdwardsPubKey:
		var result [addrKeySize]byte
		result[0] = addrKeyTypePubKeyHashEdwards
		copy(result[1:], addr.AddressPubKeyHash().Hash160()[:])
		return result, nil

	case *dcrutil.AddressSecSchnorrPubKey:
		var result [addrKeySize]byte
		result[0] = addrKeyTypePubKeyHashSchnorr
		copy(result[1:], addr.AddressPubKeyHash().Hash160()[:])
		return result, nil
	}

	return [addrKeySize]byte{}, errUnsupportedAddressType
}
Exemplo n.º 2
0
// initialize initializes an address pool for usage by loading the latest
// unused address from the blockchain itself.
func (a *addressPool) initialize(branch uint32, w *Wallet) error {
	a.addresses = make([]string, 0)
	a.mutex = new(sync.Mutex)
	a.wallet = w
	a.branch = branch

	var err error

	// Retrieve the last addresses from wallet closing and storing.
	lastExtAddr, lastIntAddr, err := w.Manager.LastUsedAddresses()
	if err != nil {
		return err
	}
	var lastSavedAddr dcrutil.Address

	// Get the last managed address for the account and branch.
	var lastIndex uint32
	if branch == waddrmgr.InternalBranch {
		_, lastIndex, err =
			a.wallet.Manager.LastInternalAddress(waddrmgr.DefaultAccountNum)
		if err != nil {
			return err
		}
		lastSavedAddr = lastIntAddr
	}
	if branch == waddrmgr.ExternalBranch {
		_, lastIndex, err =
			a.wallet.Manager.LastExternalAddress(waddrmgr.DefaultAccountNum)
		if err != nil {
			return err
		}
		lastSavedAddr = lastExtAddr
	}

	// Get the actual last index as recorded in the blockchain.
	traversed := 0
	actualLastIndex := lastIndex
	for actualLastIndex != 0 && traversed != addressPoolBuffer {
		addr, err := a.wallet.Manager.GetAddress(actualLastIndex,
			waddrmgr.DefaultAccountNum, branch)
		if err != nil {
			return err
		}

		// Start with the address on tip if address reuse is disabled.
		if !w.addressReuse {
			// If address reuse is disabled, we compare to the last
			// stored address.
			if lastSavedAddr != nil {
				lsaH160 := lastSavedAddr.Hash160()
				thisH160 := addr.Hash160()
				if *lsaH160 == *thisH160 {
					// We actually append this address because the
					// LastUsedAddresses function in Manager actually
					// stores the next to-be-used address rather than
					// the last used address. See Close below.
					a.addresses = append([]string{addr.EncodeAddress()},
						a.addresses...)
					break
				}
			}
		} else {
			// Otherwise, search the blockchain for the last actually used
			// address.
			exists, err := a.wallet.existsAddressOnChain(addr)
			if err != nil {
				return err
			}
			if exists {
				break
			}
		}

		// Insert this unused address into the cache.
		a.addresses = append([]string{addr.EncodeAddress()},
			a.addresses...)

		actualLastIndex--
		traversed++
	}

	a.cursor = 0

	return nil
}
Exemplo n.º 3
0
// 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 dcrutil.Address, skip int,
	limit int) ([]*database.TxListReply, error) {
	db.dbLock.Lock()
	defer db.dbLock.Unlock()

	// Enforce constraints for skip and limit.
	if skip < 0 {
		return nil, errors.New("offset for skip must be positive")
	}
	if limit < 1 {
		return nil, errors.New("value for limit must be positive")
	}

	// Parse address type, bailing on an unknown type.
	var addrKey []byte
	switch addr := addr.(type) {
	case *dcrutil.AddressPubKeyHash:
		hash160 := addr.Hash160()
		addrKey = hash160[:]
	case *dcrutil.AddressScriptHash:
		hash160 := addr.Hash160()
		addrKey = hash160[:]
	case *dcrutil.AddressSecpPubKey:
		hash160 := addr.AddressPubKeyHash().Hash160()
		addrKey = hash160[:]
	case *dcrutil.AddressEdwardsPubKey:
		hash160 := addr.AddressPubKeyHash().Hash160()
		addrKey = hash160[:]
	case *dcrutil.AddressSecSchnorrPubKey:
		hash160 := addr.AddressPubKeyHash().Hash160()
		addrKey = hash160[:]
	default:
		return nil, 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)
	for skip != 0 {
		iter.Next()
		skip--
	}

	// Iterate through all address indexes that match the targeted prefix.
	var replies []*database.TxListReply
	var rawIndex [database.AddrIndexKeySize]byte
	for iter.Next() {
		if limit == 0 {
			break
		}

		copy(rawIndex[:], iter.Key())
		addrIndex := unpackTxIndex(rawIndex)

		tx, blkSha, blkHeight, _, err := db.fetchTxDataByLoc(
			int64(addrIndex.Height),
			int(addrIndex.TxOffset),
			int(addrIndex.TxLen),
			[]byte{})
		if err != nil {
			log.Warnf("tx listed in addrindex record not found, height: %v"+
				" offset: %v, len: %v", addrIndex.Height, addrIndex.TxOffset,
				addrIndex.TxLen)
			limit--
			continue
		}

		var txSha chainhash.Hash
		if tx != nil {
			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, err
	}

	return replies, nil
}
Exemplo n.º 4
0
Arquivo: tx.go Projeto: alexlyp/dcrd
// 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 dcrutil.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 *dcrutil.AddressPubKeyHash:
		hash160 := addr.Hash160()
		addrKey = hash160[:]
	case *dcrutil.AddressScriptHash:
		hash160 := addr.Hash160()
		addrKey = hash160[:]
	case *dcrutil.AddressSecpPubKey:
		hash160 := addr.AddressPubKeyHash().Hash160()
		addrKey = hash160[:]
	case *dcrutil.AddressEdwardsPubKey:
		hash160 := addr.AddressPubKeyHash().Hash160()
		addrKey = hash160[:]
	case *dcrutil.AddressSecSchnorrPubKey:
		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 [database.AddrIndexKeySize]byte
	for advanceIterator(iter, reverse) && limit != 0 {
		copy(rawIndex[:], iter.Key())
		addrIndex := unpackTxIndex(rawIndex)

		tx, blkSha, blkHeight, _, err := db.fetchTxDataByLoc(
			int64(addrIndex.Height),
			int(addrIndex.TxOffset),
			int(addrIndex.TxLen),
			[]byte{})
		if err != nil {
			log.Warnf("tx listed in addrindex record not found, height: %v"+
				" offset: %v, len: %v", addrIndex.Height, addrIndex.TxOffset,
				addrIndex.TxLen)
			limit--
			continue
		}

		var txSha chainhash.Hash
		if tx != nil {
			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
}