From 810242c460ce7659816ed59a04669baa2750c866 Mon Sep 17 00:00:00 2001 From: Adam Gibson Date: Fri, 28 Jul 2017 19:37:23 +0300 Subject: [PATCH] add malicious-yg to yg test runner --- docs/TESTING.md | 36 ++++++++++++++++++++++++++++++++++++ test/ygrunner.py | 44 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 72 insertions(+), 8 deletions(-) diff --git a/docs/TESTING.md b/docs/TESTING.md index af15489..c09dbb9 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -21,3 +21,39 @@ Running the test suite should be done like: (you'll first want to copy bitcoin.conf in the test/ directory to a place you choose, and copy the regtest_joinmarket.cfg file from the test/ directory to the root directory, both files will need minor edits for your btc configuration). + +### Running tests of sendpayment and tumbler (including with malicious makers) + +The file `test/ygrunner.py` provides the ability to spin up a set of yieldgenerator +bots against the local IRC instance with the local regtest blockchain. It can be +started with + + py.test --btcroot=/path/to/bitcoin/bin/ --btcpwd=123456abcdef --btcconf=/path/to/bitcoin.conf --nirc=2 test/ygrunner.py -s + +Here the `-s` flag is useful because it prints log output to the console. If you +keep the logging level at the default `INFO` only a minimum amount will come out, if +you want more then enter this into the `joinmarket.cfg` in the root directory: + + [LOGGING] + console_log_level = DEBUG + +It will print out a hex seed for a wallet you can use for tumble/sendpayment. Next, +go into the `scripts/` directory and make sure you have copied the `regtest_joinmarket.cfg` +file into that directory also, make any changes needed (like the LOGGING one above), +and run either sendpayment or tumbler with whatever parameters you choose. + +To change the parameters of the yieldgenerators you can edit the parametrization of +the function `test_start_ygs` in [this file](https://github.com/AdamISZ/joinmarket-clientserver/blob/master/test/ygrunner.py). + +There are two changes that may be of special interest: +* to change the number of yg +bots from e.g. 3 to 4, edit the first number in the parameter list entry to 3 and the +third entry to 4 (4 means three ygs plus one taker bot). + +* More advanced case: To make the yg bots selectively (randomly) malicious, edit the last entry from 0 to some non-zero +integer representing a percentage chance of rejection, both at the receive-auth +stage and the receive-tx stage. So if you set this to 20, it means there will be +a 20% chance of *each* yg bot rejecting the auth message and the tx message (both +20%). If you are running tumbler in adversarial conditions like that, consider +changing things like the taker_utxo_retries or adding external commitments with +the add-utxo tool so external commitments usage can be tested. diff --git a/test/ygrunner.py b/test/ygrunner.py index 53c8f89..b213670 100644 --- a/test/ygrunner.py +++ b/test/ygrunner.py @@ -1,5 +1,5 @@ #! /usr/bin/env python -from __future__ import absolute_import +from __future__ import absolute_import, print_function '''Creates wallets and yield generators in regtest. Provides seed for joinmarket-qt test. This should be run via pytest, even though @@ -17,17 +17,42 @@ import os import pytest import sys import time +import random from jmclient import (YieldGeneratorBasic, ygmain, load_program_config, jm_single, sync_wallet, JMClientProtocolFactory, start_reactor) +class MaliciousYieldGenerator(YieldGeneratorBasic): + """Overrides, randomly, some maker functions + to prevent taker continuing successfully (unless + they can complete-with-subset). + """ + def set_maliciousness(self, frac): + self.mfrac = frac + def on_auth_received(self, nick, offer, commitment, cr, amount, kphex): + if random.randint(1, 100) < self.mfrac: + print("Counterparty commitment rejected maliciously") + return (False,) + return super(MaliciousYieldGenerator, self).on_auth_received(nick, + offer, commitment, cr, amount, kphex) + def on_tx_received(self, nick, txhex, offerinfo): + if random.randint(1, 100) < self.mfrac: + print("Counterparty tx rejected maliciously") + return (False, "malicious tx rejection") + return super(MaliciousYieldGenerator, self).on_tx_received(nick, txhex, + offerinfo) + + @pytest.mark.parametrize( - "num_ygs, wallet_structures, mean_amt", + "num_ygs, wallet_structures, mean_amt, malicious", [ - # 1sp 3yg, 2 mixdepths, sweep from depth1 - (3, [[1, 3, 0, 0, 0]] * 4, 2), + # 1sp 3yg, honest makers + (3, [[1, 3, 0, 0, 0]] * 4, 2, 0), + # 1sp 3yg, malicious makers reject on auth and on tx 30% of time + #(4, [[1, 3, 0, 0, 0]] * 5, 2, 30), ]) -def test_start_ygs(setup_ygrunner, num_ygs, wallet_structures, mean_amt): +def test_start_ygs(setup_ygrunner, num_ygs, wallet_structures, mean_amt, + malicious): """Set up some wallets, for the ygs and 1 sp. Then start the ygs in background and publish the seed of the sp wallet for easy import into -qt @@ -37,20 +62,23 @@ 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 "Seed : " + wallets[num_ygs]['seed'] + print("Seed : " + wallets[num_ygs]['seed']) #useful to see the utxos on screen sometimes sync_wallet(wallet) - print wallet.unspent + print(wallet.unspent) txfee = 1000 cjfee_a = 4200 cjfee_r = '0.001' ordertype = 'swreloffer' minsize = 100000 + ygclass = MaliciousYieldGenerator if malicious else YieldGeneratorBasic for i in range(num_ygs): cfg = [txfee, cjfee_a, cjfee_r, ordertype, minsize] sync_wallet(wallets[i]["wallet"]) - yg = YieldGeneratorBasic(wallets[i]["wallet"], cfg) + yg = ygclass(wallets[i]["wallet"], cfg) + if malicious: + yg.set_maliciousness(malicious) clientfactory = JMClientProtocolFactory(yg, proto_type="MAKER") nodaemon = jm_single().config.getint("DAEMON", "no_daemon") daemon = True if nodaemon == 1 else False