Skip to content

Commit

Permalink
dcr: Make addresses returns more useable.
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeGruffins committed Jan 2, 2025
1 parent c890cb2 commit 570e70e
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 47 deletions.
89 changes: 51 additions & 38 deletions asset/dcr/addresses.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,68 +10,81 @@ import (
)

// AddressesByAccount handles a getaddressesbyaccount request by returning
// all addresses for an account, or an error if the requested account does
// not exist. Does not include the current address that can be retrieved with
// w.mainWallet.CurrentAddress.
func (w *Wallet) AddressesByAccount(ctx context.Context, account string) ([]string, error) {
// external addresses for an account, or an error if the requested account does
// not exist. Returns used and unused addresses up to nUsed and nUnused. No
// unused addresses are returned if nUnused is zero. All used addresses are
// returned if nUsed is zero. index is the first unused index.
func (w *Wallet) AddressesByAccount(ctx context.Context, account string, nUsed, nUnused uint32) (used, unused []string, index uint32, err error) {
if account == "imported" {
addrs, err := w.mainWallet.ImportedAddresses(ctx, account)
if err != nil {
return nil, err
return nil, nil, 0, err
}
addrStrs := make([]string, len(addrs))
addrStrs := make([]string, 0, len(addrs))
for i := range addrs {
addrStrs[i] = addrs[i].String()
if nUsed != 0 && uint32(i) >= nUsed {
break
}
addrStrs = append(addrStrs, addrs[i].String())
}
return addrStrs, nil
return addrStrs, nil, 0, nil
}
accountNum, err := w.mainWallet.AccountNumber(ctx, account)
if err != nil {
return nil, err
return nil, nil, 0, err
}
xpub, err := w.mainWallet.AccountXpub(ctx, accountNum)
if err != nil {
return nil, err
return nil, nil, 0, err
}
extBranch, err := xpub.Child(0)
if err != nil {
return nil, err
}
intBranch, err := xpub.Child(1)
if err != nil {
return nil, err
return nil, nil, 0, err
}
endExt, endInt, err := w.mainWallet.BIP0044BranchNextIndexes(ctx, accountNum)
// It looks like this can never be zero, so a new wallet will always
// have a used address.
endExt, _, err := w.mainWallet.BIP0044BranchNextIndexes(ctx, accountNum)
if err != nil {
return nil, err
return nil, nil, 0, err
}
params := w.mainWallet.ChainParams()
addrs := make([]string, 0, endExt+endInt)
appendAddrs := func(branchKey *hdkeychain.ExtendedKey, n uint32) error {
for i := uint32(0); i < n; i++ {
child, err := branchKey.Child(i)
if errors.Is(err, hdkeychain.ErrInvalidChild) {
continue
}
if err != nil {
return err
}
pkh := dcrutil.Hash160(child.SerializedPubKey())
addr, _ := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(
pkh, params)
addrs = append(addrs, addr.String())
var totalUsed, totalUnused uint32
if nUsed != 0 && endExt >= nUsed {
totalUsed = nUsed
} else if endExt > 0 {
// The returned index is unused.
totalUsed = endExt
}
if nUnused != 0 && endExt+nUnused < hdkeychain.HardenedKeyStart {
totalUnused = nUnused
}
appendAddr := func(addrs *[]string, i uint32) error {
child, err := extBranch.Child(i)
if errors.Is(err, hdkeychain.ErrInvalidChild) {
return nil
}
if err != nil {
return err
}
pkh := dcrutil.Hash160(child.SerializedPubKey())
addr, _ := stdaddr.NewAddressPubKeyHashEcdsaSecp256k1V0(
pkh, params)
*addrs = append(*addrs, addr.String())
return nil
}
err = appendAddrs(extBranch, endExt)
if err != nil {
return nil, err
used = make([]string, 0, totalUsed)
for i := uint32(0); i < totalUsed; i++ {
if err := appendAddr(&used, endExt-1-i); err != nil {
return nil, nil, 0, err
}
}
err = appendAddrs(intBranch, endInt)
if err != nil {
return nil, err
unused = make([]string, 0, totalUnused)
for i := uint32(0); i < totalUnused; i++ {
if err := appendAddr(&unused, endExt+i); err != nil {
return nil, nil, 0, err
}
}
return addrs, nil
return used, unused, endExt, nil
}

// AccountPubkey returns an account's extended pubkey encoded for the network.
Expand Down
30 changes: 21 additions & 9 deletions cgo/addresses.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import "C"
import (
"encoding/base64"
"encoding/json"
"strconv"

dcrwallet "decred.org/dcrwallet/v4/wallet"
"decred.org/dcrwallet/v4/wallet/udb"
Expand Down Expand Up @@ -131,28 +132,39 @@ func verifyMessage(cName, cMessage, cAddress, cSig *C.char) *C.char {
}

//export addresses
func addresses(cName *C.char) *C.char {
func addresses(cName, cNUsed, cNUnused *C.char) *C.char {
w, ok := loadedWallet(cName)
if !ok {
return errCResponse("wallet with name %q is not loaded", goString(cName))
}

addrs, err := w.AddressesByAccount(w.ctx, defaultAccount)
nUsed, err := strconv.ParseUint(goString(cNUsed), 10, 32)
if err != nil {
return errCResponse("number of used addresses is not a uint32: %v", err)
}

nUnused, err := strconv.ParseUint(goString(cNUnused), 10, 32)
if err != nil {
return errCResponse("number of unused addresses is not a uint32: %v", err)
}

used, unused, index, err := w.AddressesByAccount(w.ctx, defaultAccount, uint32(nUsed), uint32(nUnused))
if err != nil {
return errCResponse("w.AddressesByAccount error: %v", err)
}

// w.AddressesByAccount does not include the current address.
res := &AddressesRes{
Used: used,
Unused: []string{},
Index: index,
}
// Avoid returning unused addresses if we are not synced.
synced, _ := w.IsSynced(w.ctx)
if synced {
addr, err := w.CurrentAddress(udb.DefaultAccountNum)
if err != nil {
return errCResponse("w.CurrentAddress error: %v", err)
}
addrs = append(addrs, addr.String())
res.Unused = unused
}

b, err := json.Marshal(addrs)
b, err := json.Marshal(res)
if err != nil {
return errCResponse("unable to marshal addresses: %v", err)
}
Expand Down
6 changes: 6 additions & 0 deletions cgo/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,9 @@ type BirthdayState struct {
SetFromHeight bool `json:"setfromheight"`
SetFromTime bool `json:"setfromtime"`
}

type AddressesRes struct {
Used []string `json:"used"`
Unused []string `json:"unused"`
Index uint32 `json:"index"`
}

0 comments on commit 570e70e

Please sign in to comment.