func nextAddr(p *Pool, ns, addrmgrNs walletdb.ReadBucket, seriesID uint32, branch Branch, index Index, stopSeriesID uint32) (
	*WithdrawalAddress, error) {
	series := p.Series(seriesID)
	if series == nil {
		return nil, newError(ErrSeriesNotExists, fmt.Sprintf("unknown seriesID: %d", seriesID), nil)
	}
	branch++
	if int(branch) > len(series.publicKeys) {
		highestIdx, err := p.highestUsedSeriesIndex(ns, seriesID)
		if err != nil {
			return nil, err
		}
		if index > highestIdx {
			seriesID++
			log.Debugf("nextAddr(): reached last branch (%d) and highest used index (%d), "+
				"moving on to next series (%d)", branch, index, seriesID)
			index = 0
		} else {
			index++
		}
		branch = 0
	}
	if seriesID >= stopSeriesID {
		return nil, nil
	}
	addr, err := p.WithdrawalAddress(ns, addrmgrNs, seriesID, branch, index)
	if err != nil && err.(Error).ErrorCode == ErrWithdrawFromUnusedAddr {
		log.Debugf("nextAddr(): skipping addr (series #%d, branch #%d, index #%d) as it hasn't "+
			"been used before", seriesID, branch, index)
		return nextAddr(p, ns, addrmgrNs, seriesID, branch, index, stopSeriesID)
	}
	return addr, err
}
nextAddr returns the next WithdrawalAddress according to the input selection
rules: http://opentransactions.org/wiki/index.php/Input_Selection_Algorithm_(voting_pools)
It returns nil if the new address' seriesID is >= stopSeriesID.
package votingpool
import (
	"bytes"
	"fmt"
	"sort"
	"github.com/gcash/bchd/chaincfg"
	"github.com/gcash/bchd/txscript"
	"github.com/gcash/bchutil"
	"github.com/gcash/bchwallet/walletdb"
	"github.com/gcash/bchwallet/wtxmgr"
)
const eligibleInputMinConfirmations = 100
type Credit struct {
	wtxmgr.Credit
	addr WithdrawalAddress
}
func newCredit(c wtxmgr.Credit, addr WithdrawalAddress) Credit {
	return Credit{Credit: c, addr: addr}
}
func (c *Credit) String() string {
	return fmt.Sprintf("Credit of %v locked to %v", c.Amount, c.addr)
}
type byAddress []Credit
func (c byAddress) Len() int      { return len(c) }
func (c byAddress) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c byAddress) Less(i, j int) bool {
	iAddr := c[i].addr
	jAddr := c[j].addr
	if iAddr.seriesID < jAddr.seriesID {
		return true
	}
	if iAddr.seriesID > jAddr.seriesID {
		return false
	}
	if iAddr.index < jAddr.index {
		return true
	}
	if iAddr.index > jAddr.index {
		return false
	}
	if iAddr.branch < jAddr.branch {
		return true
	}
	if iAddr.branch > jAddr.branch {
		return false
	}
	txidComparison := bytes.Compare(c[i].OutPoint.Hash[:], c[j].OutPoint.Hash[:])
	if txidComparison < 0 {
		return true
	}
	if txidComparison > 0 {
		return false
	}
	return c[i].OutPoint.Index < c[j].OutPoint.Index
}
func (p *Pool) getEligibleInputs(ns, addrmgrNs walletdb.ReadBucket, store *wtxmgr.Store, txmgrNs walletdb.ReadBucket, startAddress WithdrawalAddress,
	lastSeriesID uint32, dustThreshold bchutil.Amount, chainHeight int32,
	minConf int) ([]Credit, error) {
	if p.Series(lastSeriesID) == nil {
		str := fmt.Sprintf("lastSeriesID (%d) does not exist", lastSeriesID)
		return nil, newError(ErrSeriesNotExists, str, nil)
	}
	unspents, err := store.UnspentOutputs(txmgrNs)
	if err != nil {
		return nil, newError(ErrInputSelection, "failed to get unspent outputs", err)
	}
	addrMap, err := groupCreditsByAddr(unspents, p.manager.ChainParams())
	if err != nil {
		return nil, err
	}
	var inputs []Credit
	address := startAddress
	for {
		log.Debugf("Looking for eligible inputs at address %v", address.addrIdentifier())
		if candidates, ok := addrMap[address.addr.EncodeAddress()]; ok {
			var eligibles []Credit
			for _, c := range candidates {
				candidate := newCredit(c, address)
				if p.isCreditEligible(candidate, minConf, chainHeight, dustThreshold) {
					eligibles = append(eligibles, candidate)
				}
			}
			inputs = append(inputs, eligibles...)
		}
		nAddr, err := nextAddr(p, ns, addrmgrNs, address.seriesID, address.branch, address.index, lastSeriesID+1)
		if err != nil {
			return nil, newError(ErrInputSelection, "failed to get next withdrawal address", err)
		} else if nAddr == nil {
			log.Debugf("getEligibleInputs: reached last addr, stopping")
			break
		}
		address = *nAddr
	}
	sort.Sort(sort.Reverse(byAddress(inputs)))
	return inputs, nil
}