Browse Source

add tests cases for commitment sourcing

master
Adam Gibson 5 years ago
parent
commit
4e4b15b166
  1. 23
      jmclient/test/commontest.py
  2. 100
      jmclient/test/test_taker.py

23
jmclient/test/commontest.py

@ -36,6 +36,8 @@ class DummyBlockchainInterface(BlockchainInterface):
self.fake_query_results = None self.fake_query_results = None
self.qusfail = False self.qusfail = False
self.cbh = 1 self.cbh = 1
self.default_confs = 20
self.confs_for_qus = {}
def rpc(self, a, b): def rpc(self, a, b):
return None return None
@ -59,7 +61,16 @@ class DummyBlockchainInterface(BlockchainInterface):
def setQUSFail(self, state): def setQUSFail(self, state):
self.qusfail = state self.qusfail = state
def set_confs(self, confs_utxos):
# we hook specific confirmation results
# for specific utxos so that query_utxo_set
# can return a non-constant fake value.
self.confs_for_qus.update(confs_utxos)
def reset_confs(self):
self.confs_for_qus = {}
def query_utxo_set(self, txouts, includeconf=False): def query_utxo_set(self, txouts, includeconf=False):
if self.qusfail: if self.qusfail:
#simulate failure to find the utxo #simulate failure to find the utxo
@ -99,13 +110,17 @@ class DummyBlockchainInterface(BlockchainInterface):
return [{'value': 200000000, return [{'value': 200000000,
'address': addr, 'address': addr,
'script': scr, 'script': scr,
'confirms': 20}] 'confirms': self.default_confs}]
for t in txouts: for t in txouts:
result_dict = {'value': 10000000000, result_dict = {'value': 200000000,
'address': "mrcNu71ztWjAQA6ww9kHiW3zBWSQidHXTQ", 'address': "mrcNu71ztWjAQA6ww9kHiW3zBWSQidHXTQ",
'script': hextobin('76a91479b000887626b294a914501a4cd226b58b23598388ac')} 'script': hextobin('76a91479b000887626b294a914501a4cd226b58b23598388ac')}
if includeconf: if includeconf:
result_dict['confirms'] = 20 if t in self.confs_for_qus:
confs = self.confs_for_qus[t]
else:
confs = self.default_confs
result_dict['confirms'] = confs
result.append(result_dict) result.append(result_dict)
return result return result

100
jmclient/test/test_taker.py

