You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

157 lines
6.4 KiB

#! /usr/bin/env python
'''Creates wallets and yield generators in regtest.
Provides seed for joinmarket-qt test.
This should be run via pytest, even though
it's NOT part of the test-suite, because that
makes it much easier to handle start up and
shut down of the environment.
Run it like:
PYTHONPATH=.:$PYTHONPATH pytest \
--btcroot=/path/to/bitcoin/bin/ \
--btcpwd=123456abcdef --btcconf=/blah/bitcoin.conf \
--nirc=2 -s test/ygrunner.py
'''
from common import make_wallets
import pytest
import random
from jmbase import jmprint
from jmclient import YieldGeneratorBasic, load_test_config, jm_single,\
JMClientProtocolFactory, start_reactor, SegwitWallet,\
SegwitLegacyWallet, cryptoengine
class MaliciousYieldGenerator(YieldGeneratorBasic):
"""Overrides, randomly, some maker functions
to prevent taker continuing successfully (unless
they can complete-with-subset).
"""
def set_maliciousness(self, frac, mtype=None):
self.authmal = False
self.txmal = False
if mtype == "tx":
self.txmal = True
elif mtype == "auth":
self.authmal = True
else:
self.txmal = True
self.authmal = True
self.mfrac = frac
def on_auth_received(self, nick, offer, commitment, cr, amount, kphex):
if self.authmal:
if random.randint(1, 100) < self.mfrac:
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:
jmprint("Counterparty tx rejected maliciously", "debug")
return (False, "malicious tx rejection")
return super(MaliciousYieldGenerator, self).on_tx_received(nick, txhex,
offerinfo)
class DeterministicMaliciousYieldGenerator(YieldGeneratorBasic):
"""Overrides, randomly chosen persistently, some maker functions
to prevent taker continuing successfully (unless
they can complete-with-subset).
"""
def set_maliciousness(self, frac, mtype=None):
self.authmal = False
self.txmal = False
if mtype == "tx":
if random.randint(1, 100) < frac:
self.txmal = True
elif mtype == "auth":
if random.randint(1, 100) < frac:
self.authmal = True
else:
if random.randint(1, 100) < frac:
self.txmal = True
self.authmal = True
def on_auth_received(self, nick, offer, commitment, cr, amount, kphex):
if self.authmal:
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:
jmprint("Counterparty tx rejected maliciously", "debug")
return (False, "malicious tx rejection")
return super(DeterministicMaliciousYieldGenerator, self).on_tx_received(nick, txhex,
offerinfo)
@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),
# 1sp 3yg, malicious makers reject on auth and on tx 30% of time
#(3, [[1, 3, 0, 0, 0]] * 4, 2, 30, False),
# 1 sp 9 ygs, deterministically malicious 50% of time
#(9, [[1, 3, 0, 0, 0]] * 10, 2, 50, True),
])
def test_start_ygs(setup_ygrunner, num_ygs, wallet_structures, mean_amt,
malicious, deterministic):
"""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
"""
if jm_single().config.get("POLICY", "native") == "true":
walletclass = SegwitWallet
else:
# TODO add Legacy
walletclass = SegwitLegacyWallet
wallet_services = make_wallets(num_ygs + 1,
wallet_structures=wallet_structures,
mean_amt=mean_amt,
walletclass=walletclass)
#the sendpayment bot uses the last wallet in the list
wallet_service = wallet_services[num_ygs]['wallet']
jmprint("\n\nTaker wallet seed : " + wallet_services[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)
jmprint("\n\nMaker wallet seeds: ")
for i in range(num_ygs):
jmprint("Maker seed: " + wallet_services[i]['seed'])
jmprint("\n")
wallet_service.sync_wallet(fast=True)
txfee = 1000
cjfee_a = 4200
cjfee_r = '0.001'
ordertype = 'swreloffer'
minsize = 100000
ygclass = YieldGeneratorBasic
if malicious:
if deterministic:
ygclass = DeterministicMaliciousYieldGenerator
else:
ygclass = MaliciousYieldGenerator
for i in range(num_ygs):
cfg = [txfee, cjfee_a, cjfee_r, ordertype, minsize]
wallet_service_yg = wallet_services[i]["wallet"]
wallet_service_yg.startService()
yg = ygclass(wallet_service_yg, 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
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_ygrunner():
load_test_config()
jm_single().bc_interface.tick_forward_chain_interval = 10
jm_single().bc_interface.simulate_blocks()
# handles the custom regtest hrp for bech32
cryptoengine.BTC_P2WPKH.VBYTE = 100