events.go raw

   1  package gui
   2  
   3  import (
   4  	"encoding/json"
   5  	"io/ioutil"
   6  	"time"
   7  
   8  	"github.com/p9c/p9/pkg/amt"
   9  	"github.com/p9c/p9/pkg/chainrpc/p2padvt"
  10  	"github.com/p9c/p9/pkg/transport"
  11  	"github.com/p9c/p9/pkg/wire"
  12  
  13  	"github.com/p9c/p9/pkg/btcjson"
  14  	"github.com/p9c/p9/pkg/chainhash"
  15  	"github.com/p9c/p9/pkg/rpcclient"
  16  	"github.com/p9c/p9/pkg/util"
  17  )
  18  
  19  func (wg *WalletGUI) WalletAndClientRunning() bool {
  20  	running := wg.wallet.Running() && wg.WalletClient != nil && !wg.WalletClient.Disconnected()
  21  	// D.Ln("wallet and wallet rpc client are running?", running)
  22  	return running
  23  }
  24  
  25  func (wg *WalletGUI) Advertise() (e error) {
  26  	if wg.node.Running() && wg.cx.Config.Discovery.True() {
  27  		// I.Ln("sending out p2p advertisment")
  28  		if e = wg.multiConn.SendMany(
  29  			p2padvt.Magic,
  30  			transport.GetShards(p2padvt.Get(uint64(wg.cx.Config.UUID.V()), (wg.cx.Config.P2PListeners.S())[0])),
  31  		); E.Chk(e) {
  32  		}
  33  	}
  34  	return
  35  }
  36  
  37  // func (wg *WalletGUI) Tickers() {
  38  // 	first := true
  39  // 	D.Ln("updating best block")
  40  // 	var e error
  41  // 	var height int32
  42  // 	var h *chainhash.Hash
  43  // 	if h, height, e = wg.ChainClient.GetBestBlock(); E.Chk(e) {
  44  // 		// interrupt.Request()
  45  // 		return
  46  // 	}
  47  // 	D.Ln(h, height)
  48  // 	wg.State.SetBestBlockHeight(height)
  49  // 	wg.State.SetBestBlockHash(h)
  50  // 	go func() {
  51  // 		var e error
  52  // 		seconds := time.Tick(time.Second * 3)
  53  // 		fiveSeconds := time.Tick(time.Second * 5)
  54  // 	totalOut:
  55  // 		for {
  56  // 		preconnect:
  57  // 			for {
  58  // 				select {
  59  // 				case <-seconds:
  60  // 					D.Ln("preconnect loop")
  61  // 					if e = wg.Advertise(); D.Chk(e) {
  62  // 					}
  63  // 					if wg.ChainClient != nil {
  64  // 						wg.ChainClient.Disconnect()
  65  // 						wg.ChainClient.Shutdown()
  66  // 						wg.ChainClient = nil
  67  // 					}
  68  // 					if wg.WalletClient != nil {
  69  // 						wg.WalletClient.Disconnect()
  70  // 						wg.WalletClient.Shutdown()
  71  // 						wg.WalletClient = nil
  72  // 					}
  73  // 					if !wg.node.Running() {
  74  // 						break
  75  // 					}
  76  // 					break preconnect
  77  // 				case <-fiveSeconds:
  78  // 					continue
  79  // 				case <-wg.quit.Wait():
  80  // 					break totalOut
  81  // 				}
  82  // 			}
  83  // 		out:
  84  // 			for {
  85  // 				select {
  86  // 				case <-seconds:
  87  // 					if e = wg.Advertise(); D.Chk(e) {
  88  // 					}
  89  // 					if !wg.cx.IsCurrent() {
  90  // 						continue
  91  // 					} else {
  92  // 						wg.cx.Syncing.Store(false)
  93  // 					}
  94  // 					D.Ln("---------------------- ready", wg.ready.Load())
  95  // 					D.Ln("---------------------- WalletAndClientRunning", wg.WalletAndClientRunning())
  96  // 					D.Ln("---------------------- stateLoaded", wg.stateLoaded.Load())
  97  // 					wg.node.Start()
  98  // 					if e = wg.writeWalletCookie(); E.Chk(e) {
  99  // 					}
 100  // 					wg.wallet.Start()
 101  // 					D.Ln("connecting to chain")
 102  // 					if e = wg.chainClient(); E.Chk(e) {
 103  // 						break
 104  // 					}
 105  // 					if wg.wallet.Running() { // && wg.WalletClient == nil {
 106  // 						D.Ln("connecting to wallet")
 107  // 						if e = wg.walletClient(); E.Chk(e) {
 108  // 							break
 109  // 						}
 110  // 					}
 111  // 					if !wg.node.Running() {
 112  // 						D.Ln("breaking out node not running")
 113  // 						break out
 114  // 					}
 115  // 					if wg.ChainClient == nil {
 116  // 						D.Ln("breaking out chainclient is nil")
 117  // 						break out
 118  // 					}
 119  // 					// if  wg.WalletClient == nil {
 120  // 					// 	D.Ln("breaking out walletclient is nil")
 121  // 					// 	break out
 122  // 					// }
 123  // 					if wg.ChainClient.Disconnected() {
 124  // 						D.Ln("breaking out chainclient disconnected")
 125  // 						break out
 126  // 					}
 127  // 					// if wg.WalletClient.Disconnected() {
 128  // 					// 	D.Ln("breaking out walletclient disconnected")
 129  // 					// 	break out
 130  // 					// }
 131  // 					// var e error
 132  // 					if first {
 133  // 						wg.updateChainBlock()
 134  // 						wg.invalidate <- struct{}{}
 135  // 					}
 136  //
 137  // 					if wg.WalletAndClientRunning() {
 138  // 						if first {
 139  // 							wg.processWalletBlockNotification()
 140  // 						}
 141  // 						// if wg.stateLoaded.Load() { // || wg.currentReceiveGetNew.Load() {
 142  // 						// 	wg.ReceiveAddressbook = func(gtx l.Context) l.Dimensions {
 143  // 						// 		var widgets []l.Widget
 144  // 						// 		widgets = append(widgets, wg.ReceivePage.GetAddressbookHistoryCards("DocBg")...)
 145  // 						// 		le := func(gtx l.Context, index int) l.Dimensions {
 146  // 						// 			return widgets[index](gtx)
 147  // 						// 		}
 148  // 						// 		return wg.Flex().Rigid(
 149  // 						// 			wg.lists["receiveAddresses"].Length(len(widgets)).Vertical().
 150  // 						// 				ListElement(le).Fn,
 151  // 						// 		).Fn(gtx)
 152  // 						// 	}
 153  // 						// }
 154  // 						if wg.stateLoaded.Load() && !wg.State.IsReceivingAddress() { // || wg.currentReceiveGetNew.Load() {
 155  // 							wg.GetNewReceivingAddress()
 156  // 							if wg.currentReceiveQRCode == nil || wg.currentReceiveRegenerate.Load() { // || wg.currentReceiveGetNew.Load() {
 157  // 								wg.GetNewReceivingQRCode(wg.ReceivePage.urn)
 158  // 							}
 159  // 						}
 160  // 					}
 161  // 					wg.invalidate <- struct{}{}
 162  // 					first = false
 163  // 				case <-fiveSeconds:
 164  // 				case <-wg.quit.Wait():
 165  // 					break totalOut
 166  // 				}
 167  // 			}
 168  // 		}
 169  // 	}()
 170  // }
 171  
 172  func (wg *WalletGUI) updateThingies() (e error) {
 173  	// update the configuration
 174  	var b []byte
 175  	if b, e = ioutil.ReadFile(wg.cx.Config.ConfigFile.V()); !E.Chk(e) {
 176  		if e = json.Unmarshal(b, wg.cx.Config); !E.Chk(e) {
 177  			return
 178  		}
 179  	}
 180  	return
 181  }
 182  func (wg *WalletGUI) updateChainBlock() {
 183  	D.Ln("processChainBlockNotification")
 184  	var e error
 185  	if wg.ChainClient != nil && wg.ChainClient.Disconnected() || wg.ChainClient.Disconnected() {
 186  		D.Ln("connecting ChainClient")
 187  		if e = wg.chainClient(); E.Chk(e) {
 188  			return
 189  		}
 190  	}
 191  	var h *chainhash.Hash
 192  	var height int32
 193  	D.Ln("updating best block")
 194  	if h, height, e = wg.ChainClient.GetBestBlock(); E.Chk(e) {
 195  		// interrupt.Request()
 196  		return
 197  	}
 198  	D.Ln(h, height)
 199  	wg.State.SetBestBlockHeight(height)
 200  	wg.State.SetBestBlockHash(h)
 201  }
 202  
 203  func (wg *WalletGUI) processChainBlockNotification(hash *chainhash.Hash, height int32, t time.Time) {
 204  	D.Ln("processChainBlockNotification")
 205  	wg.State.SetBestBlockHeight(height)
 206  	wg.State.SetBestBlockHash(hash)
 207  	// if wg.WalletAndClientRunning() {
 208  	// 	wg.processWalletBlockNotification()
 209  	// }
 210  }
 211  
 212  func (wg *WalletGUI) processWalletBlockNotification() bool {
 213  	D.Ln("processWalletBlockNotification")
 214  	if !wg.WalletAndClientRunning() {
 215  		D.Ln("wallet and client not running")
 216  		return false
 217  	}
 218  	// check account balance
 219  	var unconfirmed amt.Amount
 220  	var e error
 221  	if unconfirmed, e = wg.WalletClient.GetUnconfirmedBalance("default"); E.Chk(e) {
 222  		return false
 223  	}
 224  	wg.State.SetBalanceUnconfirmed(unconfirmed.ToDUO())
 225  	var confirmed amt.Amount
 226  	if confirmed, e = wg.WalletClient.GetBalance("default"); E.Chk(e) {
 227  		return false
 228  	}
 229  	wg.State.SetBalance(confirmed.ToDUO())
 230  	var atr []btcjson.ListTransactionsResult
 231  	// str := wg.State.allTxs.Load()
 232  	if atr, e = wg.WalletClient.ListTransactionsCount("default", 2<<32); E.Chk(e) {
 233  		return false
 234  	}
 235  	// D.Ln(len(atr))
 236  	// wg.State.SetAllTxs(append(str, atr...))
 237  	wg.State.SetAllTxs(atr)
 238  	wg.txMx.Lock()
 239  	wg.txHistoryList = wg.State.filteredTxs.Load()
 240  	atrl := 10
 241  	if len(atr) < atrl {
 242  		atrl = len(atr)
 243  	}
 244  	wg.txMx.Unlock()
 245  	wg.RecentTransactions(10, "recent")
 246  	wg.RecentTransactions(-1, "history")
 247  	return true
 248  }
 249  
 250  func (wg *WalletGUI) forceUpdateChain() {
 251  	wg.updateChainBlock()
 252  	var e error
 253  	var height int32
 254  	var tip *chainhash.Hash
 255  	if tip, height, e = wg.ChainClient.GetBestBlock(); E.Chk(e) {
 256  		return
 257  	}
 258  	var block *wire.Block
 259  	if block, e = wg.ChainClient.GetBlock(tip); E.Chk(e) {
 260  	}
 261  	t := block.Header.Timestamp
 262  	wg.processChainBlockNotification(tip, height, t)
 263  }
 264  
 265  func (wg *WalletGUI) ChainNotifications() *rpcclient.NotificationHandlers {
 266  	return &rpcclient.NotificationHandlers{
 267  		// OnClientConnected: func() {
 268  		// 	// go func() {
 269  		// 	D.Ln("(((NOTIFICATION))) CHAIN CLIENT CONNECTED!")
 270  		// 	wg.cx.Syncing.Store(true)
 271  		// 	wg.forceUpdateChain()
 272  		// 	wg.processWalletBlockNotification()
 273  		// 	wg.RecentTransactions(10, "recent")
 274  		// 	wg.RecentTransactions(-1, "history")
 275  		// 	wg.invalidate <- struct{}{}
 276  		// 	wg.cx.Syncing.Store(false)
 277  		// },
 278  		// OnBlockConnected: func(hash *chainhash.Hash, height int32, t time.Time) {
 279  		// 	if wg.cx.Syncing.Load() {
 280  		// 		return
 281  		// 	}
 282  		// 	D.Ln("(((NOTIFICATION))) chain OnBlockConnected", hash, height, t)
 283  		// 	wg.processChainBlockNotification(hash, height, t)
 284  		// 	// wg.processWalletBlockNotification()
 285  		// 	// todo: send system notification of new block, set configuration to disable also
 286  		// 	// if wg.WalletAndClientRunning() {
 287  		// 	// 	var e error
 288  		// 	// 	if _, e = wg.WalletClient.RescanBlocks([]chainhash.Hash{*hash}); E.Chk(e) {
 289  		// 	// 	}
 290  		// 	// }
 291  		// 	wg.RecentTransactions(10, "recent")
 292  		// 	wg.RecentTransactions(-1, "history")
 293  		// 	wg.invalidate <- struct{}{}
 294  		// },
 295  		OnFilteredBlockConnected: func(height int32, header *wire.BlockHeader, txs []*util.Tx) {
 296  			nbh := header.BlockHash()
 297  			wg.processChainBlockNotification(&nbh, height, header.Timestamp)
 298  			// if time.Now().Sub(time.Unix(wg.lastUpdated.Load(), 0)) < time.Second {
 299  			// 	return
 300  			// }
 301  			wg.lastUpdated.Store(time.Now().Unix())
 302  			hash := header.BlockHash()
 303  			D.Ln(
 304  				"(((NOTIFICATION))) OnFilteredBlockConnected hash", hash, "POW hash:",
 305  				header.BlockHashWithAlgos(height), "height", height,
 306  			)
 307  			// D.S(txs)
 308  			if wg.processWalletBlockNotification() {
 309  			}
 310  			// filename := filepath.Join(*wg.cx.Config.DataDir, "state.json")
 311  			// if e := wg.State.Save(filename, wg.cx.Config.WalletPass); E.Chk(e) {
 312  			// }
 313  			// if wg.WalletAndClientRunning() {
 314  			// 	var e error
 315  			// 	if _, e = wg.WalletClient.RescanBlocks([]chainhash.Hash{hash}); E.Chk(e) {
 316  			// 	}
 317  			// }
 318  			wg.RecentTransactions(10, "recent")
 319  			wg.RecentTransactions(-1, "history")
 320  			wg.invalidate <- struct{}{}
 321  		},
 322  		// OnBlockDisconnected: func(hash *chainhash.Hash, height int32, t time.Time) {
 323  		// 	if wg.cx.Syncing.Load() {
 324  		// 		return
 325  		// 	}
 326  		// 	D.Ln("(((NOTIFICATION))) OnBlockDisconnected", hash, height, t)
 327  		// 	wg.forceUpdateChain()
 328  		// 	if wg.processWalletBlockNotification() {
 329  		// 	}
 330  		// 	wg.RecentTransactions(10, "recent")
 331  		// 	wg.RecentTransactions(-1, "history")
 332  		// 	wg.invalidate <- struct{}{}
 333  		// },
 334  		// OnFilteredBlockDisconnected: func(height int32, header *wire.BlockHeader) {
 335  		// 	if wg.cx.Syncing.Load() {
 336  		// 		return
 337  		// 	}
 338  		// 	D.Ln("(((NOTIFICATION))) OnFilteredBlockDisconnected", height, header)
 339  		// 	wg.forceUpdateChain()
 340  		// 	if wg.processWalletBlockNotification() {
 341  		// 	}
 342  		// 	wg.RecentTransactions(10, "recent")
 343  		// 	wg.RecentTransactions(-1, "history")
 344  		// 	wg.invalidate <- struct{}{}
 345  		// },
 346  		// OnRecvTx: func(transaction *util.Tx, details *btcjson.BlockDetails) {
 347  		// 	if wg.cx.Syncing.Load() {
 348  		// 		return
 349  		// 	}
 350  		// 	D.Ln("(((NOTIFICATION))) OnRecvTx", transaction, details)
 351  		// 	wg.forceUpdateChain()
 352  		// 	if wg.processWalletBlockNotification() {
 353  		// 	}
 354  		// 	wg.RecentTransactions(10, "recent")
 355  		// 	wg.RecentTransactions(-1, "history")
 356  		// 	wg.invalidate <- struct{}{}
 357  		// },
 358  		// OnRedeemingTx: func(transaction *util.Tx, details *btcjson.BlockDetails) {
 359  		// 	if wg.cx.Syncing.Load() {
 360  		// 		return
 361  		// 	}
 362  		// 	D.Ln("(((NOTIFICATION))) OnRedeemingTx", transaction, details)
 363  		// 	wg.forceUpdateChain()
 364  		// 	if wg.processWalletBlockNotification() {
 365  		// 	}
 366  		// 	wg.RecentTransactions(10, "recent")
 367  		// 	wg.RecentTransactions(-1, "history")
 368  		// 	wg.invalidate <- struct{}{}
 369  		// },
 370  		// OnRelevantTxAccepted: func(transaction []byte) {
 371  		// 	if wg.cx.Syncing.Load() {
 372  		// 		return
 373  		// 	}
 374  		// 	D.Ln("(((NOTIFICATION))) OnRelevantTxAccepted", transaction)
 375  		// 	wg.forceUpdateChain()
 376  		// 	if wg.processWalletBlockNotification() {
 377  		// 	}
 378  		// 	wg.RecentTransactions(10, "recent")
 379  		// 	wg.RecentTransactions(-1, "history")
 380  		// 	wg.invalidate <- struct{}{}
 381  		// },
 382  		// OnRescanFinished: func(hash *chainhash.Hash, height int32, blkTime time.Time) {
 383  		// 	if wg.cx.Syncing.Load() {
 384  		// 		return
 385  		// 	}
 386  		// 	D.Ln("(((NOTIFICATION))) OnRescanFinished", hash, height, blkTime)
 387  		// 	wg.processChainBlockNotification(hash, height, blkTime)
 388  		// 	// update best block height
 389  		// 	// wg.processWalletBlockNotification()
 390  		// 	// stop showing syncing indicator
 391  		// 	if wg.processWalletBlockNotification() {
 392  		// 	}
 393  		// 	wg.RecentTransactions(10, "recent")
 394  		// 	wg.RecentTransactions(-1, "history")
 395  		// 	wg.invalidate <- struct{}{}
 396  		// },
 397  		// OnRescanProgress: func(hash *chainhash.Hash, height int32, blkTime time.Time) {
 398  		// 	D.Ln("(((NOTIFICATION))) OnRescanProgress", hash, height, blkTime)
 399  		// 	// update best block height
 400  		// 	// wg.processWalletBlockNotification()
 401  		// 	// set to show syncing indicator
 402  		// 	if wg.processWalletBlockNotification() {
 403  		// 	}
 404  		// 	wg.Syncing.Store(true)
 405  		// 	wg.RecentTransactions(10, "recent")
 406  		// 	wg.RecentTransactions(-1, "history")
 407  		// 	wg.invalidate <- struct{}{}
 408  		// },
 409  		OnTxAccepted: func(hash *chainhash.Hash, amount amt.Amount) {
 410  			// if wg.syncing.Load() {
 411  			// 	D.Ln("OnTxAccepted but we are syncing")
 412  			// 	return
 413  			// }
 414  			D.Ln("(((NOTIFICATION))) OnTxAccepted")
 415  			D.Ln(hash, amount)
 416  			// if wg.processWalletBlockNotification() {
 417  			// }
 418  			wg.RecentTransactions(10, "recent")
 419  			wg.RecentTransactions(-1, "history")
 420  			wg.invalidate <- struct{}{}
 421  		},
 422  		// OnTxAcceptedVerbose: func(txDetails *btcjson.TxRawResult) {
 423  		// 	if wg.cx.Syncing.Load() {
 424  		// 		return
 425  		// 	}
 426  		// 	D.Ln("(((NOTIFICATION))) OnTxAcceptedVerbose")
 427  		// 	D.S(txDetails)
 428  		// 	if wg.processWalletBlockNotification() {
 429  		// 	}
 430  		// 	wg.RecentTransactions(10, "recent")
 431  		// 	wg.RecentTransactions(-1, "history")
 432  		// 	wg.invalidate <- struct{}{}
 433  		// },
 434  		// OnPodConnected: func(connected bool) {
 435  		// 	if wg.cx.Syncing.Load() {
 436  		// 		return
 437  		// 	}
 438  		// 	D.Ln("(((NOTIFICATION))) OnPodConnected", connected)
 439  		// 	wg.forceUpdateChain()
 440  		// 	if wg.processWalletBlockNotification() {
 441  		// 	}
 442  		// 	wg.RecentTransactions(10, "recent")
 443  		// 	wg.RecentTransactions(-1, "history")
 444  		// 	wg.invalidate <- struct{}{}
 445  		// },
 446  		// OnAccountBalance: func(account string, balance util.Amount, confirmed bool) {
 447  		// 	if wg.cx.Syncing.Load() {
 448  		// 		return
 449  		// 	}
 450  		// 	D.Ln("OnAccountBalance")
 451  		// 	// what does this actually do
 452  		// 	D.Ln(account, balance, confirmed)
 453  		// },
 454  		// OnWalletLockState: func(locked bool) {
 455  		// 	if wg.cx.Syncing.Load() {
 456  		// 		return
 457  		// 	}
 458  		// 	D.Ln("OnWalletLockState", locked)
 459  		// 	// switch interface to unlock page
 460  		// 	wg.forceUpdateChain()
 461  		// 	if wg.processWalletBlockNotification() {
 462  		// 	}
 463  		// 	// TODO: lock when idle... how to get trigger for idleness in UI?
 464  		// },
 465  		// OnUnknownNotification: func(method string, params []json.RawMessage) {
 466  		// 	if wg.cx.Syncing.Load() {
 467  		// 		return
 468  		// 	}
 469  		// 	D.Ln("(((NOTIFICATION))) OnUnknownNotification", method, params)
 470  		// 	wg.forceUpdateChain()
 471  		// 	if wg.processWalletBlockNotification() {
 472  		// 	}
 473  		// },
 474  	}
 475  	
 476  }
 477  
 478  func (wg *WalletGUI) WalletNotifications() *rpcclient.NotificationHandlers {
 479  	// if !wg.wallet.Running() || wg.WalletClient == nil || wg.WalletClient.Disconnected() {
 480  	// 	return nil
 481  	// }
 482  	// var updating bool
 483  	return &rpcclient.NotificationHandlers{
 484  		// OnClientConnected: func() {
 485  		// 	if wg.cx.Syncing.Load() {
 486  		// 		return
 487  		// 	}
 488  		// 	if updating {
 489  		// 		return
 490  		// 	}
 491  		// 	D.Ln("(((NOTIFICATION))) wallet client connected, running initial processes")
 492  		// 	for !wg.processWalletBlockNotification() {
 493  		// 		time.Sleep(time.Second)
 494  		// 		D.Ln("(((NOTIFICATION))) retry attempting to update wallet transactions")
 495  		// 	}
 496  		// 	filename := filepath.Join(wg.cx.DataDir, "state.json")
 497  		// 	if e := wg.State.Save(filename, wg.cx.Config.WalletPass); E.Chk(e) {
 498  		// 	}
 499  		// 	wg.invalidate <- struct{}{}
 500  		// 	updating = false
 501  		// },
 502  		// OnBlockConnected: func(hash *chainhash.Hash, height int32, t time.Time) {
 503  		// 	if wg.Syncing.Load() {
 504  		// 		return
 505  		// 	}
 506  		// 	D.Ln("(((NOTIFICATION))) wallet OnBlockConnected", hash, height, t)
 507  		// 	wg.processWalletBlockNotification()
 508  		// 	filename := filepath.Join(wg.cx.DataDir, "state.json")
 509  		// 	if e := wg.State.Save(filename, wg.cx.Config.WalletPass); E.Chk(e) {
 510  		// 	}
 511  		// 	wg.invalidate <- struct{}{}
 512  		// },
 513  		// OnFilteredBlockConnected: func(height int32, header *wire.BlockHeader, txs []*util.Tx) {
 514  		// 	if wg.Syncing.Load() {
 515  		// 		return
 516  		// 	}
 517  		// 	D.Ln(
 518  		// 		"(((NOTIFICATION))) wallet OnFilteredBlockConnected hash", header.BlockHash(), "POW hash:",
 519  		// 		header.BlockHashWithAlgos(height), "height", height,
 520  		// 	)
 521  		// 	// D.S(txs)
 522  		// 	nbh := header.BlockHash()
 523  		// 	wg.processChainBlockNotification(&nbh, height, header.Timestamp)
 524  		// 	if wg.processWalletBlockNotification() {
 525  		// 	}
 526  		// 	filename := filepath.Join(wg.cx.DataDir, "state.json")
 527  		// 	if e := wg.State.Save(filename, wg.cx.Config.WalletPass); E.Chk(e) {
 528  		// 	}
 529  		// 	wg.invalidate <- struct{}{}
 530  		// },
 531  		// OnBlockDisconnected: func(hash *chainhash.Hash, height int32, t time.Time) {
 532  		// 	if wg.Syncing.Load() {
 533  		// 		return
 534  		// 	}
 535  		// 	D.Ln("(((NOTIFICATION))) OnBlockDisconnected", hash, height, t)
 536  		// 	wg.forceUpdateChain()
 537  		// 	if wg.processWalletBlockNotification() {
 538  		// 	}
 539  		// },
 540  		// OnFilteredBlockDisconnected: func(height int32, header *wire.BlockHeader) {
 541  		// 	if wg.Syncing.Load() {
 542  		// 		return
 543  		// 	}
 544  		// 	D.Ln("(((NOTIFICATION))) OnFilteredBlockDisconnected", height, header)
 545  		// 	wg.forceUpdateChain()
 546  		// 	if wg.processWalletBlockNotification() {
 547  		// 	}
 548  		// },
 549  		// OnRecvTx: func(transaction *util.Tx, details *btcjson.BlockDetails) {
 550  		// 	if wg.cx.Syncing.Load() {
 551  		// 		return
 552  		// 	}
 553  		// 	D.Ln("(((NOTIFICATION))) OnRecvTx", transaction, details)
 554  		// 	wg.forceUpdateChain()
 555  		// 	if wg.processWalletBlockNotification() {
 556  		// 	}
 557  		// },
 558  		// OnRedeemingTx: func(transaction *util.Tx, details *btcjson.BlockDetails) {
 559  		// 	if wg.cx.Syncing.Load() {
 560  		// 		return
 561  		// 	}
 562  		// 	D.Ln("(((NOTIFICATION))) OnRedeemingTx", transaction, details)
 563  		// 	wg.forceUpdateChain()
 564  		// 	if wg.processWalletBlockNotification() {
 565  		// 	}
 566  		// },
 567  		// OnRelevantTxAccepted: func(transaction []byte) {
 568  		// 	if wg.cx.Syncing.Load() {
 569  		// 		return
 570  		// 	}
 571  		// 	D.Ln("(((NOTIFICATION))) OnRelevantTxAccepted", transaction)
 572  		// 	wg.forceUpdateChain()
 573  		// 	if wg.processWalletBlockNotification() {
 574  		// 	}
 575  		// },
 576  		// OnRescanFinished: func(hash *chainhash.Hash, height int32, blkTime time.Time) {
 577  		// 	if wg.cx.Syncing.Load() {
 578  		// 		return
 579  		// 	}
 580  		// 	D.Ln("(((NOTIFICATION))) OnRescanFinished", hash, height, blkTime)
 581  		// 	wg.processChainBlockNotification(hash, height, blkTime)
 582  		// 	// update best block height
 583  		// 	// wg.processWalletBlockNotification()
 584  		// 	// stop showing syncing indicator
 585  		// 	if wg.processWalletBlockNotification() {
 586  		// 	}
 587  		// 	wg.cx.Syncing.Store(false)
 588  		// 	wg.invalidate <- struct{}{}
 589  		// },
 590  		// OnRescanProgress: func(hash *chainhash.Hash, height int32, blkTime time.Time) {
 591  		// 	D.Ln("(((NOTIFICATION))) OnRescanProgress", hash, height, blkTime)
 592  		// 	// // update best block height
 593  		// 	// // wg.processWalletBlockNotification()
 594  		// 	// // set to show syncing indicator
 595  		// 	// if wg.processWalletBlockNotification() {
 596  		// 	// }
 597  		// 	// wg.Syncing.Store(true)
 598  		// 	wg.invalidate <- struct{}{}
 599  		// },
 600  		// OnTxAccepted: func(hash *chainhash.Hash, amount util.Amount) {
 601  		// 	if wg.cx.Syncing.Load() {
 602  		// 		return
 603  		// 	}
 604  		// 	D.Ln("(((NOTIFICATION))) OnTxAccepted")
 605  		// 	D.Ln(hash, amount)
 606  		// 	if wg.processWalletBlockNotification() {
 607  		// 	}
 608  		// },
 609  		// OnTxAcceptedVerbose: func(txDetails *btcjson.TxRawResult) {
 610  		// 	if wg.cx.Syncing.Load() {
 611  		// 		return
 612  		// 	}
 613  		// 	D.Ln("(((NOTIFICATION))) OnTxAcceptedVerbose")
 614  		// 	D.S(txDetails)
 615  		// 	if wg.processWalletBlockNotification() {
 616  		// 	}
 617  		// },
 618  		// OnPodConnected: func(connected bool) {
 619  		// 	D.Ln("(((NOTIFICATION))) OnPodConnected", connected)
 620  		// 	wg.forceUpdateChain()
 621  		// 	if wg.processWalletBlockNotification() {
 622  		// 	}
 623  		// },
 624  		// OnAccountBalance: func(account string, balance util.Amount, confirmed bool) {
 625  		// 	D.Ln("OnAccountBalance")
 626  		// 	// what does this actually do
 627  		// 	D.Ln(account, balance, confirmed)
 628  		// },
 629  		// OnWalletLockState: func(locked bool) {
 630  		// 	D.Ln("OnWalletLockState", locked)
 631  		// 	// switch interface to unlock page
 632  		// 	wg.forceUpdateChain()
 633  		// 	if wg.processWalletBlockNotification() {
 634  		// 	}
 635  		// 	// TODO: lock when idle... how to get trigger for idleness in UI?
 636  		// },
 637  		// OnUnknownNotification: func(method string, params []json.RawMessage) {
 638  		// 	D.Ln("(((NOTIFICATION))) OnUnknownNotification", method, params)
 639  		// 	wg.forceUpdateChain()
 640  		// 	if wg.processWalletBlockNotification() {
 641  		// 	}
 642  		// },
 643  	}
 644  	
 645  }
 646  
 647  func (wg *WalletGUI) chainClient() (e error) {
 648  	D.Ln("starting up chain client")
 649  	if wg.cx.Config.NodeOff.True() {
 650  		W.Ln("node is disabled")
 651  		return nil
 652  	}
 653  	if wg.ChainClient == nil { // || wg.ChainClient.Disconnected() {
 654  		D.Ln(wg.cx.Config.RPCConnect.V())
 655  		// wg.ChainMutex.Lock()
 656  		// defer wg.ChainMutex.Unlock()
 657  		// I.S(wg.certs)
 658  		if wg.ChainClient, e = rpcclient.New(
 659  			&rpcclient.ConnConfig{
 660  				Host:                 wg.cx.Config.RPCConnect.V(),
 661  				Endpoint:             "ws",
 662  				User:                 wg.cx.Config.Username.V(),
 663  				Pass:                 wg.cx.Config.Password.V(),
 664  				TLS:                  wg.cx.Config.ClientTLS.True(),
 665  				Certificates:         wg.certs,
 666  				DisableAutoReconnect: false,
 667  				DisableConnectOnNew:  false,
 668  			}, wg.ChainNotifications(), wg.cx.KillAll,
 669  		); E.Chk(e) {
 670  			return
 671  		}
 672  	}
 673  	if wg.ChainClient.Disconnected() {
 674  		D.Ln("connecting chain client")
 675  		if e = wg.ChainClient.Connect(1); E.Chk(e) {
 676  			return
 677  		}
 678  	}
 679  	if e = wg.ChainClient.NotifyBlocks(); !E.Chk(e) {
 680  		D.Ln("subscribed to new blocks")
 681  		// wg.WalletNotifications()
 682  		wg.invalidate <- struct{}{}
 683  	}
 684  	return
 685  }
 686  
 687  func (wg *WalletGUI) walletClient() (e error) {
 688  	D.Ln("connecting to wallet")
 689  	if wg.cx.Config.WalletOff.True() {
 690  		W.Ln("wallet is disabled")
 691  		return nil
 692  	}
 693  	// walletRPC := (*wg.cx.Config.WalletRPCListeners)[0]
 694  	// certs := wg.cx.Config.ReadCAFile()
 695  	// I.Ln("config.tls", wg.cx.Config.ClientTLS.True())
 696  	wg.WalletMutex.Lock()
 697  	if wg.WalletClient, e = rpcclient.New(
 698  		&rpcclient.ConnConfig{
 699  			Host:                 wg.cx.Config.WalletServer.V(),
 700  			Endpoint:             "ws",
 701  			User:                 wg.cx.Config.Username.V(),
 702  			Pass:                 wg.cx.Config.Password.V(),
 703  			TLS:                  wg.cx.Config.ClientTLS.True(),
 704  			Certificates:         wg.certs,
 705  			DisableAutoReconnect: false,
 706  			DisableConnectOnNew:  false,
 707  		}, wg.WalletNotifications(), wg.cx.KillAll,
 708  	); E.Chk(e) {
 709  		wg.WalletMutex.Unlock()
 710  		return
 711  	}
 712  	wg.WalletMutex.Unlock()
 713  	// if e = wg.WalletClient.Connect(1); E.Chk(e) {
 714  	// 	return
 715  	// }
 716  	if e = wg.WalletClient.NotifyNewTransactions(true); !E.Chk(e) {
 717  		D.Ln("subscribed to new transactions")
 718  	} else {
 719  		// return
 720  	}
 721  	// if e = wg.WalletClient.NotifyBlocks(); E.Chk(e) {
 722  	// 	// return
 723  	// } else {
 724  	// 	D.Ln("subscribed to wallet client notify blocks")
 725  	// }
 726  	D.Ln("wallet connected")
 727  	return
 728  }
 729