Browse Source

Include chromalog package for colorized logs

Also use this lib to print non-log messages with
standardized color formats.
Some clean up in jmbase, remove unused objects/methods.
master
AdamISZ 7 years ago
parent
commit
c139067be4
No known key found for this signature in database
GPG Key ID: 141001A1AF77F20B
  1. 2
      jmbase/jmbase/__init__.py
  2. 98
      jmbase/jmbase/support.py
  3. 3
      jmbase/setup.py
  4. 21
      jmbase/test/test_base_support.py
  5. 6
      jmclient/jmclient/blockchaininterface.py
  6. 2
      jmclient/jmclient/client_protocol.py
  7. 20
      jmclient/jmclient/commitment_utils.py
  8. 9
      jmclient/jmclient/configure.py
  9. 18
      jmclient/jmclient/electruminterface.py
  10. 4
      jmclient/jmclient/podle.py
  11. 3
      jmclient/jmclient/taker.py
  12. 17
      jmclient/jmclient/taker_utils.py
  13. 72
      jmclient/jmclient/wallet_utils.py
  14. 15
      scripts/add-utxo.py
  15. 30
      scripts/sendpayment.py
  16. 4
      scripts/sendtomany.py
  17. 12
      scripts/tumbler.py
  18. 3
      scripts/wallet-tool.py
  19. 4
      scripts/yg-privacyenhanced.py
  20. 4
      scripts/yield-generator-basic.py
  21. 19
      test/ygrunner.py

2
jmbase/jmbase/__init__.py

