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 }