consolidate: merge internal/external branches

This commit is contained in:
Roy Lee 2022-09-16 09:13:09 -07:00
parent de408d4133
commit 0410b7ce01
10 changed files with 132 additions and 321 deletions

View file

@ -31,26 +31,18 @@ type BlockFilterer struct {
// Params specifies the chain params of the current network.
Params *chaincfg.Params
// ExReverseFilter holds a reverse index mapping an external address to
// ReverseFilter holds a reverse index mapping an external address to
// the scoped index from which it was derived.
ExReverseFilter map[string]waddrmgr.ScopedIndex
// InReverseFilter holds a reverse index mapping an internal address to
// the scoped index from which it was derived.
InReverseFilter map[string]waddrmgr.ScopedIndex
ReverseFilter map[string]waddrmgr.ScopedIndex
// WathcedOutPoints is a global set of outpoints being tracked by the
// wallet. This allows the block filterer to check for spends from an
// outpoint we own.
WatchedOutPoints map[wire.OutPoint]btcutil.Address
// FoundExternal is a two-layer map recording the scope and index of
// FoundAddresses is a two-layer map recording the scope and index of
// external addresses found in a single block.
FoundExternal map[waddrmgr.KeyScope]map[uint32]struct{}
// FoundInternal is a two-layer map recording the scope and index of
// internal addresses found in a single block.
FoundInternal map[waddrmgr.KeyScope]map[uint32]struct{}
FoundAddresses map[waddrmgr.ScopedIndex]struct{}
// FoundOutPoints is a set of outpoints found in a single block whose
// address belongs to the wallet.
@ -71,31 +63,20 @@ func NewBlockFilterer(params *chaincfg.Params,
// Construct a reverse index by address string for the requested
// external addresses.
nExAddrs := len(req.ExternalAddrs)
exReverseFilter := make(map[string]waddrmgr.ScopedIndex, nExAddrs)
for scopedIndex, addr := range req.ExternalAddrs {
exReverseFilter[addr.EncodeAddress()] = scopedIndex
nAddrs := len(req.Addresses)
reverseFilter := make(map[string]waddrmgr.ScopedIndex, nAddrs)
for scopedIndex, addr := range req.Addresses {
reverseFilter[addr.EncodeAddress()] = scopedIndex
}
// Construct a reverse index by address string for the requested
// internal addresses.
nInAddrs := len(req.InternalAddrs)
inReverseFilter := make(map[string]waddrmgr.ScopedIndex, nInAddrs)
for scopedIndex, addr := range req.InternalAddrs {
inReverseFilter[addr.EncodeAddress()] = scopedIndex
}
foundExternal := make(map[waddrmgr.KeyScope]map[uint32]struct{})
foundInternal := make(map[waddrmgr.KeyScope]map[uint32]struct{})
foundAddresses := make(map[waddrmgr.ScopedIndex]struct{})
foundOutPoints := make(map[wire.OutPoint]btcutil.Address)
return &BlockFilterer{
Params: params,
ExReverseFilter: exReverseFilter,
InReverseFilter: inReverseFilter,
ReverseFilter: reverseFilter,
WatchedOutPoints: req.WatchedOutPoints,
FoundExternal: foundExternal,
FoundInternal: foundInternal,
FoundAddresses: foundAddresses,
FoundOutPoints: foundOutPoints,
}
}
@ -183,12 +164,8 @@ func (bf *BlockFilterer) FilterOutputAddrs(addrs []btcutil.Address) bool {
var isRelevant bool
for _, addr := range addrs {
addrStr := addr.EncodeAddress()
if scopedIndex, ok := bf.ExReverseFilter[addrStr]; ok {
bf.foundExternal(scopedIndex)
isRelevant = true
}
if scopedIndex, ok := bf.InReverseFilter[addrStr]; ok {
bf.foundInternal(scopedIndex)
if scopedIndex, ok := bf.ReverseFilter[addrStr]; ok {
bf.found(scopedIndex)
isRelevant = true
}
}
@ -196,22 +173,9 @@ func (bf *BlockFilterer) FilterOutputAddrs(addrs []btcutil.Address) bool {
return isRelevant
}
// foundExternal marks the scoped index as found within the block filterer's
// found marks the scoped index as found within the block filterer's
// FoundExternal map. If this the first index found for a particular scope, the
// scope's second layer map will be initialized before marking the index.
func (bf *BlockFilterer) foundExternal(scopedIndex waddrmgr.ScopedIndex) {
if _, ok := bf.FoundExternal[scopedIndex.Scope]; !ok {
bf.FoundExternal[scopedIndex.Scope] = make(map[uint32]struct{})
}
bf.FoundExternal[scopedIndex.Scope][scopedIndex.Index] = struct{}{}
}
// foundInternal marks the scoped index as found within the block filterer's
// FoundInternal map. If this the first index found for a particular scope, the
// scope's second layer map will be initialized before marking the index.
func (bf *BlockFilterer) foundInternal(scopedIndex waddrmgr.ScopedIndex) {
if _, ok := bf.FoundInternal[scopedIndex.Scope]; !ok {
bf.FoundInternal[scopedIndex.Scope] = make(map[uint32]struct{})
}
bf.FoundInternal[scopedIndex.Scope][scopedIndex.Index] = struct{}{}
func (bf *BlockFilterer) found(scopedIndex waddrmgr.ScopedIndex) {
bf.FoundAddresses[scopedIndex] = struct{}{}
}

View file

@ -75,8 +75,7 @@ type (
// is also included to monitor for spends.
FilterBlocksRequest struct {
Blocks []wtxmgr.BlockMeta
ExternalAddrs map[waddrmgr.ScopedIndex]btcutil.Address
InternalAddrs map[waddrmgr.ScopedIndex]btcutil.Address
Addresses map[waddrmgr.ScopedIndex]btcutil.Address
WatchedOutPoints map[wire.OutPoint]btcutil.Address
}
@ -90,8 +89,7 @@ type (
FilterBlocksResponse struct {
BatchIndex uint32
BlockMeta wtxmgr.BlockMeta
FoundExternalAddrs map[waddrmgr.KeyScope]map[uint32]struct{}
FoundInternalAddrs map[waddrmgr.KeyScope]map[uint32]struct{}
FoundAddresses map[waddrmgr.ScopedIndex]struct{}
FoundOutPoints map[wire.OutPoint]btcutil.Address
RelevantTxns []*wire.MsgTx
}

View file

@ -12,22 +12,12 @@ func buildFilterBlocksWatchList(req *FilterBlocksRequest) ([][]byte, error) {
// Construct a watch list containing the script addresses of all
// internal and external addresses that were requested, in addition to
// the set of outpoints currently being watched.
watchListSize := len(req.ExternalAddrs) +
len(req.InternalAddrs) +
watchListSize := len(req.Addresses) +
len(req.WatchedOutPoints)
watchList := make([][]byte, 0, watchListSize)
for _, addr := range req.ExternalAddrs {
p2shAddr, err := txscript.PayToAddrScript(addr)
if err != nil {
return nil, err
}
watchList = append(watchList, p2shAddr)
}
for _, addr := range req.InternalAddrs {
for _, addr := range req.Addresses {
p2shAddr, err := txscript.PayToAddrScript(addr)
if err != nil {
return nil, err

View file

@ -272,8 +272,7 @@ func (c *RPCClient) FilterBlocks(
resp := &FilterBlocksResponse{
BatchIndex: uint32(i),
BlockMeta: blk,
FoundExternalAddrs: blockFilterer.FoundExternal,
FoundInternalAddrs: blockFilterer.FoundInternal,
FoundAddresses: blockFilterer.FoundAddresses,
FoundOutPoints: blockFilterer.FoundOutPoints,
RelevantTxns: blockFilterer.RelevantTxns,
}

View file

@ -156,13 +156,8 @@ type accountInfo struct {
// The external branch is used for all addresses which are intended for
// external use.
nextExternalIndex uint32
lastExternalAddr ManagedAddress
// The internal branch is used for all adddresses which are only
// intended for internal wallet use such as change addresses.
nextInternalIndex uint32
lastInternalAddr ManagedAddress
nextIndex [2]uint32
lastAddr [2]ManagedAddress
// addrSchema serves as a way for an account to override its
// corresponding address schema with a custom one.

View file

@ -334,8 +334,8 @@ func testExternalAddresses(tc *testContext) bool {
err := walletdb.Update(tc.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
var err error
addrs, err = tc.manager.NextExternalAddresses(
ns, tc.internalAccount, 5,
addrs, err = tc.manager.NextAddresses(
ns, tc.internalAccount, ExternalBranch, 5,
)
return err
})
@ -371,8 +371,8 @@ func testExternalAddresses(tc *testContext) bool {
err := walletdb.View(tc.db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
var err error
lastAddr, err = tc.manager.LastExternalAddress(
ns, tc.internalAccount,
lastAddr, err = tc.manager.LastAddress(
ns, tc.internalAccount, ExternalBranch,
)
return err
})
@ -478,8 +478,8 @@ func testInternalAddresses(tc *testContext) bool {
err := walletdb.Update(tc.db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
var err error
addrs, err = tc.manager.NextInternalAddresses(
ns, tc.internalAccount, 5,
addrs, err = tc.manager.NextAddresses(
ns, tc.internalAccount, InternalBranch, 5,
)
return err
})
@ -515,8 +515,8 @@ func testInternalAddresses(tc *testContext) bool {
err := walletdb.View(tc.db, func(tx walletdb.ReadTx) error {
ns := tx.ReadBucket(waddrmgrNamespaceKey)
var err error
lastAddr, err = tc.manager.LastInternalAddress(
ns, tc.internalAccount,
lastAddr, err = tc.manager.LastAddress(
ns, tc.internalAccount, InternalBranch,
)
return err
})
@ -2032,8 +2032,8 @@ func TestScopedKeyManagerManagement(t *testing.T) {
t.Fatalf("unable to fetch scope %v: %v", scope, err)
}
externalAddr, err := sMgr.NextExternalAddresses(
ns, DefaultAccountNum, 1,
externalAddr, err := sMgr.NextAddresses(
ns, DefaultAccountNum, ExternalBranch, 1,
)
if err != nil {
t.Fatalf("unable to derive external addr: %v", err)
@ -2047,8 +2047,8 @@ func TestScopedKeyManagerManagement(t *testing.T) {
ScopeAddrMap[scope].ExternalAddrType)
}
internalAddr, err := sMgr.NextInternalAddresses(
ns, DefaultAccountNum, 1,
internalAddr, err := sMgr.NextAddresses(
ns, DefaultAccountNum, InternalBranch, 1,
)
if err != nil {
t.Fatalf("unable to derive internal addr: %v", err)
@ -2106,15 +2106,15 @@ func TestScopedKeyManagerManagement(t *testing.T) {
// We'll now create a new external address to ensure we
// retrieve the proper type.
externalAddr, err = scopedMgr.NextExternalAddresses(
ns, DefaultAccountNum, 1,
externalAddr, err = scopedMgr.NextAddresses(
ns, DefaultAccountNum, ExternalBranch, 1,
)
if err != nil {
t.Fatalf("unable to derive external addr: %v", err)
}
internalAddr, err = scopedMgr.NextInternalAddresses(
ns, DefaultAccountNum, 1,
internalAddr, err = scopedMgr.NextAddresses(
ns, DefaultAccountNum, InternalBranch, 1,
)
if err != nil {
t.Fatalf("unable to derive internal addr: %v", err)
@ -2177,8 +2177,8 @@ func TestScopedKeyManagerManagement(t *testing.T) {
err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
lastAddr, err = scopedMgr.LastExternalAddress(
ns, DefaultAccountNum,
lastAddr, err = scopedMgr.LastAddress(
ns, DefaultAccountNum, ExternalBranch,
)
if err != nil {
return err
@ -2384,8 +2384,8 @@ func testNewRawAccount(t *testing.T, _ *Manager, db walletdb.DB,
err := walletdb.Update(db, func(tx walletdb.ReadWriteTx) error {
ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
addrs, err := scopedMgr.NextExternalAddresses(
ns, accountNum, 1,
addrs, err := scopedMgr.NextAddresses(
ns, accountNum, ExternalBranch, 1,
)
if err != nil {
return err

View file

@ -404,8 +404,10 @@ func (s *ScopedKeyManager) loadAccountInfo(ns walletdb.ReadBucket,
acctName: row.name,
acctType: row.acctType,
acctKeyEncrypted: row.privKeyEncrypted,
nextExternalIndex: row.nextExternalIndex,
nextInternalIndex: row.nextInternalIndex,
nextIndex: [2]uint32{
row.nextExternalIndex,
row.nextInternalIndex,
},
}
// Use the crypto public key to decrypt the account public
@ -437,49 +439,30 @@ func (s *ScopedKeyManager) loadAccountInfo(ns walletdb.ReadBucket,
return nil, managerError(ErrDatabase, str, nil)
}
// Derive and cache the managed address for the last external address.
branch, index := ExternalBranch, acctInfo.nextExternalIndex
if index > 0 {
index--
}
lastExtAddrPath := DerivationPath{
InternalAccount: account,
Account: acctInfo.acctKeyPub.ChildIndex(),
Branch: branch,
Index: index,
MasterKeyFingerprint: acctInfo.masterKeyFingerprint,
}
lastExtKey, err := s.deriveKey(acctInfo, branch, index, hasPrivateKey)
if err != nil {
return nil, err
}
lastExtAddr, err := s.keyToManaged(lastExtKey, lastExtAddrPath, acctInfo)
if err != nil {
return nil, err
}
acctInfo.lastExternalAddr = lastExtAddr
for branch := 0; branch < 2; branch++ {
// Derive and cache the managed address for the last internal address.
branch, index = InternalBranch, acctInfo.nextInternalIndex
// Derive and cache the managed address for the last external address.
index := acctInfo.nextIndex[branch]
if index > 0 {
index--
}
lastIntAddrPath := DerivationPath{
lastAddrPath := DerivationPath{
InternalAccount: account,
Account: acctInfo.acctKeyPub.ChildIndex(),
Branch: branch,
Branch: uint32(branch),
Index: index,
MasterKeyFingerprint: acctInfo.masterKeyFingerprint,
}
lastIntKey, err := s.deriveKey(acctInfo, branch, index, hasPrivateKey)
lastKey, err := s.deriveKey(acctInfo, uint32(branch), index, hasPrivateKey)
if err != nil {
return nil, err
}
lastIntAddr, err := s.keyToManaged(lastIntKey, lastIntAddrPath, acctInfo)
lastAddr, err := s.keyToManaged(lastKey, lastAddrPath, acctInfo)
if err != nil {
return nil, err
}
acctInfo.lastInternalAddr = lastIntAddr
acctInfo.lastAddr[branch] = lastAddr
}
// Add it to the cache and return it when everything is successful.
s.acctInfo[account] = acctInfo
@ -516,8 +499,8 @@ func (s *ScopedKeyManager) AccountProperties(ns walletdb.ReadBucket,
return nil, err
}
props.AccountName = acctInfo.acctName
props.ExternalKeyCount = acctInfo.nextExternalIndex
props.InternalKeyCount = acctInfo.nextInternalIndex
props.ExternalKeyCount = acctInfo.nextIndex[ExternalBranch]
props.InternalKeyCount = acctInfo.nextIndex[InternalBranch]
props.AccountPubKey = acctInfo.acctKeyPub
props.MasterKeyFingerprint = acctInfo.masterKeyFingerprint
props.AddrSchema = acctInfo.addrSchema
@ -938,7 +921,7 @@ func (s *ScopedKeyManager) accountAddrType(acctInfo *accountInfo,
//
// This function MUST be called with the manager lock held for writes.
func (s *ScopedKeyManager) nextAddresses(ns walletdb.ReadWriteBucket,
account uint32, numAddresses uint32, internal bool) ([]ManagedAddress, error) {
account uint32, branch uint32, numAddresses uint32) ([]ManagedAddress, error) {
// The next address can only be generated for accounts that have
// already been created.
@ -956,16 +939,12 @@ func (s *ScopedKeyManager) nextAddresses(ns walletdb.ReadWriteBucket,
// Choose the branch key and index depending on whether or not this is
// an internal address.
branchNum, nextIndex := ExternalBranch, acctInfo.nextExternalIndex
if internal {
branchNum = InternalBranch
nextIndex = acctInfo.nextInternalIndex
}
nextIndex := acctInfo.nextIndex[branch]
// Choose the appropriate type of address to derive since it's possible
// for a watch-only account to have a different schema from the
// manager's.
addrType := s.accountAddrType(acctInfo, internal)
addrType := s.accountAddrType(acctInfo, branch == InternalBranch)
// Ensure the requested number of addresses doesn't exceed the maximum
// allowed for this account.
@ -978,10 +957,9 @@ func (s *ScopedKeyManager) nextAddresses(ns walletdb.ReadWriteBucket,
}
// Derive the appropriate branch key and ensure it is zeroed when done.
branchKey, err := acctKey.Derive(branchNum)
branchKey, err := acctKey.Derive(branch)
if err != nil {
str := fmt.Sprintf("failed to derive extended key branch %d",
branchNum)
str := fmt.Sprintf("failed to derive extended key branch %d", branch)
return nil, managerError(ErrKeyChain, str, err)
}
defer branchKey.Zero() // Ensure branch key is zeroed when done.
@ -1021,7 +999,7 @@ func (s *ScopedKeyManager) nextAddresses(ns walletdb.ReadWriteBucket,
derivationPath := DerivationPath{
InternalAccount: account,
Account: acctKey.ChildIndex(),
Branch: branchNum,
Branch: branch,
Index: nextIndex - 1,
}
@ -1035,15 +1013,13 @@ func (s *ScopedKeyManager) nextAddresses(ns walletdb.ReadWriteBucket,
if err != nil {
return nil, err
}
if internal {
addr.internal = true
}
addr.internal = branch == InternalBranch
managedAddr := addr
nextKey.Zero()
info := unlockDeriveInfo{
managedAddr: managedAddr,
branch: branchNum,
branch: branch,
index: nextIndex - 1,
}
addressInfo = append(addressInfo, &info)
@ -1113,13 +1089,8 @@ func (s *ScopedKeyManager) nextAddresses(ns walletdb.ReadWriteBucket,
// Set the last address and next address for tracking.
ma := addressInfo[len(addressInfo)-1].managedAddr
if internal {
acctInfo.nextInternalIndex = nextIndex
acctInfo.lastInternalAddr = ma
} else {
acctInfo.nextExternalIndex = nextIndex
acctInfo.lastExternalAddr = ma
}
acctInfo.nextIndex[branch] = nextIndex
acctInfo.lastAddr[branch] = ma
}
ns.Tx().OnCommit(onCommit)
@ -1152,16 +1123,12 @@ func (s *ScopedKeyManager) extendAddresses(ns walletdb.ReadWriteBucket,
// Choose the branch key and index depending on whether or not this is
// an internal address.
branchNum, nextIndex := ExternalBranch, acctInfo.nextExternalIndex
if internal {
branchNum = InternalBranch
nextIndex = acctInfo.nextInternalIndex
}
nextIndex := acctInfo.nextIndex[branch]
// Choose the appropriate type of address to derive since it's possible
// for a watch-only account to have a different schema from the
// manager's.
addrType := s.accountAddrType(acctInfo, internal)
addrType := s.accountAddrType(acctInfo, branch == InternalBranch)
// If the last index requested is already lower than the next index, we
// can return early.
@ -1179,10 +1146,10 @@ func (s *ScopedKeyManager) extendAddresses(ns walletdb.ReadWriteBucket,
}
// Derive the appropriate branch key and ensure it is zeroed when done.
branchKey, err := acctKey.Derive(branchNum)
branchKey, err := acctKey.Derive(branch)
if err != nil {
str := fmt.Sprintf("failed to derive extended key branch %d",
branchNum)
branch)
return managerError(ErrKeyChain, str, err)
}
defer branchKey.Zero() // Ensure branch key is zeroed when done.
@ -1224,7 +1191,7 @@ func (s *ScopedKeyManager) extendAddresses(ns walletdb.ReadWriteBucket,
derivationPath := DerivationPath{
InternalAccount: account,
Account: acctInfo.acctKeyPub.ChildIndex(),
Branch: branchNum,
Branch: branch,
Index: nextIndex - 1,
}
@ -1238,15 +1205,13 @@ func (s *ScopedKeyManager) extendAddresses(ns walletdb.ReadWriteBucket,
if err != nil {
return err
}
if internal {
addr.internal = true
}
addr.internal = branch == InternalBranch
managedAddr := addr
nextKey.Zero()
info := unlockDeriveInfo{
managedAddr: managedAddr,
branch: branchNum,
branch: branch,
index: nextIndex - 1,
}
addressInfo = append(addressInfo, &info)
@ -1302,21 +1267,16 @@ func (s *ScopedKeyManager) extendAddresses(ns walletdb.ReadWriteBucket,
// Set the last address and next address for tracking.
ma := addressInfo[len(addressInfo)-1].managedAddr
if internal {
acctInfo.nextInternalIndex = nextIndex
acctInfo.lastInternalAddr = ma
} else {
acctInfo.nextExternalIndex = nextIndex
acctInfo.lastExternalAddr = ma
}
acctInfo.nextIndex[branch] = nextIndex
acctInfo.lastAddr[branch] = ma
return nil
}
// NextExternalAddresses returns the specified number of next chained addresses
// NextAddresses returns the specified number of next chained addresses
// that are intended for external use from the address manager.
func (s *ScopedKeyManager) NextExternalAddresses(ns walletdb.ReadWriteBucket,
account uint32, numAddresses uint32) ([]ManagedAddress, error) {
func (s *ScopedKeyManager) NextAddresses(ns walletdb.ReadWriteBucket,
account uint32, branch uint32, numAddresses uint32) ([]ManagedAddress, error) {
// Enforce maximum account number.
if account > MaxAccountNum {
@ -1327,32 +1287,15 @@ func (s *ScopedKeyManager) NextExternalAddresses(ns walletdb.ReadWriteBucket,
s.mtx.Lock()
defer s.mtx.Unlock()
return s.nextAddresses(ns, account, numAddresses, false)
}
// NextInternalAddresses returns the specified number of next chained addresses
// that are intended for internal use such as change from the address manager.
func (s *ScopedKeyManager) NextInternalAddresses(ns walletdb.ReadWriteBucket,
account uint32, numAddresses uint32) ([]ManagedAddress, error) {
// Enforce maximum account number.
if account > MaxAccountNum {
err := managerError(ErrAccountNumTooHigh, errAcctTooHigh, nil)
return nil, err
}
s.mtx.Lock()
defer s.mtx.Unlock()
return s.nextAddresses(ns, account, numAddresses, true)
return s.nextAddresses(ns, account, branch, numAddresses)
}
// ExtendExternalAddresses ensures that all valid external keys through
// lastIndex are derived and stored in the wallet. This is used to ensure that
// wallet's persistent state catches up to a external child that was found
// during recovery.
func (s *ScopedKeyManager) ExtendExternalAddresses(ns walletdb.ReadWriteBucket,
account uint32, lastIndex uint32) error {
func (s *ScopedKeyManager) ExtendAddresses(ns walletdb.ReadWriteBucket,
account uint32, branch uint32, lastIndex uint32) error {
if account > MaxAccountNum {
err := managerError(ErrAccountNumTooHigh, errAcctTooHigh, nil)
@ -1362,28 +1305,10 @@ func (s *ScopedKeyManager) ExtendExternalAddresses(ns walletdb.ReadWriteBucket,
s.mtx.Lock()
defer s.mtx.Unlock()
return s.extendAddresses(ns, account, lastIndex, false)
return s.extendAddresses(ns, account, branch, lastIndex)
}
// ExtendInternalAddresses ensures that all valid internal keys through
// lastIndex are derived and stored in the wallet. This is used to ensure that
// wallet's persistent state catches up to an internal child that was found
// during recovery.
func (s *ScopedKeyManager) ExtendInternalAddresses(ns walletdb.ReadWriteBucket,
account uint32, lastIndex uint32) error {
if account > MaxAccountNum {
err := managerError(ErrAccountNumTooHigh, errAcctTooHigh, nil)
return err
}
s.mtx.Lock()
defer s.mtx.Unlock()
return s.extendAddresses(ns, account, lastIndex, true)
}
// LastExternalAddress returns the most recently requested chained external
// LastAddress returns the most recently requested chained external
// address from calling NextExternalAddress for the given account. The first
// external address for the account will be returned if none have been
// previously requested.
@ -1391,8 +1316,8 @@ func (s *ScopedKeyManager) ExtendInternalAddresses(ns walletdb.ReadWriteBucket,
// This function will return an error if the provided account number is greater
// than the MaxAccountNum constant or there is no account information for the
// passed account. Any other errors returned are generally unexpected.
func (s *ScopedKeyManager) LastExternalAddress(ns walletdb.ReadBucket,
account uint32) (ManagedAddress, error) {
func (s *ScopedKeyManager) LastAddress(ns walletdb.ReadBucket,
account, branch uint32) (ManagedAddress, error) {
// Enforce maximum account number.
if account > MaxAccountNum {
@ -1410,47 +1335,13 @@ func (s *ScopedKeyManager) LastExternalAddress(ns walletdb.ReadBucket,
return nil, err
}
if acctInfo.nextExternalIndex > 0 {
return acctInfo.lastExternalAddr, nil
if acctInfo.nextIndex[branch] > 0 {
return acctInfo.lastAddr[branch], nil
}
return nil, managerError(ErrAddressNotFound, "no previous external address", nil)
}
// LastInternalAddress returns the most recently requested chained internal
// address from calling NextInternalAddress for the given account. The first
// internal address for the account will be returned if none have been
// previously requested.
//
// This function will return an error if the provided account number is greater
// than the MaxAccountNum constant or there is no account information for the
// passed account. Any other errors returned are generally unexpected.
func (s *ScopedKeyManager) LastInternalAddress(ns walletdb.ReadBucket,
account uint32) (ManagedAddress, error) {
// Enforce maximum account number.
if account > MaxAccountNum {
err := managerError(ErrAccountNumTooHigh, errAcctTooHigh, nil)
return nil, err
}
s.mtx.Lock()
defer s.mtx.Unlock()
// Load account information for the passed account. It is typically
// cached, but if not it will be loaded from the database.
acctInfo, err := s.loadAccountInfo(ns, account)
if err != nil {
return nil, err
}
if acctInfo.nextInternalIndex > 0 {
return acctInfo.lastInternalAddr, nil
}
return nil, managerError(ErrAddressNotFound, "no previous internal address", nil)
}
// NewRawAccount creates a new account for the scoped manager. This method
// differs from the NewAccount method in that this method takes the account
// number *directly*, rather than taking a string name for the account, then

View file

@ -326,14 +326,14 @@ func (w *Wallet) ImportAccountDryRun(name string,
// attempt, we'll want to invalidate the cache for it.
defer manager.InvalidateAccountCache(accountProps.AccountNumber)
externalAddrs, err = manager.NextExternalAddresses(
ns, accountProps.AccountNumber, numAddrs,
externalAddrs, err = manager.NextAddresses(
ns, accountProps.AccountNumber, waddrmgr.ExternalBranch, numAddrs,
)
if err != nil {
return err
}
internalAddrs, err = manager.NextInternalAddresses(
ns, accountProps.AccountNumber, numAddrs,
internalAddrs, err = manager.NextAddresses(
ns, accountProps.AccountNumber, waddrmgr.InternalBranch, numAddrs,
)
if err != nil {
return err

View file

@ -261,11 +261,7 @@ func (rs *RecoveryState) AddWatchedOutPoint(outPoint *wire.OutPoint,
type ScopeRecoveryState struct {
// ExternalBranch is the recovery state of addresses generated for
// external use, i.e. receiving addresses.
ExternalBranch *BranchRecoveryState
// InternalBranch is the recovery state of addresses generated for
// internal use, i.e. change addresses.
InternalBranch *BranchRecoveryState
AccountBranches [][2]*BranchRecoveryState
}
// NewScopeRecoveryState initializes an ScopeRecoveryState with the chosen

View file

@ -954,22 +954,12 @@ func expandScopeHorizons(ns walletdb.ReadWriteBucket,
return nil
}
// externalKeyPath returns the relative external derivation path /0/0/index.
func externalKeyPath(index uint32) waddrmgr.DerivationPath {
// keyPath returns the relative external derivation path /account/branch/index.
func keyPath(account, branch, index uint32) waddrmgr.DerivationPath {
return waddrmgr.DerivationPath{
InternalAccount: waddrmgr.DefaultAccountNum,
Account: waddrmgr.DefaultAccountNum,
Branch: waddrmgr.ExternalBranch,
Index: index,
}
}
// internalKeyPath returns the relative internal derivation path /0/1/index.
func internalKeyPath(index uint32) waddrmgr.DerivationPath {
return waddrmgr.DerivationPath{
InternalAccount: waddrmgr.DefaultAccountNum,
Account: waddrmgr.DefaultAccountNum,
Branch: waddrmgr.InternalBranch,
InternalAccount: account,
Account: account,
Branch: branch,
Index: index,
}
}
@ -982,8 +972,7 @@ func newFilterBlocksRequest(batch []wtxmgr.BlockMeta,
filterReq := &chain.FilterBlocksRequest{
Blocks: batch,
ExternalAddrs: make(map[waddrmgr.ScopedIndex]btcutil.Address),
InternalAddrs: make(map[waddrmgr.ScopedIndex]btcutil.Address),
Addresses: make(map[waddrmgr.ScopedIndex]btcutil.Address),
WatchedOutPoints: recoveryState.WatchedOutPoints(),
}
@ -1112,23 +1101,12 @@ func logFilterBlocksResp(block wtxmgr.BlockMeta,
resp *chain.FilterBlocksResponse) {
// Log the number of external addresses found in this block.
var nFoundExternal int
for _, indexes := range resp.FoundExternalAddrs {
nFoundExternal += len(indexes)
}
if nFoundExternal > 0 {
log.Infof("Recovered %d external addrs at height=%d hash=%v",
nFoundExternal, block.Height, block.Hash)
}
var nFoundAddresses int
nFoundAddresses += len(resp.FoundAddresses)
// Log the number of internal addresses found in this block.
var nFoundInternal int
for _, indexes := range resp.FoundInternalAddrs {
nFoundInternal += len(indexes)
}
if nFoundInternal > 0 {
log.Infof("Recovered %d internal addrs at height=%d hash=%v",
nFoundInternal, block.Height, block.Hash)
if nFoundAddresses > 0 {
log.Infof("Recovered %d addrs at height=%d hash=%v",
nFoundAddresses, block.Height, block.Hash)
}
// Log the number of outpoints found in this block.
@ -1568,7 +1546,7 @@ func (w *Wallet) CurrentAddress(account uint32, scope waddrmgr.KeyScope) (btcuti
)
err = walletdb.Update(w.db, func(tx walletdb.ReadWriteTx) error {
addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey)
maddr, err := manager.LastExternalAddress(addrmgrNs, account)
maddr, err := manager.LastAddress(addrmgrNs, account, waddrmgr.ExternalBranch)
if err != nil {
// If no address exists yet, create the first external
// address.
@ -2954,7 +2932,7 @@ func (w *Wallet) newAddress(addrmgrNs walletdb.ReadWriteBucket, account uint32,
}
// Get next address from wallet.
addrs, err := manager.NextExternalAddresses(addrmgrNs, account, 1)
addrs, err := manager.NextAddresses(addrmgrNs, account, waddrmgr.ExternalBranch, 1)
if err != nil {
return nil, nil, err
}
@ -3012,7 +2990,7 @@ func (w *Wallet) newChangeAddress(addrmgrNs walletdb.ReadWriteBucket,
}
// Get next chained change address from wallet for account.
addrs, err := manager.NextInternalAddresses(addrmgrNs, account, 1)
addrs, err := manager.NextAddresses(addrmgrNs, account, waddrmgr.InternalBranch, 1)
if err != nil {
return nil, err
}