26 changed files with 493 additions and 378 deletions
@ -0,0 +1,12 @@ |
|||||||
|
# .coveragerc to control coverage.py |
||||||
|
[run] |
||||||
|
omit = |
||||||
|
jmclient/jmclient/jsonrpc.py |
||||||
|
jmclient/jmclient/slowaes.py |
||||||
|
jmclient/jmclient/btc.py |
||||||
|
jmclient/test/* |
||||||
|
jmclient/setup.py |
||||||
|
jmbitcoin/test/* |
||||||
|
jmbitcoin/setup.py |
||||||
|
jmbase/test/* |
||||||
|
jmbase/setup.py |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
#! /usr/bin/env python |
||||||
|
from __future__ import print_function |
||||||
|
from jmbase.support import debug_dump_object, get_password, get_log, joinmarket_alert |
||||||
|
import pytest |
||||||
|
|
||||||
|
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") |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,63 @@ |
|||||||
|
#! /usr/bin/env python |
||||||
|
from __future__ import absolute_import |
||||||
|
'''Testing mostly exceptional cases in secp256k1_main. |
||||||
|
Some of these may represent code that should be removed, TODO.''' |
||||||
|
|
||||||
|
import jmbitcoin as btc |
||||||
|
import binascii |
||||||
|
import json |
||||||
|
import pytest |
||||||
|
import os |
||||||
|
testdir = os.path.dirname(os.path.realpath(__file__)) |
||||||
|
|
||||||
|
def test_hex2b58check(): |
||||||
|
assert btc.hex_to_b58check("aa"*32) == "12JAT9y2EcnV6DPUGikLJYjWwk5UmUEFXRiQVmTbfSLbL3njFzp" |
||||||
|
|
||||||
|
def test_bindblsha(): |
||||||
|
assert btc.bin_dbl_sha256("abc") == binascii.unhexlify( |
||||||
|
"4f8b42c22dd3729b519ba6f68d2da7cc5b2d606d05daed5ad5128cc03e6c6358") |
||||||
|
|
||||||
|
def test_lpad(): |
||||||
|
assert btc.lpad("aaaa", "b", 5) == "baaaa" |
||||||
|
assert btc.lpad("aaaa", "b", 4) == "aaaa" |
||||||
|
assert btc.lpad("aaaa", "b", 3) == "aaaa" |
||||||
|
|
||||||
|
def test_safe_from_hex(): |
||||||
|
assert btc.safe_from_hex('ff0100') == '\xff\x01\x00' |
||||||
|
|
||||||
|
def test_hash2int(): |
||||||
|
assert btc.hash_to_int("aa"*32) == \ |
||||||
|
77194726158210796949047323339125271902179989777093709359638389338608753093290 |
||||||
|
|
||||||
|
@btc.hexbin |
||||||
|
def dummyforwrap(a, b, c, d="foo", e="bar"): |
||||||
|
newa = a+"\x01" |
||||||
|
x, y = b |
||||||
|
newb = [x+"\x02", y+"\x03"] |
||||||
|
if d == "foo": |
||||||
|
return newb[1] |
||||||
|
else: |
||||||
|
return newb[0] |
||||||
|
|
||||||
|
def test_hexbin(): |
||||||
|
assert dummyforwrap("aa", ["bb", "cc"], True) == "cc03" |
||||||
|
assert dummyforwrap("aa", ["bb", "cc"], True, d="baz") == "bb02" |
||||||
|
assert dummyforwrap("\xaa", ["\xbb", "\xcc"], False) == "\xcc\x03" |
||||||
|
|
||||||
|
def test_add_privkeys(): |
||||||
|
with pytest.raises(Exception) as e_info: |
||||||
|
btc.add_privkeys("aa"*32, "bb"*32+"01", True) |
||||||
|
|
||||||
|
def test_ecdsa_raw_sign(): |
||||||
|
msg = "aa"*31 |
||||||
|
with pytest.raises(Exception) as e_info: |
||||||
|
btc.ecdsa_raw_sign(msg, None, None, rawmsg=True) |
||||||
|
assert e_info.match("Invalid hash input") |
||||||
|
#build non-raw priv object as input |
||||||
|
privraw = "aa"*32 |
||||||
|
msghash = "\xbb"*32 |
||||||
|
sig = binascii.hexlify(btc.ecdsa_raw_sign(msghash, privraw, False, rawpriv=False, rawmsg=True)) |
||||||
|
assert sig == "3045022100b81960b4969b423199dea555f562a66b7f49dea5836a0168361f1a5f8a3c8298022003eea7d7ee4462e3e9d6d59220f950564caeb77f7b1cdb42af3c83b013ff3b2f" |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,6 +0,0 @@ |
|||||||
# .coveragerc to control coverage.py |
|
||||||
[run] |
|
||||||
omit = |
|
||||||
../jmclient/jsonrpc.py |
|
||||||
../jmclient/slowaes.py |
|
||||||
../jmclient/btc.py |
|
||||||
@ -0,0 +1,227 @@ |
|||||||
|
#! /usr/bin/env python |
||||||
|
from __future__ import absolute_import |
||||||
|
'''Test of unusual transaction types creation and push to |
||||||
|
network to check validity.''' |
||||||
|
|
||||||
|
import sys |
||||||
|
import os |
||||||
|
import time |
||||||
|
import binascii |
||||||
|
import random |
||||||
|
from commontest import make_wallets, make_sign_and_push |
||||||
|
|
||||||
|
import jmbitcoin as bitcoin |
||||||
|
import pytest |
||||||
|
from jmclient import (load_program_config, jm_single, sync_wallet, |
||||||
|
get_p2pk_vbyte, get_log, Wallet, select_gradual, |
||||||
|
select, select_greedy, select_greediest, estimate_tx_fee) |
||||||
|
|
||||||
|
log = get_log() |
||||||
|
#just a random selection of pubkeys for receiving multisigs; |
||||||
|
#if we ever need the privkeys, they are in a json file somewhere |
||||||
|
vpubs = ["03e9a06e539d6bf5cf1ca5c41b59121fa3df07a338322405a312c67b6349a707e9", |
||||||
|
"0280125e42c1984923106e281615dfada44d38c4125c005963b322427110d709d6", |
||||||
|
"02726fa5b19e9406aaa46ee22fd9e81a09dd5eb7c87505b93a11efcf4b945e778c", |
||||||
|
"03600a739be32a14938680b3b3d61b51f217a60df118160d0decab22c9e1329862", |
||||||
|
"028a2f126e3999ff66d01dcb101ab526d3aa1bf5cbdc4bde14950a4cead95f6fcb", |
||||||
|
"02bea84d70e74f7603746b62d79bf035e16d982b56e6a1ee07dfd3b9130e8a2ad9"] |
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize( |
||||||
|
"nw, wallet_structures, mean_amt, sdev_amt, amount, pubs, k", [ |
||||||
|
(1, [[2, 1, 4, 0, 0]], 4, 1.4, 600000000, vpubs[1:4], 2), |
||||||
|
(1, [[3, 3, 0, 0, 3]], 4, 1.4, 100000000, vpubs[:4], 3), |
||||||
|
]) |
||||||
|
def test_create_p2sh_output_tx(setup_tx_creation, nw, wallet_structures, |
||||||
|
mean_amt, sdev_amt, amount, pubs, k): |
||||||
|
wallets = make_wallets(nw, wallet_structures, mean_amt, sdev_amt) |
||||||
|
for w in wallets.values(): |
||||||
|
sync_wallet(w['wallet']) |
||||||
|
for k, w in enumerate(wallets.values()): |
||||||
|
wallet = w['wallet'] |
||||||
|
ins_full = wallet.select_utxos(0, amount) |
||||||
|
script = bitcoin.mk_multisig_script(pubs, k) |
||||||
|
#try the alternative argument passing |
||||||
|
pubs.append(k) |
||||||
|
script2 = bitcoin.mk_multisig_script(*pubs) |
||||||
|
assert script2 == script |
||||||
|
output_addr = bitcoin.scriptaddr(script, magicbyte=196) |
||||||
|
txid = make_sign_and_push(ins_full, |
||||||
|
wallet, |
||||||
|
amount, |
||||||
|
output_addr=output_addr) |
||||||
|
assert txid |
||||||
|
|
||||||
|
def test_script_to_address(setup_tx_creation): |
||||||
|
sample_script = "a914307f099a3bfedec9a09682238db491bade1b467f87" |
||||||
|
assert bitcoin.script_to_address( |
||||||
|
sample_script) == "367SYUMqo1Fi4tQsycnmCtB6Ces1Z7EZLH" |
||||||
|
assert bitcoin.script_to_address( |
||||||
|
sample_script, vbyte=196) == "2MwfecDHsQTm4Gg3RekQdpqAMR15BJrjfRF" |
||||||
|
|
||||||
|
def test_mktx(setup_tx_creation): |
||||||
|
"""Testing exceptional conditions; not guaranteed |
||||||
|
to create valid tx objects""" |
||||||
|
#outpoint structure must be {"outpoint":{"hash":hash, "index": num}} |
||||||
|
ins = [{'outpoint': {"hash":x*32, "index":0}, |
||||||
|
"script": "", "sequence": 4294967295} for x in ["a", "b", "c"]] |
||||||
|
pub = vpubs[0] |
||||||
|
addr = bitcoin.pubkey_to_address(pub, magicbyte=get_p2pk_vbyte()) |
||||||
|
script = bitcoin.address_to_script(addr) |
||||||
|
outs = [script + ":1000", addr+":2000",{"script":script, "value":3000}] |
||||||
|
tx = bitcoin.mktx(ins, outs) |
||||||
|
print(tx) |
||||||
|
#rewrite with invalid output |
||||||
|
outs.append({"foo": "bar"}) |
||||||
|
with pytest.raises(Exception) as e_info: |
||||||
|
tx = bitcoin.mktx(ins, outs) |
||||||
|
|
||||||
|
def test_bintxhash(setup_tx_creation): |
||||||
|
tx = "abcd" |
||||||
|
x = bitcoin.bin_txhash(tx) |
||||||
|
assert binascii.hexlify(x) == "943cbb9637d9b16b92529b182ed0257ec729afc897ac0522b2ed2a86f6809917" |
||||||
|
|
||||||
|
def test_all_same_priv(setup_tx_creation): |
||||||
|
#recipient |
||||||
|
priv = "aa"*32 + "01" |
||||||
|
addr = bitcoin.privkey_to_address(priv, magicbyte=get_p2pk_vbyte()) |
||||||
|
wallet = make_wallets(1, [[1,0,0,0,0]], 1)[0]['wallet'] |
||||||
|
#make another utxo on the same address |
||||||
|
addrinwallet = wallet.get_addr(0,0,0) |
||||||
|
jm_single().bc_interface.grab_coins(addrinwallet, 1) |
||||||
|
sync_wallet(wallet) |
||||||
|
insfull = wallet.select_utxos(0, 110000000) |
||||||
|
outs = [{"address": addr, "value": 1000000}] |
||||||
|
ins = insfull.keys() |
||||||
|
tx = bitcoin.mktx(ins, outs) |
||||||
|
tx = bitcoin.signall(tx, wallet.get_key_from_addr(addrinwallet)) |
||||||
|
|
||||||
|
@pytest.mark.parametrize( |
||||||
|
"signall, mktxlist", |
||||||
|
[ |
||||||
|
(True, False), |
||||||
|
(False, True), |
||||||
|
]) |
||||||
|
def test_verify_tx_input(setup_tx_creation, signall, mktxlist): |
||||||
|
priv = "aa"*32 + "01" |
||||||
|
addr = bitcoin.privkey_to_address(priv, magicbyte=get_p2pk_vbyte()) |
||||||
|
wallet = make_wallets(1, [[2,0,0,0,0]], 1)[0]['wallet'] |
||||||
|
sync_wallet(wallet) |
||||||
|
insfull = wallet.select_utxos(0, 110000000) |
||||||
|
print(insfull) |
||||||
|
if not mktxlist: |
||||||
|
outs = [{"address": addr, "value": 1000000}] |
||||||
|
ins = insfull.keys() |
||||||
|
tx = bitcoin.mktx(ins, outs) |
||||||
|
else: |
||||||
|
out1 = addr+":1000000" |
||||||
|
ins0, ins1 = insfull.keys() |
||||||
|
print("INS0 is: " + str(ins0)) |
||||||
|
print("INS1 is: " + str(ins1)) |
||||||
|
tx = bitcoin.mktx(ins0, ins1, out1) |
||||||
|
desertx = bitcoin.deserialize(tx) |
||||||
|
print(desertx) |
||||||
|
if signall: |
||||||
|
privdict = {} |
||||||
|
for index, ins in enumerate(desertx['ins']): |
||||||
|
utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) |
||||||
|
ad = insfull[utxo]['address'] |
||||||
|
priv = wallet.get_key_from_addr(ad) |
||||||
|
privdict[utxo] = priv |
||||||
|
tx = bitcoin.signall(tx, privdict) |
||||||
|
else: |
||||||
|
for index, ins in enumerate(desertx['ins']): |
||||||
|
utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) |
||||||
|
ad = insfull[utxo]['address'] |
||||||
|
priv = wallet.get_key_from_addr(ad) |
||||||
|
if index % 2: |
||||||
|
tx = binascii.unhexlify(tx) |
||||||
|
tx = bitcoin.sign(tx, index, priv) |
||||||
|
if index % 2: |
||||||
|
tx = binascii.hexlify(tx) |
||||||
|
desertx2 = bitcoin.deserialize(tx) |
||||||
|
print(desertx2) |
||||||
|
sig, pub = bitcoin.deserialize_script(desertx2['ins'][0]['script']) |
||||||
|
print(sig, pub) |
||||||
|
pubscript = bitcoin.address_to_script(bitcoin.pubkey_to_address( |
||||||
|
pub, magicbyte=get_p2pk_vbyte())) |
||||||
|
sig = binascii.unhexlify(sig) |
||||||
|
pub = binascii.unhexlify(pub) |
||||||
|
sig_good = bitcoin.verify_tx_input(tx, 0, pubscript, |
||||||
|
sig, pub) |
||||||
|
assert sig_good |
||||||
|
|
||||||
|
def test_absurd_fees(setup_tx_creation): |
||||||
|
"""Test triggering of ValueError exception |
||||||
|
if the transaction fees calculated from the blockchain |
||||||
|
interface exceed the limit set in the config. |
||||||
|
""" |
||||||
|
jm_single().bc_interface.absurd_fees = True |
||||||
|
#pay into it |
||||||
|
wallet = make_wallets(1, [[2, 0, 0, 0, 1]], 3)[0]['wallet'] |
||||||
|
sync_wallet(wallet) |
||||||
|
amount = 350000000 |
||||||
|
ins_full = wallet.select_utxos(0, amount) |
||||||
|
with pytest.raises(ValueError) as e_info: |
||||||
|
txid = make_sign_and_push(ins_full, wallet, amount, estimate_fee=True) |
||||||
|
|
||||||
|
def test_create_sighash_txs(setup_tx_creation): |
||||||
|
#non-standard hash codes: |
||||||
|
for sighash in [bitcoin.SIGHASH_ANYONECANPAY + bitcoin.SIGHASH_SINGLE, |
||||||
|
bitcoin.SIGHASH_NONE, bitcoin.SIGHASH_SINGLE]: |
||||||
|
wallet = make_wallets(1, [[2, 0, 0, 0, 1]], 3)[0]['wallet'] |
||||||
|
sync_wallet(wallet) |
||||||
|
amount = 350000000 |
||||||
|
ins_full = wallet.select_utxos(0, amount) |
||||||
|
print "using hashcode: " + str(sighash) |
||||||
|
txid = make_sign_and_push(ins_full, wallet, amount, hashcode=sighash) |
||||||
|
assert txid |
||||||
|
|
||||||
|
#Create an invalid sighash single (too many inputs) |
||||||
|
extra = wallet.select_utxos(4, 100000000) #just a few more inputs |
||||||
|
ins_full.update(extra) |
||||||
|
with pytest.raises(Exception) as e_info: |
||||||
|
txid = make_sign_and_push(ins_full, |
||||||
|
wallet, |
||||||
|
amount, |
||||||
|
hashcode=bitcoin.SIGHASH_SINGLE) |
||||||
|
|
||||||
|
#trigger insufficient funds |
||||||
|
with pytest.raises(Exception) as e_info: |
||||||
|
fake_utxos = wallet.select_utxos(4, 1000000000) |
||||||
|
|
||||||
|
|
||||||
|
def test_spend_p2sh_utxos(setup_tx_creation): |
||||||
|
#make a multisig address from 3 privs |
||||||
|
privs = [chr(x) * 32 + '\x01' for x in range(1, 4)] |
||||||
|
pubs = [bitcoin.privkey_to_pubkey(binascii.hexlify(priv)) for priv in privs] |
||||||
|
script = bitcoin.mk_multisig_script(pubs, 2) |
||||||
|
msig_addr = bitcoin.scriptaddr(script, magicbyte=196) |
||||||
|
#pay into it |
||||||
|
wallet = make_wallets(1, [[2, 0, 0, 0, 1]], 3)[0]['wallet'] |
||||||
|
sync_wallet(wallet) |
||||||
|
amount = 350000000 |
||||||
|
ins_full = wallet.select_utxos(0, amount) |
||||||
|
txid = make_sign_and_push(ins_full, wallet, amount, output_addr=msig_addr) |
||||||
|
assert txid |
||||||
|
#wait for mining |
||||||
|
time.sleep(4) |
||||||
|
#spend out; the input can be constructed from the txid of previous |
||||||
|
msig_in = txid + ":0" |
||||||
|
ins = [msig_in] |
||||||
|
#random output address and change addr |
||||||
|
output_addr = wallet.get_new_addr(1, 1) |
||||||
|
amount2 = amount - 50000 |
||||||
|
outs = [{'value': amount2, 'address': output_addr}] |
||||||
|
tx = bitcoin.mktx(ins, outs) |
||||||
|
sigs = [] |
||||||
|
for priv in privs[:2]: |
||||||
|
sigs.append(bitcoin.multisign(tx, 0, script, binascii.hexlify(priv))) |
||||||
|
tx = bitcoin.apply_multisignatures(tx, 0, script, sigs) |
||||||
|
txid = jm_single().bc_interface.pushtx(tx) |
||||||
|
assert txid |
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module") |
||||||
|
def setup_tx_creation(): |
||||||
|
load_program_config() |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
# content of pytest.ini |
||||||
|
[tool:pytest] |
||||||
|
norecursedirs = test/* |
||||||
|
testpaths = jmbitcoin jmclient jmbase |
||||||
@ -1,168 +0,0 @@ |
|||||||
#! /usr/bin/env python |
|
||||||
from __future__ import absolute_import |
|
||||||
'''Some helper functions for testing''' |
|
||||||
|
|
||||||
import sys |
|
||||||
import os |
|
||||||
import time |
|
||||||
import binascii |
|
||||||
import pexpect |
|
||||||
import random |
|
||||||
import subprocess |
|
||||||
import platform |
|
||||||
from decimal import Decimal |
|
||||||
|
|
||||||
data_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) |
|
||||||
sys.path.insert(0, os.path.join(data_dir)) |
|
||||||
|
|
||||||
from joinmarket import jm_single, Wallet, get_log |
|
||||||
from joinmarket.support import chunks |
|
||||||
from joinmarket.wallet import estimate_tx_fee |
|
||||||
import bitcoin as btc |
|
||||||
|
|
||||||
log = get_log() |
|
||||||
'''This code is intended to provide |
|
||||||
subprocess startup cross-platform with |
|
||||||
some useful options; it could do with |
|
||||||
some simplification/improvement.''' |
|
||||||
import platform |
|
||||||
OS = platform.system() |
|
||||||
PINL = '\r\n' if OS == 'Windows' else '\n' |
|
||||||
|
|
||||||
class TestWallet(Wallet): |
|
||||||
"""Implementation of wallet |
|
||||||
that allows passing in a password |
|
||||||
for removal of command line interrupt. |
|
||||||
""" |
|
||||||
|
|
||||||
def __init__(self, |
|
||||||
seedarg, |
|
||||||
max_mix_depth=2, |
|
||||||
gaplimit=6, |
|
||||||
extend_mixdepth=False, |
|
||||||
storepassword=False, |
|
||||||
pwd=None): |
|
||||||
self.given_pwd = pwd |
|
||||||
super(TestWallet, self).__init__(seedarg, |
|
||||||
max_mix_depth, |
|
||||||
gaplimit, |
|
||||||
extend_mixdepth, |
|
||||||
storepassword) |
|
||||||
|
|
||||||
def read_wallet_file_data(self, filename): |
|
||||||
return super(TestWallet, self).read_wallet_file_data( |
|
||||||
filename, self.given_pwd) |
|
||||||
|
|
||||||
def make_sign_and_push(ins_full, |
|
||||||
wallet, |
|
||||||
amount, |
|
||||||
output_addr=None, |
|
||||||
change_addr=None, |
|
||||||
hashcode=btc.SIGHASH_ALL, |
|
||||||
estimate_fee = False): |
|
||||||
"""Utility function for easily building transactions |
|
||||||
from wallets |
|
||||||
""" |
|
||||||
total = sum(x['value'] for x in ins_full.values()) |
|
||||||
ins = ins_full.keys() |
|
||||||
#random output address and change addr |
|
||||||
output_addr = wallet.get_new_addr(1, 1) if not output_addr else output_addr |
|
||||||
change_addr = wallet.get_new_addr(1, 0) if not change_addr else change_addr |
|
||||||
fee_est = estimate_tx_fee(len(ins), 2) if estimate_fee else 10000 |
|
||||||
outs = [{'value': amount, |
|
||||||
'address': output_addr}, {'value': total - amount - fee_est, |
|
||||||
'address': change_addr}] |
|
||||||
|
|
||||||
tx = btc.mktx(ins, outs) |
|
||||||
de_tx = btc.deserialize(tx) |
|
||||||
for index, ins in enumerate(de_tx['ins']): |
|
||||||
utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index']) |
|
||||||
addr = ins_full[utxo]['address'] |
|
||||||
priv = wallet.get_key_from_addr(addr) |
|
||||||
if index % 2: |
|
||||||
priv = binascii.unhexlify(priv) |
|
||||||
tx = btc.sign(tx, index, priv, hashcode=hashcode) |
|
||||||
#pushtx returns False on any error |
|
||||||
print btc.deserialize(tx) |
|
||||||
push_succeed = jm_single().bc_interface.pushtx(tx) |
|
||||||
if push_succeed: |
|
||||||
return btc.txhash(tx) |
|
||||||
else: |
|
||||||
return False |
|
||||||
|
|
||||||
def local_command(command, bg=False, redirect=''): |
|
||||||
if redirect == 'NULL': |
|
||||||
if OS == 'Windows': |
|
||||||
command.append(' > NUL 2>&1') |
|
||||||
elif OS == 'Linux': |
|
||||||
command.extend(['>', '/dev/null', '2>&1']) |
|
||||||
else: |
|
||||||
print "OS not recognised, quitting." |
|
||||||
elif redirect: |
|
||||||
command.extend(['>', redirect]) |
|
||||||
|
|
||||||
if bg: |
|
||||||
#using subprocess.PIPE seems to cause problems |
|
||||||
FNULL = open(os.devnull, 'w') |
|
||||||
return subprocess.Popen(command, |
|
||||||
stdout=FNULL, |
|
||||||
stderr=subprocess.STDOUT, |
|
||||||
close_fds=True) |
|
||||||
else: |
|
||||||
#in case of foreground execution, we can use the output; if not |
|
||||||
#it doesn't matter |
|
||||||
return subprocess.check_output(command) |
|
||||||
|
|
||||||
|
|
||||||
def make_wallets(n, |
|
||||||
wallet_structures=None, |
|
||||||
mean_amt=1, |
|
||||||
sdev_amt=0, |
|
||||||
start_index=0, |
|
||||||
fixed_seeds=None, |
|
||||||
test_wallet=False, |
|
||||||
passwords=None): |
|
||||||
'''n: number of wallets to be created |
|
||||||
wallet_structure: array of n arrays , each subarray |
|
||||||
specifying the number of addresses to be populated with coins |
|
||||||
at each depth (for now, this will only populate coins into 'receive' addresses) |
|
||||||
mean_amt: the number of coins (in btc units) in each address as above |
|
||||||
sdev_amt: if randomness in amouts is desired, specify here. |
|
||||||
Returns: a dict of dicts of form {0:{'seed':seed,'wallet':Wallet object},1:..,} |
|
||||||
Default Wallet constructor is joinmarket.Wallet, else use TestWallet, |
|
||||||
which takes a password parameter as in the list passwords. |
|
||||||
''' |
|
||||||
if len(wallet_structures) != n: |
|
||||||
raise Exception("Number of wallets doesn't match wallet structures") |
|
||||||
if not fixed_seeds: |
|
||||||
seeds = chunks(binascii.hexlify(os.urandom(15 * n)), 15 * 2) |
|
||||||
else: |
|
||||||
seeds = fixed_seeds |
|
||||||
wallets = {} |
|
||||||
for i in range(n): |
|
||||||
if test_wallet: |
|
||||||
w = TestWallet(seeds[i], max_mix_depth=5, pwd=passwords[i]) |
|
||||||
else: |
|
||||||
w = Wallet(seeds[i], max_mix_depth=5) |
|
||||||
wallets[i + start_index] = {'seed': seeds[i], |
|
||||||
'wallet': w} |
|
||||||
for j in range(5): |
|
||||||
for k in range(wallet_structures[i][j]): |
|
||||||
deviation = sdev_amt * random.random() |
|
||||||
amt = mean_amt - sdev_amt / 2.0 + deviation |
|
||||||
if amt < 0: amt = 0.001 |
|
||||||
amt = float(Decimal(amt).quantize(Decimal(10)**-8)) |
|
||||||
jm_single().bc_interface.grab_coins( |
|
||||||
wallets[i + start_index]['wallet'].get_external_addr(j), |
|
||||||
amt) |
|
||||||
#reset the index so the coins can be seen if running in same script |
|
||||||
wallets[i + start_index]['wallet'].index[j][0] -= wallet_structures[i][j] |
|
||||||
return wallets |
|
||||||
|
|
||||||
|
|
||||||
def interact(process, inputs, expected): |
|
||||||
if len(inputs) != len(expected): |
|
||||||
raise Exception("Invalid inputs to interact()") |
|
||||||
for i, inp in enumerate(inputs): |
|
||||||
process.expect(expected[i]) |
|
||||||
process.sendline(inp) |
|
||||||
@ -1,76 +0,0 @@ |
|||||||
import pytest |
|
||||||
import os |
|
||||||
import time |
|
||||||
import subprocess |
|
||||||
from commontest import local_command |
|
||||||
from joinmarket import load_program_config |
|
||||||
|
|
||||||
bitcoin_path = None |
|
||||||
bitcoin_conf = None |
|
||||||
bitcoin_rpcpassword = None |
|
||||||
bitcoin_rpcusername = None |
|
||||||
miniircd_procs = [] |
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser): |
|
||||||
parser.addoption("--btcroot", action="store", default='', |
|
||||||
help="the fully qualified path to the directory containing "+\ |
|
||||||
"the bitcoin binaries, e.g. /home/user/bitcoin/bin/") |
|
||||||
parser.addoption("--btcconf", action="store", |
|
||||||
help="the fully qualified path to the location of the "+\ |
|
||||||
"bitcoin configuration file you use for testing, e.g. "+\ |
|
||||||
"/home/user/.bitcoin/bitcoin.conf") |
|
||||||
parser.addoption("--btcpwd", |
|
||||||
action="store", |
|
||||||
help="the RPC password for your test bitcoin instance") |
|
||||||
parser.addoption("--btcuser", |
|
||||||
action="store", |
|
||||||
default='bitcoinrpc', |
|
||||||
help="the RPC username for your test bitcoin instance (default=bitcoinrpc)") |
|
||||||
parser.addoption("--nirc", |
|
||||||
type="int", |
|
||||||
action="store", |
|
||||||
default=1, |
|
||||||
help="the number of local miniircd instances") |
|
||||||
|
|
||||||
def teardown(): |
|
||||||
#didn't find a stop command in miniircd, so just kill |
|
||||||
global miniircd_procs |
|
||||||
for m in miniircd_procs: |
|
||||||
m.kill() |
|
||||||
|
|
||||||
#shut down bitcoin and remove the regtest dir |
|
||||||
local_command([bitcoin_path + "bitcoin-cli", "-regtest", "-rpcuser=" + bitcoin_rpcusername, |
|
||||||
"-rpcpassword=" + bitcoin_rpcpassword, "stop"]) |
|
||||||
#note, it is better to clean out ~/.bitcoin/regtest but too |
|
||||||
#dangerous to automate it here perhaps |
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session", autouse=True) |
|
||||||
def setup(request): |
|
||||||
request.addfinalizer(teardown) |
|
||||||
|
|
||||||
global bitcoin_conf, bitcoin_path, bitcoin_rpcpassword, bitcoin_rpcusername |
|
||||||
bitcoin_path = request.config.getoption("--btcroot") |
|
||||||
bitcoin_conf = request.config.getoption("--btcconf") |
|
||||||
bitcoin_rpcpassword = request.config.getoption("--btcpwd") |
|
||||||
bitcoin_rpcusername = request.config.getoption("--btcuser") |
|
||||||
|
|
||||||
#start up miniircd |
|
||||||
#minor bug in miniircd (seems); need *full* unqualified path for motd file |
|
||||||
cwd = os.getcwd() |
|
||||||
n_irc = request.config.getoption("--nirc") |
|
||||||
global miniircd_procs |
|
||||||
for i in range(n_irc): |
|
||||||
miniircd_proc = local_command( |
|
||||||
["./miniircd/miniircd", "--ports=" + str(6667+i), |
|
||||||
"--motd=" + cwd + "/miniircd/testmotd"], |
|
||||||
bg=True) |
|
||||||
miniircd_procs.append(miniircd_proc) |
|
||||||
#start up regtest blockchain |
|
||||||
btc_proc = subprocess.call([bitcoin_path + "bitcoind", "-regtest", |
|
||||||
"-daemon", "-conf=" + bitcoin_conf]) |
|
||||||
time.sleep(3) |
|
||||||
#generate blocks |
|
||||||
local_command([bitcoin_path + "bitcoin-cli", "-regtest", "-rpcuser=" + bitcoin_rpcusername, |
|
||||||
"-rpcpassword=" + bitcoin_rpcpassword, "generate", "101"]) |
|
||||||
Loading…
Reference in new issue