@ -2,7 +2,7 @@ from __future__ import (absolute_import, division,
print_function, unicode_literals)
from builtins import *
from .support import (get_log, chunks, debug_silence, debug_dump_object,
from .support import (get_log, chunks, debug_silence, jmprint,
joinmarket_alert, core_alert, get_password,
set_logging_level)
from .commands import *

98
jmbase/jmbase/support.py

@ -1,16 +1,48 @@
from __future__ import (absolute_import, division,
print_function, unicode_literals)
from builtins import * # noqa: F401
from future.utils import iteritems
import sys
import logging
import pprint
from getpass import getpass
logFormatter = logging.Formatter(
"%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s] %(message)s")
from chromalog.log import (
ColorizingStreamHandler,
ColorizingFormatter,
)
from chromalog.colorizer import GenericColorizer
from colorama import Fore, Back, Style
# magic; importing e.g. 'info' actually instantiates
# that as a function that uses the color map
# defined below. ( noqa because flake doesn't understand)
from chromalog.mark.helpers.simple import ( # noqa: F401
debug,
info,
important,
success,
warning,
error,
critical,
)
# our chosen colorings for log messages in JM:
jm_color_map = {
'debug': (Style.DIM + Fore.LIGHTBLUE_EX, Style.RESET_ALL),
'info': (Style.BRIGHT + Fore.BLUE, Style.RESET_ALL),
'important': (Style.BRIGHT, Style.RESET_ALL),
'success': (Fore.GREEN, Style.RESET_ALL),
'warning': (Fore.YELLOW, Style.RESET_ALL),
'error': (Fore.RED, Style.RESET_ALL),
'critical': (Back.RED, Style.RESET_ALL),
}
class JMColorizer(GenericColorizer):
default_color_map = jm_color_map
jm_colorizer = JMColorizer()
logFormatter = ColorizingFormatter(
"%(asctime)s [%(levelname)s] %(message)s")
log = logging.getLogger('joinmarket')
log.setLevel(logging.DEBUG)
@ -21,11 +53,10 @@ debug_silence = [False]
#TODO pass this through from client, bitcoin paramater:
DUST_THRESHOLD = 2730
#consoleHandler = logging.StreamHandler(stream=sys.stdout)
class JoinMarketStreamHandler(logging.StreamHandler):
class JoinMarketStreamHandler(ColorizingStreamHandler):
def __init__(self, stream):
super(JoinMarketStreamHandler, self).__init__(stream)
def __init__(self):
super(JoinMarketStreamHandler, self).__init__(colorizer=jm_colorizer)
def emit(self, record):
if joinmarket_alert[0]:
@ -35,10 +66,31 @@ class JoinMarketStreamHandler(logging.StreamHandler):
if not debug_silence[0]:
super(JoinMarketStreamHandler, self).emit(record)
handler = JoinMarketStreamHandler()
handler.setFormatter(logFormatter)
log.addHandler(handler)
def jmprint(msg, level="info"):
""" Provides the ability to print messages
with consistent formatting, outside the logging system
(in case you don't want the standard log format).
Example applications are: REPL style stuff, and/or
some very important / user workflow affecting communication.
Note that this exclusively for console printout, NOT for
logging to file (chromalog will handle file streams
properly, but this will not).
"""
if not level in jm_color_map.keys():
raise Exception("Unsupported formatting")
consoleHandler = JoinMarketStreamHandler(stream=sys.stdout)
consoleHandler.setFormatter(logFormatter)
log.addHandler(consoleHandler)
# .colorize_message function does a .format() on the string,
# which does not work with string-ified json; this should
# result in output as intended:
msg = msg.replace('{', '{{')
msg = msg.replace('}', '}}')
fmtfn = eval(level)
print(jm_colorizer.colorize_message(fmtfn(msg)))
def get_log():
"""
@ -48,7 +100,7 @@ def get_log():
return log
def set_logging_level(level):
consoleHandler.setLevel(level)
handler.setLevel(level)
def chunks(d, n):
return [d[x:x + n] for x in range(0, len(d), n)]
@ -58,21 +110,3 @@ def get_password(msg): #pragma: no cover
if not isinstance(password, bytes):
password = password.encode('utf-8')
return password
def debug_dump_object(obj, skip_fields=None):
if skip_fields is None:
skip_fields = []
log.debug('Class debug dump, name:' + obj.__class__.__name__)
for k, v in iteritems(obj.__dict__):
if k in skip_fields:
continue
if k == 'password' or k == 'given_password':
continue
log.debug('key=' + k)
if isinstance(v, str):
log.debug('string: len:' + str(len(v)))
log.debug(v)
elif isinstance(v, dict) or isinstance(v, list):
log.debug(pprint.pformat(v))
else:
log.debug(str(v))

3
jmbase/setup.py

@ -9,5 +9,6 @@ setup(name='joinmarketbase',
author_email='',
license='GPL',
packages=['jmbase'],
install_requires=['future', 'twisted==18.9.0', 'service-identity'],
install_requires=['future', 'twisted==18.9.0', 'service-identity',
'chromalog==1.0.5'],
zip_safe=False)

21
jmbase/test/test_base_support.py

@ -2,25 +2,10 @@
from __future__ import (absolute_import, division,
print_function, unicode_literals)
from builtins import * # noqa: F401
from jmbase.support import debug_dump_object, joinmarket_alert
def test_debug_dump_object():
joinmarket_alert[0] = "dummy jm alert"
class TestObj(object):
def __init__(self):
self.x = "foo"
self.password = "bar"
self.y = "baz"
to = TestObj()
debug_dump_object(to)
to.given_password = "baa"
debug_dump_object(to)
to.extradict = {1:2, 3:4}
debug_dump_object(to)
to.extralist = ["dummy", "list"]
debug_dump_object(to)
to.extradata = 100
debug_dump_object(to, skip_fields="y")
def test_color_coded_logging():
# TODO
pass

6
jmclient/jmclient/blockchaininterface.py

@ -16,7 +16,7 @@ import jmbitcoin as btc
from jmclient.jsonrpc import JsonRpcConnectionError, JsonRpcError
from jmclient.configure import get_p2pk_vbyte, jm_single
from jmbase.support import get_log
from jmbase.support import get_log, jmprint
log = get_log()
@ -388,7 +388,7 @@ class BitcoinCoreInterface(BlockchainInterface):
if restart_cb:
restart_cb(restart_msg)
else:
print(restart_msg)
jmprint(restart_msg, "important")
sys.exit(0)
def sync_wallet(self, wallet, fast=False, restart_cb=None):
@ -936,7 +936,7 @@ class RegtestBitcoinCoreInterface(BitcoinCoreInterface): #pragma: no cover
ret = super(RegtestBitcoinCoreInterface, self).pushtx(txhex)
if not self.simulating and self.tick_forward_chain_interval > 0:
print('will call tfc after ' + str(self.tick_forward_chain_interval) + ' seconds.')
log.debug('will call tfc after ' + str(self.tick_forward_chain_interval) + ' seconds.')
reactor.callLater(self.tick_forward_chain_interval,
self.tick_forward_chain, 1)
return ret

2
jmclient/jmclient/client_protocol.py

@ -57,7 +57,7 @@ class JMClientProtocol(amp.AMP):
d.addErrback(self.defaultErrback)
def connectionMade(self):
print('connection was made, starting client')
jlog.debug('connection was made, starting client.')
self.factory.setClient(self)
self.clientStart()

20
jmclient/jmclient/commitment_utils.py

@ -4,6 +4,7 @@ from builtins import * # noqa: F401
import sys
import jmbitcoin as btc
from jmbase import jmprint
from jmclient import jm_single, get_p2pk_vbyte, get_p2sh_vbyte
def quit(parser, errmsg): #pragma: no cover
@ -25,12 +26,12 @@ def get_utxo_info(upriv):
assert n in range(256)
except:
#not sending data to stdout in case privkey info
print("Failed to parse utxo information for utxo")
jmprint("Failed to parse utxo information for utxo", "error")
raise
try:
hexpriv = btc.from_wif_privkey(priv, vbyte=get_p2pk_vbyte())
except:
print("failed to parse privkey, make sure it's WIF compressed format.")
jmprint("failed to parse privkey, make sure it's WIF compressed format.", "error")
raise
return u, priv
@ -43,27 +44,26 @@ def validate_utxo_data(utxo_datas, retrieve=False, segwit=False):
"""
results = []
for u, priv in utxo_datas:
print('validating this utxo: ' + str(u))
jmprint('validating this utxo: ' + str(u), "info")
hexpriv = btc.from_wif_privkey(priv, vbyte=get_p2pk_vbyte())
if segwit:
addr = btc.pubkey_to_p2sh_p2wpkh_address(
btc.privkey_to_pubkey(hexpriv), get_p2sh_vbyte())
else:
addr = btc.privkey_to_address(hexpriv, magicbyte=get_p2pk_vbyte())
print('claimed address: ' + addr)
jmprint('claimed address: ' + addr, "info")
res = jm_single().bc_interface.query_utxo_set([u])
print('blockchain shows this data: ' + str(res))
if len(res) != 1 or None in res:
print("utxo not found on blockchain: " + str(u))
jmprint("utxo not found on blockchain: " + str(u), "error")
return False
if res[0]['address'] != addr:
print("privkey corresponds to the wrong address for utxo: " + str(u))
print("blockchain returned address: {}".format(res[0]['address']))
print("your privkey gave this address: " + addr)
jmprint("privkey corresponds to the wrong address for utxo: " + str(u), "error")
jmprint("blockchain returned address: {}".format(res[0]['address']), "error")
jmprint("your privkey gave this address: " + addr, "error")
return False
if retrieve:
results.append((u, res[0]['value']))
print('all utxos validated OK')
jmprint('all utxos validated OK', "success")
if retrieve:
return results
return True

9
jmclient/jmclient/configure.py

@ -12,7 +12,7 @@ from configparser import ConfigParser, NoOptionError
import jmbitcoin as btc
from jmclient.jsonrpc import JsonRpc
from jmbase.support import (get_log, joinmarket_alert, core_alert, debug_silence,
set_logging_level)
set_logging_level, jmprint)
from jmclient.podle import set_commitment_file
log = get_log()
@ -407,8 +407,8 @@ def load_program_config(config_path=None, bs=None):
if len(loadedFiles) != 1:
with open(global_singleton.config_location, "w") as configfile:
configfile.write(defaultconfig)
print("Created a new `joinmarket.cfg`. Please review and adopt the "
"settings and restart joinmarket.")
jmprint("Created a new `joinmarket.cfg`. Please review and adopt the "
"settings and restart joinmarket.", "info")
exit(1)
#These are left as sanity checks but currently impossible
@ -437,7 +437,8 @@ def load_program_config(config_path=None, bs=None):
try:
set_logging_level(loglevel)
except:
print("Failed to set logging level, must be DEBUG, INFO, WARNING, ERROR")
jmprint("Failed to set logging level, must be DEBUG, INFO, WARNING, ERROR",
"error")
try:
global_singleton.maker_timeout_sec = global_singleton.config.getint(
'TIMEOUT', 'maker_timeout_sec')

