// accountIsUsed checks if an account has ever been used by scanning the // first acctSeekWidth many addresses for usage. func (w *Wallet) accountIsUsed(account uint32, chainClient *chain.RPCClient) bool { // Search external branch then internal branch for a used // address. We need to set the address function to use based // on whether or not this is the initial sync. The function // AddressDerivedFromCointype is able to see addresses that // exists in accounts that have not yet been created, while // AddressDerivedFromDbAcct can not. addrFunc := w.Manager.AddressDerivedFromDbAcct if w.initiallyUnlocked { addrFunc = w.Manager.AddressDerivedFromCointype } for branch := uint32(0); branch < 2; branch++ { for i := uint32(0); i < acctSeekWidth; i++ { var addr dcrutil.Address err := walletdb.View(w.db, func(tx walletdb.ReadTx) error { addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey) var err error addr, err = addrFunc(addrmgrNs, i, account, branch) return err }) if err != nil { // Skip erroneous keys, which happen rarely. continue } exists, err := chainClient.ExistsAddress(addr) if err != nil { return false } if exists { return true } } } return false }
// debugAccountAddrGapsString is a debug function that prints a graphical outlook // of address usage to a string, from the perspective of the daemon. func debugAccountAddrGapsString(chainClient *chain.RPCClient, scanBackFrom uint32, account uint32, branch uint32, w *Wallet) (string, error) { var buf bytes.Buffer str := fmt.Sprintf("Begin debug address scan scanning backwards from "+ "idx %v, account %v, branch %v\n", scanBackFrom, account, branch) buf.WriteString(str) var firstUsedIndex uint32 for i := scanBackFrom; i > 0; i-- { var addr dcrutil.Address err := walletdb.View(w.db, func(tx walletdb.ReadTx) error { addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey) var err error addr, err = w.Manager.AddressDerivedFromDbAcct(addrmgrNs, i, account, branch) return err }) // Skip erroneous keys. if err != nil { continue } exists, err := chainClient.ExistsAddress(addr) if err != nil { return "", fmt.Errorf("failed to access chain server: %v", err) } if exists { firstUsedIndex = i break } } str = fmt.Sprintf("Last used index found: %v\n", firstUsedIndex) buf.WriteString(str) var batchSize uint32 = 50 batches := (firstUsedIndex / batchSize) + 1 var lastBatchSize uint32 if firstUsedIndex%batchSize != 0 { lastBatchSize = firstUsedIndex - ((batches - 1) * batchSize) } for i := uint32(0); i < batches; i++ { str = fmt.Sprintf("%8v", i*batchSize) buf.WriteString(str) start := i * batchSize end := (i + 1) * batchSize if i == batches-1 { // Nothing to do because last batch empty. if lastBatchSize == 0 { break } end = (i*batchSize + lastBatchSize) + 1 } for j := start; j < end; j++ { if j%10 == 0 { buf.WriteString(" ") } char := "_" var addr dcrutil.Address err := walletdb.View(w.db, func(tx walletdb.ReadTx) error { addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey) var err error addr, err = w.Manager.AddressDerivedFromDbAcct(addrmgrNs, j, account, branch) return err }) if err != nil { char = "X" } exists, err := chainClient.ExistsAddress(addr) if err != nil { return "", fmt.Errorf("failed to access chain server: %v", err) } if exists { char = "#" } buf.WriteString(char) } buf.WriteString("\n") } return buf.String(), nil }