github.com/decred/dcrlnd@v0.7.6/internal/testutils/embeddedwallet.go (about)

     1  package testutils
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"io/ioutil"
     7  	"net"
     8  	"os"
     9  	"time"
    10  
    11  	"decred.org/dcrwallet/v4/chain"
    12  	"decred.org/dcrwallet/v4/p2p"
    13  	"decred.org/dcrwallet/v4/spv"
    14  	wallet "decred.org/dcrwallet/v4/wallet"
    15  	"decred.org/dcrwallet/v4/wallet/udb"
    16  	"github.com/decred/dcrd/addrmgr/v2"
    17  	"github.com/decred/dcrd/chaincfg/chainhash"
    18  	"github.com/decred/dcrd/chaincfg/v3"
    19  	"github.com/decred/dcrd/rpcclient/v8"
    20  	"github.com/decred/dcrlnd/build"
    21  	walletloader "github.com/decred/dcrlnd/lnwallet/dcrwallet/loader"
    22  )
    23  
    24  var (
    25  	testHDSeed = chainhash.Hash{
    26  		0xb7, 0x94, 0x38, 0x5f, 0x2d, 0x1e, 0xf7, 0xab,
    27  		0x4d, 0x92, 0x73, 0xd1, 0x90, 0x63, 0x81, 0xb4,
    28  		0x4f, 0x2f, 0x6f, 0x25, 0x98, 0xa3, 0xef, 0xb9,
    29  		0x69, 0x49, 0x18, 0x83, 0x31, 0x98, 0x47, 0x53,
    30  	}
    31  )
    32  
    33  func init() {
    34  	wallet.UseLogger(build.NewSubLogger("DCRW", nil))
    35  	p2p.UseLogger(build.NewSubLogger("DCRW", nil))
    36  	spv.UseLogger(build.NewSubLogger("DCRW", nil))
    37  	chain.UseLogger(build.NewSubLogger("DCRW", nil))
    38  	udb.UseLogger(build.NewSubLogger("DCRW", nil))
    39  }
    40  
    41  // NewRPCSyncingTestWallet creates a test wallet that syncs itself using the
    42  // RPC connection mode.
    43  func NewRPCSyncingTestWallet(t TB, rpcConfig *rpcclient.ConnConfig) (*wallet.Wallet, func()) {
    44  	t.Helper()
    45  
    46  	tempDir, err := ioutil.TempDir("", "test-dcrw-rpc")
    47  	if err != nil {
    48  		t.Fatal(err)
    49  	}
    50  
    51  	defer func() {
    52  		if t.Failed() {
    53  			t.Logf("Wallet data at %s", tempDir)
    54  		}
    55  	}()
    56  
    57  	loader := walletloader.NewLoader(chaincfg.SimNetParams(), tempDir,
    58  		wallet.DefaultGapLimit)
    59  
    60  	pass := []byte("test")
    61  
    62  	birthday := time.Now().Add(-time.Hour * 24)
    63  	w, err := loader.CreateNewWallet(
    64  		context.Background(), pass, pass, testHDSeed[:], birthday,
    65  	)
    66  	if err != nil {
    67  		t.Fatal(err)
    68  	}
    69  
    70  	if err := w.Unlock(context.Background(), pass, nil); err != nil {
    71  		t.Fatal(err)
    72  	}
    73  
    74  	chainRpcOpts := chain.RPCOptions{
    75  		Address: rpcConfig.Host,
    76  		User:    rpcConfig.User,
    77  		Pass:    rpcConfig.Pass,
    78  		CA:      rpcConfig.Certificates,
    79  	}
    80  	syncer := chain.NewSyncer(w, &chainRpcOpts)
    81  	syncerCtx, cancel := context.WithCancel(context.Background())
    82  	initialSync := make(chan struct{})
    83  	syncer.SetCallbacks(&chain.Callbacks{
    84  		Synced: func(_ bool) {
    85  			select {
    86  			case <-initialSync:
    87  			default:
    88  				close(initialSync)
    89  			}
    90  		},
    91  	})
    92  	go syncer.Run(syncerCtx)
    93  
    94  	select {
    95  	case <-initialSync:
    96  	case <-time.After(60 * time.Second):
    97  		t.Fatal("timeout waiting for initial wallet sync")
    98  	}
    99  
   100  	cleanUp := func() {
   101  		cancel()
   102  		w.Lock()
   103  		if !t.Failed() {
   104  			os.RemoveAll(tempDir)
   105  		} else {
   106  			t.Logf("Wallet data at %s", tempDir)
   107  		}
   108  	}
   109  
   110  	return w, cleanUp
   111  }
   112  
   113  // NewSPVSyncingTestWallet creates a test wallet that syncs itself using the
   114  // SPV connection mode.
   115  func NewSPVSyncingTestWallet(t TB, p2pAddr string) (*wallet.Wallet, func()) {
   116  	t.Helper()
   117  
   118  	tempDir, err := ioutil.TempDir("", "test-dcrw-spv")
   119  	if err != nil {
   120  		t.Fatal(err)
   121  	}
   122  
   123  	defer func() {
   124  		if t.Failed() {
   125  			t.Logf("Wallet data at %s", tempDir)
   126  		}
   127  	}()
   128  
   129  	loader := walletloader.NewLoader(chaincfg.SimNetParams(), tempDir,
   130  		wallet.DefaultGapLimit)
   131  
   132  	pass := []byte("test")
   133  
   134  	birthday := time.Now().Add(-time.Hour * 24)
   135  	w, err := loader.CreateNewWallet(
   136  		context.Background(), pass, pass, testHDSeed[:], birthday,
   137  	)
   138  	if err != nil {
   139  		t.Fatal(err)
   140  	}
   141  
   142  	if err := w.Unlock(context.Background(), pass, nil); err != nil {
   143  		t.Fatal(err)
   144  	}
   145  
   146  	addr := &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 0}
   147  	amgrDir := tempDir
   148  	amgr := addrmgr.New(amgrDir, net.LookupIP)
   149  	lp := p2p.NewLocalPeer(w.ChainParams(), addr, amgr)
   150  	syncer := spv.NewSyncer(w, lp)
   151  	syncer.SetPersistentPeers([]string{p2pAddr})
   152  	syncedChan := make(chan struct{})
   153  	spvNtfns := &spv.Notifications{
   154  		Synced: func(isSynced bool) {
   155  			if isSynced {
   156  				select {
   157  				case <-syncedChan:
   158  				default:
   159  					close(syncedChan)
   160  				}
   161  			}
   162  		},
   163  	}
   164  	syncer.SetNotifications(spvNtfns)
   165  	w.SetNetworkBackend(syncer)
   166  	ctx, cancel := context.WithCancel(context.Background())
   167  	syncerChan := make(chan error, 1)
   168  	go func() { syncerChan <- syncer.Run(ctx) }()
   169  
   170  	// Wait until the initial sync completes.
   171  	select {
   172  	case <-syncedChan:
   173  	case err := <-syncerChan:
   174  		t.Fatalf("syncer.Run failed: %v", err)
   175  	case <-time.After(30 * time.Second):
   176  		t.Fatalf("timeout waiting for initial spv sync")
   177  	}
   178  
   179  	cleanUp := func() {
   180  		cancel()
   181  		select {
   182  		case err := <-syncerChan:
   183  			if err != nil && !errors.Is(err, context.Canceled) {
   184  				t.Logf("SPV syncer errored: %v", err)
   185  			}
   186  		case <-time.After(30 * time.Second):
   187  			t.Logf("Timeout waiting for SPV syncer to finish")
   188  		}
   189  		w.Lock()
   190  		if !t.Failed() {
   191  			os.RemoveAll(tempDir)
   192  		} else {
   193  			t.Logf("Wallet data at %s", tempDir)
   194  		}
   195  	}
   196  
   197  	return w, cleanUp
   198  }