@ -31,6 +31,7 @@ class DummyWallet(SegwitWallet):
super().initialize(storage, get_network(), max_mixdepth=5) super().initialize(storage, get_network(), max_mixdepth=5)
super().__init__(storage) super().__init__(storage)
self._add_utxos() self._add_utxos()
self.ex_utxos = {}
self.inject_addr_get_failure = False self.inject_addr_get_failure = False
def _add_utxos(self): def _add_utxos(self):
@ -43,6 +44,26 @@ class DummyWallet(SegwitWallet):
script = self._ENGINE.address_to_script(data['address']) script = self._ENGINE.address_to_script(data['address'])
self._script_map[script] = path self._script_map[script] = path
def add_extra_utxo(self, txid, index, value, md,
address="mrcNu71ztWjAQA6ww9kHiW3zBWSQidHXTQ",
i=0):
# note branch and index, path will be ignored in these test cases,
# the tree is not real.
# if we have extra utxos that have been added for some test,
# we will need to return a script and an address, although it
# won't be used; note we can't use base class get_utxos_by_mixdepth
# because the paths are fake.
if md not in self.ex_utxos:
self.ex_utxos[md] = {}
self.ex_utxos[md].update({(txid, index): {"mixdepth": md,
"address": address,
"value": value,
"script": self._ENGINE.address_to_script(address),
"path": (b'dummy', md, i)}})
def remove_extra_utxo(self, txid, index, md):
del self.ex_utxos[(txid, index)]
def get_utxos_by_mixdepth(self, include_disabled=False, verbose=True, def get_utxos_by_mixdepth(self, include_disabled=False, verbose=True,
includeheight=False): includeheight=False):
# utxostr conversion routines because taker_test_data uses hex: # utxostr conversion routines because taker_test_data uses hex:
@ -53,6 +74,8 @@ class DummyWallet(SegwitWallet):
retval[mixdepth][utxostr_to_utxo(utxo)[1]] = val retval[mixdepth][utxostr_to_utxo(utxo)[1]] = val
val["script"] = self._ENGINE.address_to_script(val['address']) val["script"] = self._ENGINE.address_to_script(val['address'])
val["path"] = (b'dummy', mixdepth, i) val["path"] = (b'dummy', mixdepth, i)
for md, u in self.ex_utxos.items():
retval[md].update(u)
return retval return retval
def select_utxos(self, mixdepth, amount, utxo_filter=None, select_fn=None, def select_utxos(self, mixdepth, amount, utxo_filter=None, select_fn=None,
@ -149,39 +172,88 @@ def test_filter_rejection(setup_taker):
assert not res[0] assert not res[0]
@pytest.mark.parametrize( @pytest.mark.parametrize(
"failquery, external", "mixdepth, cjamt, failquery, external, expected_success, amtpercent, age, mixdepth_extras",
[ [
(False, False), (0, 110000000, False, False, True, 0, 0, {}),
(True, False), (0, 110000000, True, False, True, 0, 0, {}),
(False, True), (0, 110000000, False, True, True, 0, 0, {}),
# this will fail to source from mixdepth 1 just because 2 < 50% of 5.5:
(1, 550000000, False, False, False, 50, 5, {}),
# this must fail to source even though the size in mixdepth 0 is enough:
(1, 550000000, False, False, False, 50, 5, {0: [600000000]}),
# this should succeed in sourcing because even though there are 9 utxos
# in mixdepth 0, one of them is more than 20% (the original 2BTC):
(0, 900000000, False, False, True, 20, 5, {0:[100000000]*8}),
# this case must fail since the utxos are all at 20 confs and too new:
(0, 110000000, False, False, False, 20, 25, {}),
# make the confs in the spending mixdepth insufficient, while those
# in another mixdepth are OK; must fail:
(0, 110000000, False, False, False, 20, 5, {"confchange": {0: 1}}),
]) ])
def test_make_commitment(setup_taker, failquery, external): def test_make_commitment(setup_taker, mixdepth, cjamt, failquery, external,
expected_success, amtpercent, age, mixdepth_extras):
def clean_up(): def clean_up():
jm_single().config.set("POLICY", "taker_utxo_age", old_taker_utxo_age) jm_single().config.set("POLICY", "taker_utxo_age", old_taker_utxo_age)
jm_single().config.set("POLICY", "taker_utxo_amtpercent", old_taker_utxo_amtpercent) jm_single().config.set("POLICY", "taker_utxo_amtpercent", old_taker_utxo_amtpercent)
set_commitment_file(old_commitment_file) set_commitment_file(old_commitment_file)
jm_single().bc_interface.setQUSFail(False) jm_single().bc_interface.setQUSFail(False)
jm_single().bc_interface.reset_confs()
os.remove('dummyext') os.remove('dummyext')
old_commitment_file = get_commitment_file() old_commitment_file = get_commitment_file()
with open('dummyext', 'wb') as f: with open('dummyext', 'wb') as f:
f.write(json.dumps(t_dummy_ext, indent=4).encode('utf-8')) f.write(json.dumps(t_dummy_ext, indent=4).encode('utf-8'))
if external: if external:
set_commitment_file('dummyext') set_commitment_file('dummyext')
# define the appropriate podle acceptance parameters in the global config:
old_taker_utxo_age = jm_single().config.get("POLICY", "taker_utxo_age") old_taker_utxo_age = jm_single().config.get("POLICY", "taker_utxo_age")
old_taker_utxo_amtpercent = jm_single().config.get("POLICY", "taker_utxo_amtpercent") old_taker_utxo_amtpercent = jm_single().config.get("POLICY", "taker_utxo_amtpercent")
jm_single().config.set("POLICY", "taker_utxo_age", "5") if expected_success:
jm_single().config.set("POLICY", "taker_utxo_amtpercent", "20") # set to defaults for mainnet
mixdepth = 0 newtua = "5"
amount = 110000000 newtuap = "20"
taker = get_taker([(mixdepth, amount, 3, "mnsquzxrHXpFsZeL42qwbKdCP2y1esN3qw", NO_ROUNDING)]) else:
taker.cjamount = amount newtua = str(age)
taker.input_utxos = convert_utxos(t_utxos_by_mixdepth[0]) newtuap = str(amtpercent)
jm_single().config.set("POLICY", "taker_utxo_age", newtua)
jm_single().config.set("POLICY", "taker_utxo_amtpercent", newtuap)
taker = get_taker([(mixdepth, cjamt, 3, "mnsquzxrHXpFsZeL42qwbKdCP2y1esN3qw", NO_ROUNDING)])
# modify or add any extra utxos for this run:
for k, v in mixdepth_extras.items():
if k == "confchange":
for k2, v2 in v.items():
# set the utxos in mixdepth k2 to have confs v2:
cdict = taker.wallet_service.get_utxos_by_mixdepth()[k2]
jm_single().bc_interface.set_confs({utxo: v2 for utxo in cdict.keys()})
else:
for value in v:
taker.wallet_service.add_extra_utxo(
os.urandom(32), 0, value, k)
taker.cjamount = cjamt
taker.input_utxos = taker.wallet_service.get_utxos_by_mixdepth()[mixdepth]
taker.mixdepth = mixdepth taker.mixdepth = mixdepth
if failquery: if failquery:
jm_single().bc_interface.setQUSFail(True) jm_single().bc_interface.setQUSFail(True)
taker.make_commitment() comm, revelation, msg = taker.make_commitment()
if expected_success and failquery:
# for manual tests, show the error message:
print("Failure case due to QUS fail: ")
print("Erromsg: ", msg)
assert not comm
elif expected_success:
assert comm, "podle was not generated but should have been."
else:
# in these cases we have set the podle acceptance
# parameters such that our in-mixdepth utxos are not good
# enough.
# for manual tests, show the errormsg:
print("Failure case, errormsg: ", msg)
assert not comm, "podle was generated but should not have been."
clean_up() clean_up()
def test_not_found_maker_utxos(setup_taker): def test_not_found_maker_utxos(setup_taker):
taker = get_taker([(0, 20000000, 3, "mnsquzxrHXpFsZeL42qwbKdCP2y1esN3qw", 0, NO_ROUNDING)]) taker = get_taker([(0, 20000000, 3, "mnsquzxrHXpFsZeL42qwbKdCP2y1esN3qw", 0, NO_ROUNDING)])
orderbook = copy.deepcopy(t_orderbook) orderbook = copy.deepcopy(t_orderbook)

Loading…
Cancel
Save