decred.org/dcrwallet/v3@v3.1.0/wallet/discovery_test.go (about)

     1  // Copyright (c) 2020 The Decred developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package wallet
     6  
     7  import (
     8  	"context"
     9  	"testing"
    10  
    11  	"decred.org/dcrwallet/v3/wallet/walletdb"
    12  )
    13  
    14  // TestDiscoveryCursorPos tests that the account cursor index is not reset
    15  // during address discovery such that an address could be reused.
    16  func TestDiscoveryCursorPos(t *testing.T) {
    17  	ctx := context.Background()
    18  
    19  	cfg := basicWalletConfig
    20  	// normally would just do the upgrade, but the buffers record
    21  	// off-by-ones after the upgrade.  will be fixed in a later commit.
    22  	cfg.DisableCoinTypeUpgrades = true
    23  
    24  	w, teardown := testWallet(ctx, t, &cfg)
    25  	defer teardown()
    26  
    27  	/*
    28  		// Upgrade the cointype before proceeding.  The test is invalid if a
    29  		// cointype upgrade occurs during discovery.
    30  		err := w.UpgradeToSLIP0044CoinType(ctx)
    31  		if err != nil {
    32  			t.Fatal(err)
    33  		}
    34  	*/
    35  
    36  	// Advance the cursor within the gap limit but without recording the
    37  	// returned addresses in the database (these may be persisted during a
    38  	// later update).
    39  	w.addressBuffersMu.Lock()
    40  	xpub := w.addressBuffers[0].albExternal.branchXpub
    41  	w.addressBuffers[0].albExternal.cursor = 9 // 0-9 have been returned
    42  	w.addressBuffersMu.Unlock()
    43  
    44  	// Perform address discovery
    45  	// All peer funcs may be left unimplemented; wallet only records the genesis block.
    46  	peer := &peerFuncs{}
    47  	err := w.DiscoverActiveAddresses(ctx, peer, &w.chainParams.GenesisHash, false, w.GapLimit())
    48  	if err != nil {
    49  		t.Fatal(err)
    50  	}
    51  
    52  	w.addressBuffersMu.Lock()
    53  	lastUsed := w.addressBuffers[0].albExternal.lastUsed
    54  	cursor := w.addressBuffers[0].albExternal.cursor
    55  	w.addressBuffersMu.Unlock()
    56  	wasLastUsed := ^uint32(0)
    57  	wasCursor := uint32(9)
    58  	if lastUsed != wasLastUsed || cursor != wasCursor {
    59  		t.Errorf("cursor was reset: lastUsed=%d (want %d) cursor=%d (want %d)",
    60  			lastUsed, wasLastUsed, cursor, wasCursor)
    61  	}
    62  
    63  	// Manually mark an address between the lastUsed and cursor as used, and
    64  	// addresses through the cursor as returned, then perform discovery
    65  	// again.  The cursor should be reduced such that the next returned
    66  	// address would be the same as before, without introducing a backwards
    67  	// reset or wasted addresses.
    68  	addr4, err := deriveChildAddress(xpub, 4, w.chainParams)
    69  	if err != nil {
    70  		t.Fatal(err)
    71  	}
    72  	err = walletdb.Update(ctx, w.db, func(dbtx walletdb.ReadWriteTx) error {
    73  		ns := dbtx.ReadBucket(waddrmgrNamespaceKey)
    74  		err = w.manager.MarkReturnedChildIndex(dbtx, 0, 0, 9) // 0-9 have been returned
    75  		if err != nil {
    76  			return err
    77  		}
    78  		maddr4, err := w.manager.Address(ns, addr4)
    79  		if err != nil {
    80  			return err
    81  		}
    82  		return w.markUsedAddress("", dbtx, maddr4)
    83  	})
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  	err = w.DiscoverActiveAddresses(ctx, peer, &w.chainParams.GenesisHash, false, w.GapLimit())
    88  	if err != nil {
    89  		t.Fatal(err)
    90  	}
    91  
    92  	w.addressBuffersMu.Lock()
    93  	lastUsed = w.addressBuffers[0].albExternal.lastUsed
    94  	cursor = w.addressBuffers[0].albExternal.cursor
    95  	w.addressBuffersMu.Unlock()
    96  	wasLastUsed += 5
    97  	wasCursor -= 5
    98  	if lastUsed != wasLastUsed || cursor != wasCursor {
    99  		t.Errorf("cursor was reset: lastUsed=%d (want %d) cursor=%d (want %d)",
   100  			lastUsed, wasLastUsed, cursor, wasCursor)
   101  	}
   102  }