Browse Source

Merge #589: Allow accessing basic wallet info without blockchain source

f26186d1bd Allow accessing basic wallet info without blockchain source (Kristaps Kaupe)

Pull request description:

  In both GUI and `wallet-tool.py`. Useful to, for example, extract recovery seed from a .jmdat wallet file without blockchain source. Resolves #545.

Top commit has no ACKs.

Tree-SHA512: c9c2d3b8601eac5dd55a05694c3fbd0873007abc666170e43cf26d745602db84200f5000355e4cc1c3be8085c78764f7d1d6cec87552d4e5775d47aa3d835208
master
Kristaps Kaupe 6 years ago
parent
commit
ebd4a82403
No known key found for this signature in database
GPG Key ID: D47B1B4232B55437
  1. 3
      jmclient/jmclient/wallet.py
  2. 5
      jmclient/jmclient/wallet_service.py
  3. 2
      jmclient/jmclient/wallet_utils.py
  4. 7
      jmclient/jmclient/yieldgenerator.py
  5. 40
      scripts/joinmarket-qt.py
  6. 4
      scripts/tumbler.py

3
jmclient/jmclient/wallet.py

@ -74,6 +74,9 @@ def estimate_tx_fee(ins, outs, txtype='p2pkh', extra_bytes=0):
for a transaction with the given number of inputs and outputs, for a transaction with the given number of inputs and outputs,
based on information from the blockchain interface. based on information from the blockchain interface.
''' '''
if jm_single().bc_interface is None:
raise RuntimeError("Cannot estimate transaction fee " +
"without blockchain source.")
fee_per_kb = jm_single().bc_interface.estimate_fee_per_kb( fee_per_kb = jm_single().bc_interface.estimate_fee_per_kb(
jm_single().config.getint("POLICY","tx_fees")) jm_single().config.getint("POLICY","tx_fees"))
absurd_fee = jm_single().config.getint("POLICY", "absurd_fee_per_kb") absurd_fee = jm_single().config.getint("POLICY", "absurd_fee_per_kb")

5
jmclient/jmclient/wallet_service.py

@ -42,7 +42,11 @@ class WalletService(Service):
self.bci = jm_single().bc_interface self.bci = jm_single().bc_interface
# keep track of the quasi-real-time blockheight # keep track of the quasi-real-time blockheight
# (updated in main monitor loop) # (updated in main monitor loop)
if self.bci is not None:
self.update_blockheight() self.update_blockheight()
else:
jlog.warning("No blockchain source available, " +
"wallet tools will not show correct balances.")
self.wallet = wallet self.wallet = wallet
self.synced = False self.synced = False
@ -111,6 +115,7 @@ class WalletService(Service):
""" Ensures wallet sync is complete """ Ensures wallet sync is complete
before the main event loop starts. before the main event loop starts.
""" """
if self.bci is not None:
d = task.deferLater(reactor, 0.0, self.sync_wallet) d = task.deferLater(reactor, 0.0, self.sync_wallet)
d.addCallback(self.start_wallet_monitoring) d.addCallback(self.start_wallet_monitoring)

2
jmclient/jmclient/wallet_utils.py

@ -1410,7 +1410,7 @@ def wallet_tool_main(wallet_root_path):
# the service will not be started since this is a synchronous script: # the service will not be started since this is a synchronous script:
wallet_service = WalletService(wallet) wallet_service = WalletService(wallet)
if method not in noscan_methods: if method not in noscan_methods and jm_single().bc_interface is not None:
# if nothing was configured, we override bitcoind's options so that # if nothing was configured, we override bitcoind's options so that
# unconfirmed balance is included in the wallet display by default # unconfirmed balance is included in the wallet display by default
if 'listunspent_args' not in jm_single().config.options('POLICY'): if 'listunspent_args' not in jm_single().config.options('POLICY'):

7
jmclient/jmclient/yieldgenerator.py