18
jmclient/jmclient/electruminterface.py

@ -18,7 +18,7 @@ from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor, task, defer
from .blockchaininterface import BlockchainInterface
from .configure import get_p2sh_vbyte
from jmbase import get_log
from jmbase import get_log, jmprint
from .electrum_data import get_default_servers, set_electrum_testnet,\
DEFAULT_PROTO
@ -96,7 +96,7 @@ class TxElectrumClientProtocolFactory(ClientFactory):
self.bci.start_electrum_proto(None)
def clientConnectionFailed(self, connector, reason):
print('connection failed')
jmprint('connection failed', "warning")
self.bci.start_electrum_proto(None)
class ElectrumConn(threading.Thread):
@ -423,7 +423,7 @@ class ElectrumInterface(BlockchainInterface):
if super(ElectrumInterface, self).fee_per_kb_has_been_manually_set(N):
return int(random.uniform(N * float(0.8), N * float(1.2)))
fee_info = self.get_from_electrum('blockchain.estimatefee', N, blocking=True)
print('got fee info result: ' + str(fee_info))
jmprint('got fee info result: ' + str(fee_info), "debug")
fee = fee_info.get('result')
fee_per_kb_sat = int(float(fee) * 100000000)
return fee_per_kb_sat
@ -437,7 +437,7 @@ class ElectrumInterface(BlockchainInterface):
End the loop when the confirmation has been seen (no spent monitoring here).
"""
wl = self.tx_watcher_loops[notifyaddr]
print('txoutset=' + pprint.pformat(tx_output_set))
jmprint('txoutset=' + pprint.pformat(tx_output_set), "debug")
unconftx = self.get_from_electrum('blockchain.address.get_mempool',
notifyaddr, blocking=True).get('result')
unconftxs = set([str(t['tx_hash']) for t in unconftx])
@ -453,14 +453,14 @@ class ElectrumInterface(BlockchainInterface):
txhex = txdata['hex']
outs = set([(sv['script'], sv['value']) for sv in btc.deserialize(
txhex)['outs']])
print('unconfirm query outs = ' + str(outs))
jmprint('unconfirm query outs = ' + str(outs), "debug")
if outs == tx_output_set:
unconfirmed_txid = txdata['id']
unconfirmed_txhex = txhex
break
#call unconf callback if it was found in the mempool
if unconfirmed_txid and not wl[1]:
print("Tx: " + str(unconfirmed_txid) + " seen on network.")
jmprint("Tx: " + str(unconfirmed_txid) + " seen on network.", "info")
unconfirmfun(btc.deserialize(unconfirmed_txhex), unconfirmed_txid)
wl[1] = True
return
@ -479,7 +479,7 @@ class ElectrumInterface(BlockchainInterface):
txhex = txdata['hex']
outs = set([(sv['script'], sv['value']) for sv in btc.deserialize(
txhex)['outs']])
print('confirm query outs = ' + str(outs))
jmprint('confirm query outs = ' + str(outs), "info")
if outs == tx_output_set:
confirmed_txid = txdata['id']
confirmed_txhex = txhex
@ -518,7 +518,7 @@ class ElectrumInterface(BlockchainInterface):
unconftxs = [str(t['tx_hash']) for t in unconftxs_res]
if not wl[1] and txid in unconftxs:
print("Tx: " + str(txid) + " seen on network.")
jmprint("Tx: " + str(txid) + " seen on network.", "info")
unconfirmfun(txd, txid)
wl[1] = True
return
@ -526,7 +526,7 @@ class ElectrumInterface(BlockchainInterface):
addr, blocking=True).get('result')
conftxs = [str(t['tx_hash']) for t in conftx]
if not wl[2] and len(conftxs) and txid in conftxs:
print("Tx: " + str(txid) + " is confirmed.")
jmprint("Tx: " + str(txid) + " is confirmed.", "info")
confirmfun(txd, txid, 1)
wl[2] = True
#Note we do not stop the monitoring loop when

4
jmclient/jmclient/podle.py

@ -10,6 +10,7 @@ import hashlib
import json
import binascii
import struct
from jmbase import jmprint
from jmbitcoin import multiply, add_pubkeys, getG, podle_PublicKey,\
podle_PrivateKey, encode, decode, N, podle_PublicKey_class
@ -312,7 +313,8 @@ def update_commitments(commitment=None,
c = json.loads(f.read().decode('utf-8'))
except ValueError: #pragma: no cover
#Exit conditions cannot be included in tests.
print("the file: " + PODLE_COMMIT_FILE + " is not valid json.")
jmprint("the file: " + PODLE_COMMIT_FILE + " is not valid json.",
"error")
sys.exit(0)
if 'used' in c:

3
jmclient/jmclient/taker.py

@ -563,7 +563,8 @@ class Taker(object):
#verify_tx_input will not even parse the script if it has integers or None,
#so abort in case we were given a junk sig:
if not all([not isinstance(x, int) and x for x in sig_deserialized]):
print("Junk signature: ", sig_deserialized, ", not attempting to verify")
jlog.warn("Junk signature: " + str(sig_deserialized) + \
", not attempting to verify")
break
if len(sig_deserialized) == 2:
ver_sig, ver_pub = sig_deserialized

17
jmclient/jmclient/taker_utils.py

@ -8,7 +8,7 @@ import os
import time
import numbers
from binascii import unhexlify
from jmbase import get_log
from jmbase import get_log, jmprint
from .configure import jm_single, validate_address
from .schedule import human_readable_schedule_entry, tweak_tumble_schedule,\
schedule_to_text
@ -233,18 +233,19 @@ def tumbler_taker_finished_update(taker, schedulefile, tumble_log, options,
#for command line script TODO
if taker.schedule[taker.schedule_index+1][3] == 'addrask':
jm_single().debug_silence[0] = True
print('\n'.join(['=' * 60] * 3))
print('Tumbler requires more addresses to stop amount correlation')
print('Obtain a new destination address from your bitcoin recipient')
print(' for example click the button that gives a new deposit address')
print('\n'.join(['=' * 60] * 1))
jmprint('\n'.join(['=' * 60] * 3))
jmprint('Tumbler requires more addresses to stop amount correlation')
jmprint('Obtain a new destination address from your bitcoin recipient')
jmprint(' for example click the button that gives a new deposit address')
jmprint('\n'.join(['=' * 60] * 1))
while True:
destaddr = input('insert new address: ')
addr_valid, errormsg = validate_address(destaddr)
if addr_valid:
break
print(
'Address ' + destaddr + ' invalid. ' + errormsg + ' try again')
jmprint(
'Address ' + destaddr + ' invalid. ' + errormsg + ' try again',
"warning")
jm_single().debug_silence[0] = False
taker.schedule[taker.schedule_index+1][3] = destaddr
taker.tdestaddrs.append(destaddr)

72
jmclient/jmclient/wallet_utils.py

@ -16,7 +16,7 @@ from jmclient import (get_network, WALLET_IMPLEMENTATIONS, Storage, podle,
jm_single, BitcoinCoreInterface, JsonRpcError, sync_wallet, WalletError,
VolatileStorage, StoragePasswordError,
is_segwit_mode, SegwitLegacyWallet, LegacyWallet)
from jmbase.support import get_password
from jmbase.support import get_password, jmprint
from .cryptoengine import TYPE_P2PKH, TYPE_P2SH_P2WPKH
import jmbitcoin as btc
@ -456,7 +456,7 @@ def cli_get_wallet_passphrase_check():
password = get_password('Enter wallet file encryption passphrase: ')
password2 = get_password('Reenter wallet file encryption passphrase: ')
if password != password2:
print('ERROR. Passwords did not match')
jmprint('ERROR. Passwords did not match', "error")
return False
return password
@ -467,7 +467,7 @@ def cli_display_user_words(words, mnemonic_extension):
text = 'Write down this wallet recovery mnemonic\n\n' + words +'\n'
if mnemonic_extension:
text += '\nAnd this mnemonic extension: ' + mnemonic_extension + '\n'
print(text)
jmprint(text, "important")
def cli_user_mnemonic_entry():
mnemonic_phrase = input("Input mnemonic recovery phrase: ")
@ -480,9 +480,10 @@ def cli_get_mnemonic_extension():
uin = input("Would you like to use a two-factor mnemonic recovery "
"phrase? write 'n' if you don't know what this is (y/n): ")
if len(uin) == 0 or uin[0] != 'y':
print("Not using mnemonic extension")
jmprint("Not using mnemonic extension", "info")
return None #no mnemonic extension
print("Note: This will be stored in a reversible way. Do not reuse!")
jmprint("Note: This will be stored in a reversible way. Do not reuse!",
"info")
return input("Enter mnemonic extension: ")
@ -554,7 +555,7 @@ def wallet_generate_recover(method, walletspath,
try:
entropy = LegacyWallet.entropy_from_mnemonic(seed)
except WalletError as e:
print("Unable to restore seed: {}".format(e.message))
jmprint("Unable to restore seed: {}".format(e.message), "error")
return False
elif method != 'generate':
raise Exception("unknown method for wallet creation: '{}'"
@ -571,8 +572,8 @@ def wallet_generate_recover(method, walletspath,
wallet = create_wallet(wallet_path, password, mixdepth,
wallet_cls=LegacyWallet, entropy=entropy)
print("Write down and safely store this wallet recovery seed\n\n{}\n"
.format(wallet.get_mnemonic_words()[0]))
jmprint("Write down and safely store this wallet recovery seed\n\n{}\n"
.format(wallet.get_mnemonic_words()[0]), "important")
wallet.close()
return True
@ -628,7 +629,7 @@ def wallet_fetch_history(wallet, options):
sat_to_str(balance), skip_n1(cj_n), sat_to_str(miner_fees),
'% 3d' % utxo_count, skip_n1(mixdepth_src), skip_n1(mixdepth_dst)]
if options.verbosity % 2 == 0: data += [txid]
print(s().join(map('"{}"'.format, data)))
jmprint(s().join(map('"{}"'.format, data)), "info")
field_names = ['tx#', 'timestamp', 'type', 'amount/btc',
@ -636,9 +637,9 @@ def wallet_fetch_history(wallet, options):
'utxo-count', 'mixdepth-from', 'mixdepth-to']
if options.verbosity % 2 == 0: field_names += ['txid']
if options.csv:
print('Bumping verbosity level to 4 due to --csv flag')
jmprint('Bumping verbosity level to 4 due to --csv flag', "debug")
options.verbosity = 4
if options.verbosity > 0: print(s().join(field_names))
if options.verbosity > 0: jmprint(s().join(field_names), "info")
if options.verbosity <= 2: cj_batch = [0]*8 + [[]]*2
balance = 0
utxo_count = 0
@ -722,7 +723,7 @@ def wallet_fetch_history(wallet, options):
#payment to self
out_value = sum([output_script_values[a] for a in our_output_scripts])
if not is_coinjoin:
print('this is wrong TODO handle non-coinjoin internal')
jmprint('this is wrong TODO handle non-coinjoin internal', "warning")
tx_type = 'cj internal'
amount = cj_amount
delta_balance = out_value - our_input_value
@ -732,7 +733,7 @@ def wallet_fetch_history(wallet, options):
mixdepth_dst = wallet.get_script_mixdepth(cj_script)
else:
tx_type = 'unknown type'
print('our utxos: ' + str(len(our_input_scripts)) \
jmprint('our utxos: ' + str(len(our_input_scripts)) \
+ ' in, ' + str(len(our_output_scripts)) + ' out')
balance += delta_balance
utxo_count += (len(our_output_scripts) - utxos_consumed)
@ -790,10 +791,10 @@ def wallet_fetch_history(wallet, options):
)['time']
except JsonRpcError:
now = jm_single().bc_interface.rpc('getblock', [bestblockhash])['time']
print(' %s best block is %s' % (datetime.fromtimestamp(now)
jmprint(' %s best block is %s' % (datetime.fromtimestamp(now)
.strftime("%Y-%m-%d %H:%M"), bestblockhash))
total_profit = float(balance - sum(deposits)) / float(100000000)
print('total profit = %.8f BTC' % total_profit)
jmprint('total profit = %.8f BTC' % total_profit)
if abs(total_profit) > 0:
try:
@ -808,21 +809,21 @@ def wallet_fetch_history(wallet, options):
return np.sum(np.exp((now - deposit_times) / 60.0 / 60 / 24 /
365)**r * deposits) - final_balance
r = brentq(f, a=1, b=-1, args=(deposits, deposit_times, now, balance))
print('continuously compounded equivalent annual interest rate = ' +
jmprint('continuously compounded equivalent annual interest rate = ' +
str(r * 100) + ' %')
print('(as if yield generator was a bank account)')
jmprint('(as if yield generator was a bank account)')
except ImportError:
print('scipy not installed, unable to predict accumulation rate')
print('to add it to this virtualenv, use `pip install scipy`')
jmprint('scipy not installed, unable to predict accumulation rate')
jmprint('to add it to this virtualenv, use `pip install scipy`')
total_wallet_balance = sum(wallet.get_balance_by_mixdepth().values())
if balance != total_wallet_balance:
print(('BUG ERROR: wallet balance (%s) does not match balance from ' +
jmprint(('BUG ERROR: wallet balance (%s) does not match balance from ' +
'history (%s)') % (sat_to_str(total_wallet_balance),
sat_to_str(balance)))
wallet_utxo_count = sum(map(len, wallet.get_utxos_by_mixdepth_().values()))
if utxo_count != wallet_utxo_count:
print(('BUG ERROR: wallet utxo count (%d) does not match utxo count from ' +
jmprint(('BUG ERROR: wallet utxo count (%d) does not match utxo count from ' +
'history (%s)') % (wallet_utxo_count, utxo_count))
@ -835,11 +836,11 @@ def wallet_showseed(wallet):
def wallet_importprivkey(wallet, mixdepth, key_type):
print("WARNING: This imported key will not be recoverable with your 12 "
"word mnemonic phrase. Make sure you have backups.")
print("WARNING: Handling of raw ECDSA bitcoin private keys can lead to "
jmprint("WARNING: This imported key will not be recoverable with your 12 "
"word mnemonic phrase. Make sure you have backups.", "warning")
jmprint("WARNING: Handling of raw ECDSA bitcoin private keys can lead to "
"non-intuitive behaviour and loss of funds.\n Recommended instead "
"is to use the \'sweep\' feature of sendpayment.py.")
"is to use the \'sweep\' feature of sendpayment.py.", "warning")
privkeys = input("Enter private key(s) to import: ")
privkeys = privkeys.split(',') if ',' in privkeys else privkeys.split()
imported_addr = []
@ -857,20 +858,22 @@ def wallet_importprivkey(wallet, mixdepth, key_type):
imported_addr.append(wallet.get_addr_path(path))
if not imported_addr:
print("Warning: No keys imported!")
jmprint("Warning: No keys imported!", "error")
return
wallet.save()
# show addresses to user so they can verify everything went as expected
print("Imported keys for addresses:\n{}".format('\n'.join(imported_addr)))
jmprint("Imported keys for addresses:\n{}".format('\n'.join(imported_addr)),
"success")
if import_failed:
print("Warning: failed to import {} keys".format(import_failed))
jmprint("Warning: failed to import {} keys".format(import_failed),
"error")
def wallet_dumpprivkey(wallet, hdpath):
if not hdpath:
print("Error: no hd wallet path supplied")
jmprint("Error: no hd wallet path supplied", "error")
return False
path = wallet.path_repr_to_path(hdpath)
return wallet.get_wif_path(path) # will raise exception on invalid path
@ -992,10 +995,11 @@ def open_wallet(path, ask_for_password=True, password=None, read_only=False,
pwd = get_password("Enter wallet decryption passphrase: ") or None
storage = Storage(path, password=pwd, read_only=read_only)
except StoragePasswordError:
print("Wrong password, try again.")
jmprint("Wrong password, try again.", "warning")
continue
except Exception as e:
print("Failed to load wallet, error message: " + repr(e))
jmprint("Failed to load wallet, error message: " + repr(e),
"error")
raise e
break
else:
@ -1081,8 +1085,8 @@ def wallet_tool_main(wallet_root_path):
return wallet_display(wallet, options.gaplimit, options.showprivkey, summarized=True)
elif method == "history":
if not isinstance(jm_single().bc_interface, BitcoinCoreInterface):
print('showing history only available when using the Bitcoin Core ' +
'blockchain interface')
jmprint('showing history only available when using the Bitcoin Core ' +
'blockchain interface', "error")
sys.exit(0)
else:
return wallet_fetch_history(wallet, options)
@ -1133,5 +1137,5 @@ if __name__ == "__main__":
acctlist.append(WalletViewAccount(rootpath, a, branches=branches))
wallet = WalletView(rootpath + "/" + str(walletbranch),
accounts=acctlist)
print(wallet.serialize())
jmprint(wallet.serialize(), "success")

15
scripts/add-utxo.py

@ -16,6 +16,7 @@ import binascii
from pprint import pformat
from optparse import OptionParser
from jmbase import jmprint
import jmbitcoin as btc
from jmclient import load_program_config, jm_single, get_p2pk_vbyte,\
open_wallet, sync_wallet, add_external_commitments, update_commitments,\
@ -161,16 +162,16 @@ def main():
if len(args) > 0 or other:
if input("You have chosen to delete commitments, other arguments "
"will be ignored; continue? (y/n)") != 'y':
print("Quitting")
jmprint("Quitting", "warning")
sys.exit(0)
c, e = get_podle_commitments()
print(pformat(e))
jmprint(pformat(e), "info")
if input(
"You will remove the above commitments; are you sure? (y/n): ") != 'y':
print("Quitting")
jmprint("Quitting", "warning")
sys.exit(0)
update_commitments(external_to_remove=e)
print("Commitments deleted.")
jmprint("Commitments deleted.", "important")
sys.exit(0)
#Three options (-w, -r, -R) for loading utxo and privkey pairs from a wallet,
@ -199,13 +200,13 @@ def main():
utxo_data.append((u, priv))
elif options.in_json:
if not os.path.isfile(options.in_json):
print("File: " + options.in_json + " not found.")
jmprint("File: " + options.in_json + " not found.", "error")
sys.exit(0)
with open(options.in_json, "rb") as f:
try:
utxo_json = json.loads(f.read())
except:
print("Failed to read json from " + options.in_json)
jmprint("Failed to read json from " + options.in_json, "error")
sys.exit(0)
for u, pva in iteritems(utxo_json):
utxo_data.append((u, pva['privkey']))
@ -232,4 +233,4 @@ def main():
if __name__ == "__main__":
main()
print('done')
jmprint('done', "success")

30
scripts/sendpayment.py

@ -19,20 +19,20 @@ from jmclient import Taker, load_program_config, get_schedule,\
sync_wallet, RegtestBitcoinCoreInterface, estimate_tx_fee, direct_send,\
open_test_wallet_maybe, get_wallet_path
from twisted.python.log import startLogging
from jmbase.support import get_log
from jmbase.support import get_log, jmprint
from cli_options import get_sendpayment_parser, get_max_cj_fee_values
log = get_log()
#CLI specific, so relocated here (not used by tumbler)
def pick_order(orders, n): #pragma: no cover
print("Considered orders:")
jmprint("Considered orders:", "info")
for i, o in enumerate(orders):
print(" %2d. %20s, CJ fee: %6s, tx fee: %6d" %
(i, o[0]['counterparty'], str(o[0]['cjfee']), o[0]['txfee']))
jmprint(" %2d. %20s, CJ fee: %6s, tx fee: %6d" %
(i, o[0]['counterparty'], str(o[0]['cjfee']), o[0]['txfee']), "info")
pickedOrderIndex = -1
if i == 0:
print("Only one possible pick, picking it.")
jmprint("Only one possible pick, picking it.", "info")
return orders[0]
while pickedOrderIndex == -1:
try:
@ -67,15 +67,15 @@ def main():
mixdepth = options.mixdepth
addr_valid, errormsg = validate_address(destaddr)
if not addr_valid:
print('ERROR: Address invalid. ' + errormsg)
jmprint('ERROR: Address invalid. ' + errormsg, "error")
return
schedule = [[options.mixdepth, amount, options.makercount,
destaddr, 0.0, 0]]
else:
result, schedule = get_schedule(options.schedule)
if not result:
log.info("Failed to load schedule file, quitting. Check the syntax.")
log.info("Error was: " + str(schedule))
log.error("Failed to load schedule file, quitting. Check the syntax.")
log.error("Error was: " + str(schedule))
sys.exit(0)
mixdepth = 0
for s in schedule:
@ -95,8 +95,8 @@ def main():
if options.pickorders:
chooseOrdersFunc = pick_order
if sweeping:
print('WARNING: You may have to pick offers multiple times')
print('WARNING: due to manual offer picking while sweeping')
jmprint('WARNING: You may have to pick offers multiple times', "warning")
jmprint('WARNING: due to manual offer picking while sweeping', "warning")
else:
chooseOrdersFunc = options.order_choose_fn
@ -134,8 +134,8 @@ def main():
return
if wallet.get_txtype() == 'p2pkh':
print("Only direct sends (use -N 0) are supported for "
"legacy (non-segwit) wallets.")
jmprint("Only direct sends (use -N 0) are supported for "
"legacy (non-segwit) wallets.", "error")
return
def filter_orders_callback(orders_fees, cjamount):
@ -198,9 +198,9 @@ def main():
"giving up this attempt.")
reactor.stop()
return
print("We failed to complete the transaction. The following "
jmprint("We failed to complete the transaction. The following "
"makers responded honestly: ", taker.honest_makers,
", so we will retry with them.")
", so we will retry with them.", "warning")
#Now we have to set the specific group we want to use, and hopefully
#they will respond again as they showed honesty last time.
#we must reset the number of counterparties, as well as fix who they
@ -238,4 +238,4 @@ def main():
if __name__ == "__main__":
main()
print('done')
jmprint('done', "success")

4
scripts/sendtomany.py

@ -11,7 +11,7 @@ for other reasons).
from pprint import pformat
from optparse import OptionParser
import jmbitcoin as btc
from jmbase import get_log
from jmbase import get_log, jmprint
from jmclient import load_program_config, estimate_tx_fee, jm_single,\
get_p2pk_vbyte, validate_address, get_utxo_info,\
validate_utxo_data, quit
@ -121,4 +121,4 @@ def main():
if __name__ == "__main__":
main()
print('done')
jmprint('done', "success")

12
scripts/tumbler.py

@ -14,7 +14,7 @@ from jmclient import Taker, load_program_config, get_schedule,\
RegtestBitcoinCoreInterface, schedule_to_text, restart_waiter,\
get_tumble_log, tumbler_taker_finished_update,\
tumbler_filter_orders_callback
from jmbase.support import get_log
from jmbase.support import get_log, jmprint
from cli_options import get_tumbler_parser, get_max_cj_fee_values
log = get_log()
logsdir = os.path.join(os.path.dirname(
@ -27,7 +27,7 @@ def main():
options_org = options
options = vars(options)
if len(args) < 1:
print('Error: Needs a wallet file')
jmprint('Error: Needs a wallet file', "error")
sys.exit(0)
load_program_config()
@ -50,7 +50,7 @@ def main():
#Output information to log files
jm_single().mincjamount = options['mincjamount']
destaddrs = args[1:]
print(destaddrs)
jmprint("Destination addresses: " + str(destaddrs), "important")
#If the --restart flag is set we read the schedule
#from the file, and filter out entries that are
#already complete
@ -58,9 +58,9 @@ def main():
res, schedule = get_schedule(os.path.join(logsdir,
options['schedulefile']))
if not res:
print("Failed to load schedule, name: " + str(
options['schedulefile']))
print("Error was: " + str(schedule))
jmprint("Failed to load schedule, name: " + str(
options['schedulefile']), "error")
jmprint("Error was: " + str(schedule), "error")
sys.exit(0)
#This removes all entries that are marked as done
schedule = [s for s in schedule if s[5] != 1]

3
scripts/wallet-tool.py

@ -2,9 +2,10 @@ from __future__ import (absolute_import, division,
print_function, unicode_literals)
from builtins import * # noqa: F401
from jmbase import jmprint
from jmclient import load_program_config, wallet_tool_main
if __name__ == "__main__":
load_program_config()
#JMCS follows same convention as JM original; wallet is in "wallets" localdir
print(wallet_tool_main("wallets"))
jmprint(wallet_tool_main("wallets"), "success")

4
scripts/yg-privacyenhanced.py

@ -6,7 +6,7 @@ from future.utils import iteritems
import random
from jmbase import get_log
from jmbase import get_log, jmprint
from jmclient import YieldGeneratorBasic, ygmain, jm_single
@ -98,4 +98,4 @@ if __name__ == "__main__":
cjfee_r=cjfee_r, ordertype=ordertype,
nickserv_password='',
minsize=minsize, gaplimit=gaplimit)
print('done')
jmprint('done', "success")

4
scripts/yield-generator-basic.py

@ -3,7 +3,7 @@ from __future__ import (absolute_import, division,
print_function, unicode_literals)
from builtins import * # noqa: F401
from jmbase import get_log
from jmbase import get_log, jmprint
from jmclient import YieldGeneratorBasic, ygmain
"""THESE SETTINGS CAN SIMPLY BE EDITED BY HAND IN THIS FILE:
@ -23,4 +23,4 @@ if __name__ == "__main__":
cjfee_r=cjfee_r, ordertype=ordertype,
nickserv_password=nickserv_password,
minsize=max_minsize, gaplimit=gaplimit)
print('done')
jmprint('done', "success")

