Beispiel #1
0
// dumpSStxHashes dumps the hashes of all owned SStxs for some address.
func (s *StakeStore) dumpSStxHashesForAddress(ns walletdb.ReadBucket, addr dcrutil.Address) ([]chainhash.Hash, error) {
	// Extract the HASH160 script hash; if it's not 20 bytes
	// long, return an error.
	hash160 := addr.ScriptAddress()
	if len(hash160) != 20 {
		str := "stake store is closed"
		return nil, stakeStoreError(ErrInput, str, nil)
	}
	_, addrIsP2SH := addr.(*dcrutil.AddressScriptHash)

	allTickets := s.dumpSStxHashes()
	var ticketsForAddr []chainhash.Hash

	// Access the database and store the result locally.
	for _, h := range allTickets {
		thisHash160, p2sh, err := fetchSStxRecordSStxTicketHash160(ns, &h)
		if err != nil {
			str := "failure getting ticket 0th out script hashes from db"
			return nil, stakeStoreError(ErrDatabase, str, err)
		}
		if addrIsP2SH != p2sh {
			continue
		}

		if bytes.Equal(hash160, thisHash160) {
			ticketsForAddr = append(ticketsForAddr, h)
		}
	}

	return ticketsForAddr, nil
}
Beispiel #2
0
// TicketsWithAddress returns a slice of ticket hashes that are currently live
// corresponding to the given address.
//
// This function is safe for concurrent access.
func (b *BlockChain) TicketsWithAddress(address dcrutil.Address) ([]chainhash.Hash, error) {
	b.chainLock.RLock()
	sn := b.bestNode.stakeNode
	b.chainLock.RUnlock()

	tickets := sn.LiveTickets()

	var ticketsWithAddr []chainhash.Hash
	err := b.db.View(func(dbTx database.Tx) error {
		var err error
		for _, hash := range tickets {
			utxo, err := dbFetchUtxoEntry(dbTx, &hash)
			if err != nil {
				return err
			}

			_, addrs, _, err :=
				txscript.ExtractPkScriptAddrs(txscript.DefaultScriptVersion,
					utxo.PkScriptByIndex(0), b.chainParams)
			if addrs[0].EncodeAddress() == address.EncodeAddress() {
				ticketsWithAddr = append(ticketsWithAddr, hash)
			}
		}
		return err
	})
	if err != nil {
		return nil, err
	}

	return ticketsWithAddr, nil
}
Beispiel #3
0
// dumpSStxHashes dumps the hashes of all owned SStxs for some address.
func (s *StakeStore) dumpSStxHashesForAddress(addr dcrutil.Address) ([]chainhash.Hash, error) {
	// Extract the HASH160 script hash; if it's not 20 bytes
	// long, return an error.
	scriptHash := addr.ScriptAddress()
	if len(scriptHash) != 20 {
		str := "stake store is closed"
		return nil, stakeStoreError(ErrInput, str, nil)
	}

	var err error
	allTickets := s.dumpSStxHashes()
	var ticketsForAddr []chainhash.Hash

	// Access the database and store the result locally.
	err = s.namespace.View(func(tx walletdb.Tx) error {
		var err error
		var thisScrHash []byte
		for _, h := range allTickets {
			thisScrHash, err = fetchSStxRecordSStxTicketScriptHash(tx, &h)
			if err != nil {
				return err
			}
			if bytes.Equal(scriptHash, thisScrHash) {
				ticketsForAddr = append(ticketsForAddr, h)
			}
		}
		return nil
	})
	if err != nil {
		str := "failure getting ticket 0th out script hashes from db"
		return nil, stakeStoreError(ErrDatabase, str, err)
	}

	return ticketsForAddr, nil
}
Beispiel #4
0
// GetLiveTicketsForAddress gets all currently active tickets for a given
// address.
func (tmdb *TicketDB) GetLiveTicketsForAddress(
	address dcrutil.Address) ([]chainhash.Hash, error) {
	tmdb.mtx.Lock()
	defer tmdb.mtx.Unlock()

	var ltfa []chainhash.Hash
	for i := 0; i < BucketsSize; i++ {
		for _, ticket := range tmdb.maps.ticketMap[i] {
			// Load the ticket from the database and find the address that it's
			// going to.
			txReply, err := tmdb.database.FetchTxBySha(&ticket.SStxHash)
			if err != nil {
				return nil, err
			}

			_, addr, _, err :=
				txscript.ExtractPkScriptAddrs(txReply[0].Tx.TxOut[0].Version,
					txReply[0].Tx.TxOut[0].PkScript, tmdb.chainParams)
			if err != nil {
				return nil, err
			}

			// Compare the HASH160 result and see if it's equal.
			if bytes.Equal(addr[0].ScriptAddress(), address.ScriptAddress()) {
				ltfa = append(ltfa, ticket.SStxHash)
			}
		}
	}

	return ltfa, nil
}
Beispiel #5
0
// SearchRawTransactionsAsync returns an instance of a type that can be used to
// get the result of the RPC at some future time by invoking the Receive
// function on the returned instance.
//
// See SearchRawTransactions for the blocking version and more details.
func (c *Client) SearchRawTransactionsAsync(address dcrutil.Address, skip,
	count int, reverse bool,
	filterAddrs []string) FutureSearchRawTransactionsResult {

	addr := address.EncodeAddress()
	verbose := dcrjson.Int(0)
	cmd := dcrjson.NewSearchRawTransactionsCmd(addr, verbose, &skip, &count,
		nil, &reverse, &filterAddrs)
	return c.sendCmd(cmd)
}
Beispiel #6
0
// stakePoolUserInfo returns the stake pool user information for a given stake
// pool user, keyed to their P2SH voting address.
func (s *StakeStore) stakePoolUserInfo(ns walletdb.ReadBucket, user dcrutil.Address) (*StakePoolUser, error) {
	_, isScriptHash := user.(*dcrutil.AddressScriptHash)
	_, isP2PKH := user.(*dcrutil.AddressPubKeyHash)
	if !(isScriptHash || isP2PKH) {
		str := fmt.Sprintf("user %v is invalid", user.EncodeAddress())
		return nil, stakeStoreError(ErrBadPoolUserAddr, str, nil)
	}
	scriptHashB := user.ScriptAddress()
	scriptHash := new([20]byte)
	copy(scriptHash[:], scriptHashB)

	stakePoolUser := new(StakePoolUser)

	// Catch missing user errors below and blank out the stake
	// pool user information for the section if the user has
	// no entries.
	missingValidTickets, missingInvalidTickets := false, false

	userTickets, fetchErrVal := fetchStakePoolUserTickets(ns, *scriptHash)
	if fetchErrVal != nil {
		stakeMgrErr, is := fetchErrVal.(StakeStoreError)
		if is {
			missingValidTickets = stakeMgrErr.ErrorCode ==
				ErrPoolUserTicketsNotFound
		} else {
			return nil, fetchErrVal
		}
	}
	if missingValidTickets {
		userTickets = make([]*PoolTicket, 0)
	}

	invalTickets, fetchErrInval := fetchStakePoolUserInvalTickets(ns,
		*scriptHash)
	if fetchErrInval != nil {
		stakeMgrErr, is := fetchErrInval.(StakeStoreError)
		if is {
			missingInvalidTickets = stakeMgrErr.ErrorCode ==
				ErrPoolUserInvalTcktsNotFound
		} else {
			return nil, fetchErrInval
		}
	}
	if missingInvalidTickets {
		invalTickets = make([]*chainhash.Hash, 0)
	}

	stakePoolUser.Tickets = userTickets
	stakePoolUser.InvalidTickets = invalTickets

	return stakePoolUser, nil
}
Beispiel #7
0
// updateStakePoolUserInvalTickets updates the list of invalid stake pool
// tickets for a given user. If the ticket does not currently exist in the
// database, it adds it.
func (s *StakeStore) updateStakePoolUserInvalTickets(ns walletdb.ReadWriteBucket, user dcrutil.Address, ticket *chainhash.Hash) error {
	_, isScriptHash := user.(*dcrutil.AddressScriptHash)
	_, isP2PKH := user.(*dcrutil.AddressPubKeyHash)
	if !(isScriptHash || isP2PKH) {
		str := fmt.Sprintf("user %v is invalid", user.EncodeAddress())
		return stakeStoreError(ErrBadPoolUserAddr, str, nil)
	}
	scriptHashB := user.ScriptAddress()
	scriptHash := new([20]byte)
	copy(scriptHash[:], scriptHashB)

	return updateStakePoolInvalUserTickets(ns, *scriptHash, ticket)
}
Beispiel #8
0
// SearchRawTransactionsVerboseAsync returns an instance of a type that can be
// used to get the result of the RPC at some future time by invoking the Receive
// function on the returned instance.
//
// See SearchRawTransactionsVerbose for the blocking version and more details.
func (c *Client) SearchRawTransactionsVerboseAsync(address dcrutil.Address, skip,
	count int, includePrevOut bool, reverse bool,
	filterAddrs *[]string) FutureSearchRawTransactionsVerboseResult {

	addr := address.EncodeAddress()
	verbose := dcrjson.Int(1)
	var prevOut *int
	if includePrevOut {
		prevOut = dcrjson.Int(1)
	}
	cmd := dcrjson.NewSearchRawTransactionsCmd(addr, verbose, &skip, &count,
		prevOut, &reverse, filterAddrs)
	return c.sendCmd(cmd)
}
Beispiel #9
0
// PayToSSRtx creates a new script to pay a transaction output to a
// public key hash, but tags the output with OP_SSRTX. For use in constructing
// valid SSRtx.
func PayToSSRtx(addr dcrutil.Address) ([]byte, error) {
	if addr == nil {
		return nil, ErrUnsupportedAddress
	}

	// Only pay to pubkey hash and pay to script hash are
	// supported.
	scriptType := PubKeyHashTy
	switch addr := addr.(type) {
	case *dcrutil.AddressPubKeyHash:
		if addr.DSA(addr.Net()) != chainec.ECTypeSecp256k1 {
			return nil, ErrUnsupportedAddress
		}
		break
	case *dcrutil.AddressScriptHash:
		scriptType = ScriptHashTy
		break
	default:
		return nil, ErrUnsupportedAddress
	}

	hash := addr.ScriptAddress()

	if scriptType == PubKeyHashTy {
		return NewScriptBuilder().AddOp(OP_SSRTX).AddOp(OP_DUP).
			AddOp(OP_HASH160).AddData(hash).AddOp(OP_EQUALVERIFY).
			AddOp(OP_CHECKSIG).Script()
	}
	return NewScriptBuilder().AddOp(OP_SSRTX).AddOp(OP_HASH160).
		AddData(hash).AddOp(OP_EQUAL).Script()
}
Beispiel #10
0
func (s *walletServer) NextAddress(ctx context.Context, req *pb.NextAddressRequest) (
	*pb.NextAddressResponse, error) {

	var (
		addr dcrutil.Address
		err  error
	)
	switch req.Kind {
	case pb.NextAddressRequest_BIP0044_EXTERNAL:
		addr, err = s.wallet.NewAddress(req.Account, waddrmgr.ExternalBranch)
		if err != nil {
			return nil, translateError(err)
		}
	case pb.NextAddressRequest_BIP0044_INTERNAL:
		addr, err = s.wallet.NewAddress(req.Account, waddrmgr.InternalBranch)
		if err != nil {
			return nil, translateError(err)
		}
	default:
		return nil, grpc.Errorf(codes.InvalidArgument, "kind=%v", req.Kind)
	}
	if err != nil {
		return nil, translateError(err)
	}

	pubKey, err := s.wallet.PubKeyForAddress(addr)
	if err != nil {
		return nil, translateError(err)
	}
	pubKeyAddr, err := dcrutil.NewAddressSecpPubKey(pubKey.Serialize(), s.wallet.ChainParams())
	if err != nil {
		return nil, translateError(err)
	}

	return &pb.NextAddressResponse{
		Address:   addr.EncodeAddress(),
		PublicKey: pubKeyAddr.String(),
	}, nil
}
Beispiel #11
0
// GenerateSStxAddrPush generates an OP_RETURN push for SSGen payment addresses in
// an SStx.
func GenerateSStxAddrPush(addr dcrutil.Address, amount dcrutil.Amount,
	limits uint16) ([]byte, error) {
	if addr == nil {
		return nil, ErrUnsupportedAddress
	}

	// Only pay to pubkey hash and pay to script hash are
	// supported.
	scriptType := PubKeyHashTy
	switch addr := addr.(type) {
	case *dcrutil.AddressPubKeyHash:
		if addr.DSA(addr.Net()) != chainec.ECTypeSecp256k1 {
			return nil, ErrUnsupportedAddress
		}
		break
	case *dcrutil.AddressScriptHash:
		scriptType = ScriptHashTy
		break
	default:
		return nil, ErrUnsupportedAddress
	}

	// Prefix
	dataPushes := []byte{
		0x6a, // OP_RETURN
		0x1e, // OP_DATA_30
	}

	hash := addr.ScriptAddress()

	amountBuffer := make([]byte, 8)
	binary.LittleEndian.PutUint64(amountBuffer, uint64(amount))

	// Set the bit flag indicating pay to script hash.
	if scriptType == ScriptHashTy {
		amountBuffer[7] |= 1 << 7
	}

	limitsBuffer := make([]byte, 2)
	binary.LittleEndian.PutUint16(limitsBuffer, limits)

	// Concatenate the prefix, pubkeyhash, and amount.
	addrOut := append(dataPushes, hash...)
	addrOut = append(addrOut, amountBuffer...)
	addrOut = append(addrOut, limitsBuffer...)

	return addrOut, nil
}
Beispiel #12
0
// PayToAddrScript creates a new script to pay a transaction output to a the
// specified address.
func PayToAddrScript(addr dcrutil.Address) ([]byte, error) {
	switch addr := addr.(type) {
	case *dcrutil.AddressPubKeyHash:
		if addr == nil {
			return nil, ErrUnsupportedAddress
		}
		switch addr.DSA(addr.Net()) {
		case chainec.ECTypeSecp256k1:
			return payToPubKeyHashScript(addr.ScriptAddress())
		case chainec.ECTypeEdwards:
			return payToPubKeyHashEdwardsScript(addr.ScriptAddress())
		case chainec.ECTypeSecSchnorr:
			return payToPubKeyHashSchnorrScript(addr.ScriptAddress())
		}

	case *dcrutil.AddressScriptHash:
		if addr == nil {
			return nil, ErrUnsupportedAddress
		}
		return payToScriptHashScript(addr.ScriptAddress())

	case *dcrutil.AddressSecpPubKey:
		if addr == nil {
			return nil, ErrUnsupportedAddress
		}
		return payToPubKeyScript(addr.ScriptAddress())

	case *dcrutil.AddressEdwardsPubKey:
		if addr == nil {
			return nil, ErrUnsupportedAddress
		}
		return payToEdwardsPubKeyScript(addr.ScriptAddress())

	case *dcrutil.AddressSecSchnorrPubKey:
		if addr == nil {
			return nil, ErrUnsupportedAddress
		}
		return payToSchnorrPubKeyScript(addr.ScriptAddress())
	}

	return nil, ErrUnsupportedAddress
}
// SearchRawTransactionsVerboseAsync returns an instance of a type that can be
// used to get the result of the RPC at some future time by invoking the Receive
// function on the returned instance.
//
// See SearchRawTransactionsVerbose for the blocking version and more details.
func (c *Client) SearchRawTransactionsVerboseAsync(address dcrutil.Address, skip, count int) FutureSearchRawTransactionsVerboseResult {
	addr := address.EncodeAddress()
	verbose := dcrjson.Int(1)
	cmd := dcrjson.NewSearchRawTransactionsCmd(addr, verbose, &skip, &count)
	return c.sendCmd(cmd)
}
Beispiel #14
0
// ExistsAddressAsync returns an instance of a type that can be used to get the
// result of the RPC at some future time by invoking the Receive function on the
// returned instance.
func (c *Client) ExistsAddressAsync(address dcrutil.Address) FutureExistsAddressResult {
	cmd := dcrjson.NewExistsAddressCmd(address.EncodeAddress())
	return c.sendCmd(cmd)
}
Beispiel #15
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
}
Beispiel #16
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, 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
}
Beispiel #17
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
}
Beispiel #18
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
}