Browse Source

Replaces test_full_coinjoin with test_e2e_coinjoin

The former was a stale test that we never got to a properly
working state, so we replace it with test/e2e-coinjoin-test.py
which does the same job more effectively, using the RPC-API.
Also removed the old file from parameters of run_tests script.
master
Adam Gibson 4 years ago
parent
commit
3b3bd39597
No known key found for this signature in database
GPG Key ID: 141001A1AF77F20B
  1. 2
      docs/TESTING.md
  2. 3
      test/run_tests.sh
  3. 21
      test/test_e2e_coinjoin.py
  4. 147
      test/test_full_coinjoin.py
  5. 3
      test/ygrunner.py

2
docs/TESTING.md

@ -25,7 +25,7 @@ Then copy the `regtest_joinmarket.cfg` file from the `test/` directory to the `j
Run the test suite via pytest: Run the test suite via pytest:
(jmvenv)$ pytest --btcconf=/path/to/bitcoin.conf --btcroot=/path/to/bitcoin/bin/ --btcpwd=123456abcdef --nirc=2 --ignore test/test_full_coinjoin.py -p no:warnings (jmvenv)$ pytest --btcconf=/path/to/bitcoin.conf --btcroot=/path/to/bitcoin/bin/ --btcpwd=123456abcdef --nirc=2 -p no:warnings
#### Running tests of sendpayment and tumbler (including with malicious makers) #### Running tests of sendpayment and tumbler (including with malicious makers)

3
test/run_tests.sh

@ -222,8 +222,7 @@ run_jm_tests ()
--btcroot=$btcroot \ --btcroot=$btcroot \
--btcuser=$btcuser \ --btcuser=$btcuser \
--nirc=$nirc \ --nirc=$nirc \
-p no:warnings \ -p no:warnings
--ignore test/test_full_coinjoin.py
local success="$?" local success="$?"
[[ -f ./joinmarket.cfg ]] && unlink ./joinmarket.cfg [[ -f ./joinmarket.cfg ]] && unlink ./joinmarket.cfg
if [ -f "${jm_test_datadir}/bitcoind.pid" ] && read bitcoind_pid <"${jm_test_datadir}/bitcoind.pid"; then if [ -f "${jm_test_datadir}/bitcoind.pid" ] && read bitcoind_pid <"${jm_test_datadir}/bitcoind.pid"; then

21
test/e2e-coinjoin-test.py → test/test_e2e_coinjoin.py

@ -24,19 +24,11 @@ from jmbase import (get_nontor_agent, BytesProducer, jmprint,
from jmclient import (YieldGeneratorBasic, load_test_config, jm_single, from jmclient import (YieldGeneratorBasic, load_test_config, jm_single,
JMClientProtocolFactory, start_reactor, SegwitWallet, get_mchannels, JMClientProtocolFactory, start_reactor, SegwitWallet, get_mchannels,
SegwitLegacyWallet, JMWalletDaemon) SegwitLegacyWallet, JMWalletDaemon)
import jmclient
from jmclient.wallet_rpc import api_version_string from jmclient.wallet_rpc import api_version_string
log = get_log() log = get_log()
# For quicker testing, restrict the range of timelock
# addresses to avoid slow load of multiple bots.
# Note: no need to revert this change as test runs
# in isolation.
from jmclient import FidelityBondMixin
FidelityBondMixin.TIMELOCK_ERA_YEARS = 2
FidelityBondMixin.TIMELOCK_EPOCH_YEAR = datetime.now().year
FidelityBondMixin.TIMENUMBERS_PER_PUBKEY = 12
wallet_name = "test-onion-yg-runner.jmdat" wallet_name = "test-onion-yg-runner.jmdat"
mean_amt = 2.0 mean_amt = 2.0
@ -196,8 +188,7 @@ def test_start_yg_and_taker_setup(setup_onion_ygrunner):
wallet_service = wallet_services[end_bot_num - 1]['wallet'] wallet_service = wallet_services[end_bot_num - 1]['wallet']
jmprint("\n\nTaker wallet seed : " + wallet_services[end_bot_num - 1]['seed']) jmprint("\n\nTaker wallet seed : " + wallet_services[end_bot_num - 1]['seed'])
# for manual audit if necessary, show the maker's wallet seeds # for manual audit if necessary, show the maker's wallet seeds
# also (note this audit should be automated in future, see # also (note this audit should be automated in future)
# test_full_coinjoin.py in this directory)
jmprint("\n\nMaker wallet seeds: ") jmprint("\n\nMaker wallet seeds: ")
for i in range(start_bot_num, end_bot_num): for i in range(start_bot_num, end_bot_num):
jmprint("Maker seed: " + wallet_services[i - 1]['seed']) jmprint("Maker seed: " + wallet_services[i - 1]['seed'])
@ -331,8 +322,12 @@ def process_coinjoin_response(response):
json_body = json.loads(response.decode("utf-8")) json_body = json.loads(response.decode("utf-8"))
print("coinjoin response: {}".format(json_body)) print("coinjoin response: {}".format(json_body))
@pytest.fixture(scope="module") @pytest.fixture
def setup_onion_ygrunner(): def setup_onion_ygrunner(monkeypatch):
# For quicker testing, restrict the range of timelock
# addresses to avoid slow load of multiple bots.
monkeypatch.setattr(jmclient.FidelityBondMixin, 'TIMELOCK_ERA_YEARS', 2)
monkeypatch.setattr(jmclient.FidelityBondMixin, 'TIMELOCK_EPOCH_YEAR', datetime.now().year)
load_test_config() load_test_config()
jm_single().bc_interface.tick_forward_chain_interval = 10 jm_single().bc_interface.tick_forward_chain_interval = 10
jm_single().bc_interface.simulate_blocks() jm_single().bc_interface.simulate_blocks()

147
test/test_full_coinjoin.py

@ -1,147 +0,0 @@
#! /usr/bin/env python
from __future__ import (absolute_import, division,
print_function, unicode_literals)
from builtins import * # noqa: F401
'''Runs a full joinmarket pit (using `nirc` miniircd servers,
with `nirc` options specified as an option to pytest),in
bitcoin regtest mode with 3 maker bots and 1 taker bot,
and does 1 coinjoin. This is intended as an E2E sanity check
but certainly could be extended further.
'''
from common import make_wallets
import pytest
import sys
from jmclient import YieldGeneratorBasic, load_test_config, jm_single,\
sync_wallet, JMClientProtocolFactory, start_reactor, Taker, \
random_under_max_order_choose
from jmbase.support import get_log
from twisted.internet import reactor
from twisted.python.log import startLogging
log = get_log()
# Note that this parametrization is inherited (i.e. copied) from
# the previous 'ygrunner.py' script which is intended to be run
# manually to test out complex scenarios. Here, we only run one
# simple test with honest makers (and for simplicity malicious
# makers are not included in the code). Vars are left in in case
# we want to do more complex stuff in the automated tests later.
@pytest.mark.parametrize(
"num_ygs, wallet_structures, mean_amt, malicious, deterministic",
[
# 1sp 3yg, honest makers
(3, [[1, 3, 0, 0, 0]] * 4, 2, 0, False),
])
def test_cj(setup_full_coinjoin, num_ygs, wallet_structures, mean_amt,
malicious, deterministic):
"""Starts by setting up wallets for maker and taker bots; then,
instantiates a single taker with the final wallet.
The remaining wallets are used to set up YieldGenerators (basic form).
All the wallets are given coins according to the rules of make_wallets,
using the parameters for the values.
The final start_reactor call is the only one that actually starts the
reactor; the others only set up protocol instances.
Inline are custom callbacks for the Taker, and these are basically
copies of those in the `sendpayment.py` script for now, but they could
be customized later for testing.
The Taker's schedule is a single coinjoin, using basically random values,
again this could be easily edited or parametrized if we feel like it.
"""
# Set up some wallets, for the ygs and 1 sp.
wallets = make_wallets(num_ygs + 1,
wallet_structures=wallet_structures,
mean_amt=mean_amt)
#the sendpayment bot uses the last wallet in the list
wallet = wallets[num_ygs]['wallet']
sync_wallet(wallet, fast=True)
# grab a dest addr from the wallet
destaddr = wallet.get_external_addr(4)
coinjoin_amt = 20000000
schedule = [[1, coinjoin_amt, 2, destaddr,
0.0, False]]
""" The following two callback functions are as simple as possible
modifications of the same in scripts/sendpayment.py
"""
def filter_orders_callback(orders_fees, cjamount):
return True
def taker_finished(res, fromtx=False, waittime=0.0, txdetails=None):
def final_checks():
sync_wallet(wallet, fast=True)
newbal = wallet.get_balance_by_mixdepth()[4]
oldbal = wallet.get_balance_by_mixdepth()[1]
# These are our check that the coinjoin succeeded
assert newbal == coinjoin_amt
# TODO: parametrize these; cj fees = 38K (.001 x 20M x 2 makers)
# minus 1K tx fee contribution each; 600M is original balance
# in mixdepth 1
assert oldbal + newbal + (40000 - 2000) + taker.total_txfee == 600000000
if fromtx == "unconfirmed":
#If final entry, stop *here*, don't wait for confirmation
if taker.schedule_index + 1 == len(taker.schedule):
reactor.stop()
final_checks()
return
if fromtx:
# currently this test uses a schedule with only one entry
assert False, "taker_finished was called with fromtx=True"
reactor.stop()
return
else:
if not res:
assert False, "Did not complete successfully, shutting down"
# Note that this is required in both conditional branches,
# especially in testing, because it's possible to receive the
# confirmed callback before the unconfirmed.
reactor.stop()
final_checks()
# twisted logging is required for debugging:
startLogging(sys.stdout)
taker = Taker(wallet,
schedule,
order_chooser=random_under_max_order_choose,
max_cj_fee=(0.1, 200),
callbacks=(filter_orders_callback, None, taker_finished))
clientfactory = JMClientProtocolFactory(taker)
nodaemon = jm_single().config.getint("DAEMON", "no_daemon")
daemon = True if nodaemon == 1 else False
start_reactor(jm_single().config.get("DAEMON", "daemon_host"),
jm_single().config.getint("DAEMON", "daemon_port"),
clientfactory, daemon=daemon, rs=False)
txfee = 1000
cjfee_a = 4200
cjfee_r = '0.001'
ordertype = 'swreloffer'
minsize = 100000
ygclass = YieldGeneratorBasic
# As noted above, this is not currently used but can be in future:
if malicious or deterministic:
raise NotImplementedError
for i in range(num_ygs):
cfg = [txfee, cjfee_a, cjfee_r, ordertype, minsize]
sync_wallet(wallets[i]["wallet"], fast=True)
yg = ygclass(wallets[i]["wallet"], cfg)
if malicious:
yg.set_maliciousness(malicious, mtype="tx")
clientfactory = JMClientProtocolFactory(yg, proto_type="MAKER")
nodaemon = jm_single().config.getint("DAEMON", "no_daemon")
daemon = True if nodaemon == 1 else False
# As noted above, only the final start_reactor() call will
# actually start it!
rs = True if i == num_ygs - 1 else False
start_reactor(jm_single().config.get("DAEMON", "daemon_host"),
jm_single().config.getint("DAEMON", "daemon_port"),
clientfactory, daemon=daemon, rs=rs)
@pytest.fixture(scope="module")
def setup_full_coinjoin():
load_test_config()
jm_single().bc_interface.tick_forward_chain_interval = 10
jm_single().bc_interface.simulate_blocks()

3
test/ygrunner.py

@ -123,8 +123,7 @@ def test_start_ygs(setup_ygrunner, num_ygs, wallet_structures, fb_indices,
wallet_service = wallet_services[num_ygs]['wallet'] wallet_service = wallet_services[num_ygs]['wallet']
jmprint("\n\nTaker wallet seed : " + wallet_services[num_ygs]['seed']) jmprint("\n\nTaker wallet seed : " + wallet_services[num_ygs]['seed'])
# for manual audit if necessary, show the maker's wallet seeds # for manual audit if necessary, show the maker's wallet seeds
# also (note this audit should be automated in future, see # also (note this audit should be automated in future)
# test_full_coinjoin.py in this directory)
jmprint("\n\nMaker wallet seeds: ") jmprint("\n\nMaker wallet seeds: ")
for i in range(num_ygs): for i in range(num_ygs):
jmprint("Maker seed: " + wallet_services[i]['seed']) jmprint("Maker seed: " + wallet_services[i]['seed'])

Loading…
Cancel
Save