19
test/ygrunner.py

@ -17,6 +17,7 @@ from builtins import * # noqa: F401
from common import make_wallets
import pytest
import random
from jmbase import jmprint
from jmclient import YieldGeneratorBasic, load_program_config, jm_single,\
sync_wallet, JMClientProtocolFactory, start_reactor
@ -41,14 +42,14 @@ class MaliciousYieldGenerator(YieldGeneratorBasic):
def on_auth_received(self, nick, offer, commitment, cr, amount, kphex):
if self.authmal:
if random.randint(1, 100) < self.mfrac:
print("Counterparty commitment rejected maliciously")
jmprint("Counterparty commitment rejected maliciously", "debug")
return (False,)
return super(MaliciousYieldGenerator, self).on_auth_received(nick,
offer, commitment, cr, amount, kphex)
def on_tx_received(self, nick, txhex, offerinfo):
if self.txmal:
if random.randint(1, 100) < self.mfrac:
print("Counterparty tx rejected maliciously")
jmprint("Counterparty tx rejected maliciously", "debug")
return (False, "malicious tx rejection")
return super(MaliciousYieldGenerator, self).on_tx_received(nick, txhex,
offerinfo)
@ -74,13 +75,13 @@ class DeterministicMaliciousYieldGenerator(YieldGeneratorBasic):
def on_auth_received(self, nick, offer, commitment, cr, amount, kphex):
if self.authmal:
print("Counterparty commitment rejected maliciously")
jmprint("Counterparty commitment rejected maliciously", "debug")
return (False,)
return super(DeterministicMaliciousYieldGenerator, self).on_auth_received(nick,
offer, commitment, cr, amount, kphex)
def on_tx_received(self, nick, txhex, offerinfo):
if self.txmal:
print("Counterparty tx rejected maliciously")
jmprint("Counterparty tx rejected maliciously", "debug")
return (False, "malicious tx rejection")
return super(DeterministicMaliciousYieldGenerator, self).on_tx_received(nick, txhex,
offerinfo)
@ -106,17 +107,15 @@ def test_start_ygs(setup_ygrunner, num_ygs, wallet_structures, mean_amt,
mean_amt=mean_amt)
#the sendpayment bot uses the last wallet in the list
wallet = wallets[num_ygs]['wallet']
print("\n\nTaker wallet seed : " + wallets[num_ygs]['seed'])
jmprint("\n\nTaker wallet seed : " + wallets[num_ygs]['seed'])
# for manual audit if necessary, show the maker's wallet seeds
# also (note this audit should be automated in future, see
# test_full_coinjoin.py in this directory)
print("\n\nMaker wallet seeds: ")
jmprint("\n\nMaker wallet seeds: ")
for i in range(num_ygs):
print("Maker seed: " + wallets[i]['seed'])
print("\n")
#useful to see the utxos on screen sometimes
jmprint("Maker seed: " + wallets[i]['seed'])
jmprint("\n")
sync_wallet(wallet, fast=True)
print(wallet.get_utxos_by_mixdepth())
txfee = 1000
cjfee_a = 4200
cjfee_r = '0.001'

Loading…
Cancel
Save