@ -12,7 +12,7 @@ from jmclient import Maker, jm_single, load_program_config, \
JMClientProtocolFactory, start_reactor, calc_cj_fee, \ JMClientProtocolFactory, start_reactor, calc_cj_fee, \
WalletService, add_base_options WalletService, add_base_options
from .wallet_utils import open_test_wallet_maybe, get_wallet_path from .wallet_utils import open_test_wallet_maybe, get_wallet_path
from jmbase.support import EXIT_ARGERROR from jmbase.support import EXIT_ARGERROR, EXIT_FAILURE
jlog = get_log() jlog = get_log()
@ -239,6 +239,11 @@ def ygmain(ygclass, txfee=1000, cjfee_a=200, cjfee_r=0.002, ordertype='swreloffe
load_program_config(config_path=options.datadir) load_program_config(config_path=options.datadir)
if jm_single().bc_interface is None:
jlog.error("Running yield generator requires configured " +
"blockchain source.")
sys.exit(EXIT_FAILURE)
wallet_path = get_wallet_path(wallet_name, None) wallet_path = get_wallet_path(wallet_name, None)
wallet = open_test_wallet_maybe( wallet = open_test_wallet_maybe(
wallet_path, wallet_name, options.mixdepth, wallet_path, wallet_name, options.mixdepth,

40
scripts/joinmarket-qt.py

@ -580,6 +580,9 @@ class SpendTab(QWidget):
self.startJoin() self.startJoin()
def startMultiple(self): def startMultiple(self):
if jm_single().bc_interface is None:
log.info("Cannot start join, blockchain source not available.")
return
if not self.spendstate.runstate == 'ready': if not self.spendstate.runstate == 'ready':
log.info("Cannot start join, already running.") log.info("Cannot start join, already running.")
return return
@ -659,7 +662,7 @@ class SpendTab(QWidget):
try: try:
amount = btc.amount_to_sat(self.amountInput.text()) amount = btc.amount_to_sat(self.amountInput.text())
except ValueError as e: except ValueError as e:
JMQtMessageBox(parent, e.args[0], title="Error", mbtype="warn") JMQtMessageBox(self, e.args[0], title="Error", mbtype="warn")
return return
makercount = int(self.numCPInput.text()) makercount = int(self.numCPInput.text())
mixdepth = int(self.mixdepthInput.text()) mixdepth = int(self.mixdepthInput.text())
@ -995,6 +998,12 @@ class SpendTab(QWidget):
self.tumbler_destaddrs = None self.tumbler_destaddrs = None
def validateSettings(self): def validateSettings(self):
if jm_single().bc_interface is None:
JMQtMessageBox(
self,
"Sending coins not possible without blockchain source.",
mbtype='warn', title="Error")
return False
valid, errmsg = validate_address( valid, errmsg = validate_address(
str(self.addressInput.text().strip())) str(self.addressInput.text().strip()))
if not valid: if not valid:
@ -1318,11 +1327,17 @@ class JMWalletTab(QWidget):
self.wallet_name = os.path.basename( self.wallet_name = os.path.basename(
mainWindow.wallet_service.get_storage_location()) mainWindow.wallet_service.get_storage_location())
if total_bal is None: if total_bal is None:
if jm_single().bc_interface is not None:
total_bal = " (syncing..)" total_bal = " (syncing..)"
else:
total_bal = " (unknown, no blockchain source available)"
self.label1.setText("CURRENT WALLET: " + self.wallet_name + self.label1.setText("CURRENT WALLET: " + self.wallet_name +
', total balance: ' + total_bal) ', total balance: ' + total_bal)
l.show() l.show()
if jm_single().bc_interface is None and self.wallet_name != 'NONE':
return
for i in range(nm): for i in range(nm):
if walletinfo: if walletinfo:
mdbalance = mbalances[i] mdbalance = mbalances[i]
@ -1728,6 +1743,12 @@ class JMMainWindow(QMainWindow):
self.walletRefresh.stop() self.walletRefresh.stop()
self.wallet_service = WalletService(wallet) self.wallet_service = WalletService(wallet)
if jm_single().bc_interface is None:
self.centralWidget().widget(0).updateWalletInfo(
get_wallet_printout(self.wallet_service))
return True
# add information callbacks: # add information callbacks:
self.wallet_service.add_restart_callback(self.restartWithMsg) self.wallet_service.add_restart_callback(self.restartWithMsg)
self.wallet_service.autofreeze_warning_cb = self.autofreeze_warning_cb self.wallet_service.autofreeze_warning_cb = self.autofreeze_warning_cb
@ -1936,15 +1957,16 @@ except Exception as e:
]) ])
JMQtMessageBox(None, config_load_error, mbtype='crit', title='failed to load') JMQtMessageBox(None, config_load_error, mbtype='crit', title='failed to load')
sys.exit(EXIT_FAILURE) sys.exit(EXIT_FAILURE)
# Qt does not currently support any functioning without a Core interface: # Only partial functionality (see wallet info, change config) is possible
# without a blockchain interface.
if jm_single().bc_interface is None: if jm_single().bc_interface is None:
blockchain_error = ''.join(["Joinmarket-Qt requires Bitcoin Core as a blockchain ", blockchain_warning = ''.join([
"interface; change the setting of 'blockchain_source' ", "No blockchain source currently configured. ",
"in the joinmarket.cfg file to a value not equal to ", "You will be able to see wallet information and change configuration ",
"'no-blockchain'; see comments for details."]) "but other functionality will be limited. ",
JMQtMessageBox(None, blockchain_error, mbtype='crit', "Go to the 'Settings' tab and configure blockchain settings there."])
title='Invalid blockchain source') JMQtMessageBox(None, blockchain_warning, mbtype='warn',
sys.exit(EXIT_FAILURE) title='No blockchain source')
#refuse to load non-segwit wallet (needs extra work in wallet-utils). #refuse to load non-segwit wallet (needs extra work in wallet-utils).
if not jm_single().config.get("POLICY", "segwit") == "true": if not jm_single().config.get("POLICY", "segwit") == "true":
wallet_load_error = ''.join(["Joinmarket-Qt only supports segwit based wallets, ", wallet_load_error = ''.join(["Joinmarket-Qt only supports segwit based wallets, ",

4
scripts/tumbler.py

@ -31,6 +31,10 @@ def main():
sys.exit(EXIT_ARGERROR) sys.exit(EXIT_ARGERROR)
load_program_config(config_path=options['datadir']) load_program_config(config_path=options['datadir'])
if jm_single().bc_interface is None:
jmprint('Error: Needs a blockchain source', "error")
sys.exit(EXIT_FAILURE)
check_regtest() check_regtest()
#Load the wallet #Load the wallet

Loading…
Cancel
Save