def test_spend_freeze_script(setup_tx_creation): ensure_bip65_activated() wallet_service = make_wallets(1, [[3, 0, 0, 0, 0]], 3)[0]['wallet'] wallet_service.sync_wallet(fast=True) mediantime = jm_single().bc_interface.rpc("getblockchaininfo", [])["mediantime"] timeoffset_success_tests = [(2, False), (-60 * 60 * 24 * 30, True), (60 * 60 * 24 * 30, False)] for timeoffset, required_success in timeoffset_success_tests: #generate keypair priv = b"\xaa" * 32 + b"\x01" pub = bitcoin.privkey_to_pubkey(priv) addr_locktime = mediantime + timeoffset redeem_script = bitcoin.mk_freeze_script(pub, addr_locktime) script_pub_key = bitcoin.redeem_script_to_p2wsh_script(redeem_script) # cannot convert to address within wallet service, as not known # to wallet; use engine directly: addr = wallet_service._ENGINE.script_to_address(script_pub_key) #fund frozen funds address amount = 100000000 funding_ins_full = wallet_service.select_utxos(0, amount) funding_txid = make_sign_and_push(funding_ins_full, wallet_service, amount, output_addr=addr) assert funding_txid #spend frozen funds frozen_in = (funding_txid, 0) output_addr = wallet_service.get_internal_addr(1) miner_fee = 5000 outs = [{'value': amount - miner_fee, 'address': output_addr}] tx = bitcoin.mktx([frozen_in], outs, locktime=addr_locktime + 1) i = 0 sig, success = bitcoin.sign(tx, i, priv, amount=amount, native=redeem_script) assert success push_success = jm_single().bc_interface.pushtx(tx.serialize()) assert push_success == required_success
def test_spend_freeze_script(setup_tx_creation): ensure_bip65_activated() wallet_service = make_wallets(1, [[3, 0, 0, 0, 0]], 3)[0]['wallet'] wallet_service.sync_wallet(fast=True) mediantime = jm_single().bc_interface.rpc("getblockchaininfo", [])["mediantime"] timeoffset_success_tests = [(2, False), (-60*60*24*30, True), (60*60*24*30, False)] for timeoffset, required_success in timeoffset_success_tests: #generate keypair priv = "aa"*32 + "01" pub = unhexlify(bitcoin.privkey_to_pubkey(priv)) addr_locktime = mediantime + timeoffset redeem_script = bitcoin.mk_freeze_script(pub, addr_locktime) script_pub_key = bitcoin.redeem_script_to_p2wsh_script(redeem_script) regtest_vbyte = 100 addr = bitcoin.script_to_address(script_pub_key, vbyte=regtest_vbyte) #fund frozen funds address amount = 100000000 funding_ins_full = wallet_service.select_utxos(0, amount) funding_txid = make_sign_and_push(funding_ins_full, wallet_service, amount, output_addr=addr) assert funding_txid #spend frozen funds frozen_in = funding_txid + ":0" output_addr = wallet_service.get_internal_addr(1) miner_fee = 5000 outs = [{'value': amount - miner_fee, 'address': output_addr}] tx = bitcoin.mktx([frozen_in], outs, locktime=addr_locktime+1) i = 0 sig = bitcoin.get_p2sh_signature(tx, i, redeem_script, priv, amount) assert bitcoin.verify_tx_input(tx, i, script_pub_key, sig, pub, scriptCode=redeem_script, amount=amount) tx = bitcoin.apply_freeze_signature(tx, i, redeem_script, sig) push_success = jm_single().bc_interface.pushtx(tx) assert push_success == required_success
def pubkey_to_script_code(cls, pubkey_locktime): pubkey, locktime = pubkey_locktime return btc.mk_freeze_script(pubkey, locktime)
def create_fidelity_bond_table(self, btc_unit): if jm_single().bc_interface == None: with self.taker.dblock: fbonds = self.taker.db.execute( "SELECT * FROM fidelitybonds;").fetchall() fidelity_bond_data = [] for fb in fbonds: try: proof = FidelityBondProof.parse_and_verify_proof_msg( fb["counterparty"], fb["takernick"], fb["proof"]) except ValueError: proof = None fidelity_bond_data.append((proof, None)) fidelity_bond_values = [-1] * len( fidelity_bond_data) #-1 means no data bond_outpoint_conf_times = [-1] * len(fidelity_bond_data) total_btc_committed_str = "unknown" else: (fidelity_bond_data, fidelity_bond_values, bond_outpoint_conf_times) =\ get_fidelity_bond_data(self.taker) total_btc_committed_str = satoshi_to_unit( sum([ utxo_data["value"] for _, utxo_data in fidelity_bond_data ]), None, btc_unit, 0) RETARGET_INTERVAL = 2016 elem = lambda e: "<td>" + e + "</td>" bondtable = "" for (bond_data, utxo_data), bond_value, conf_time in zip( fidelity_bond_data, fidelity_bond_values, bond_outpoint_conf_times): if bond_value == -1 or conf_time == -1 or utxo_data == None: bond_value_str = "No data" conf_time_str = "No data" utxo_value_str = "No data" else: bond_value_str = satoshi_to_unit_power( bond_value, 2 * unit_to_power[btc_unit]) conf_time_str = str( datetime.utcfromtimestamp(0) + timedelta(seconds=conf_time)) utxo_value_str = satoshi_to_unit(utxo_data["value"], None, btc_unit, 0) bondtable += ( "<tr>" + elem(bond_data.maker_nick) + elem( bintohex(bond_data.utxo[0]) + ":" + str(bond_data.utxo[1])) + elem(bond_value_str) + elem( (datetime.utcfromtimestamp(0) + timedelta( seconds=bond_data.locktime)).strftime("%Y-%m-%d")) + elem(utxo_value_str) + elem(conf_time_str) + elem(str(bond_data.cert_expiry * RETARGET_INTERVAL)) + elem( bintohex( btc.mk_freeze_script(bond_data.utxo_pub, bond_data.locktime))) + "</tr>") heading2 = (str(len(fidelity_bond_data)) + " fidelity bonds found with " + total_btc_committed_str + " " + btc_unit + " total locked up") choose_units_form = ( '<form method="get" action="">' + '<select name="btcunit" onchange="this.form.submit();">' + ''.join( ('<option>' + u + ' </option>' for u in sorted_units)) + '</select></form>') choose_units_form = choose_units_form.replace( '<option>' + btc_unit, '<option selected="selected">' + btc_unit) decodescript_tip = ( "<br/>Tip: try running the RPC <code>decodescript " + "<redeemscript></code> as proof that the fidelity bond address matches the " + "locktime.<br/>Also run <code>gettxout <utxo_txid> <utxo_vout></code> " + "as proof that the fidelity bond UTXO is real.") return (heading2, choose_units_form + create_bonds_table_heading(btc_unit) + bondtable + "</table>" + decodescript_tip)
def test_make_commitment(setup_taker, mixdepth, cjamt, failquery, external, expected_success, amtpercent, age, mixdepth_extras): def clean_up(): jm_single().config.set("POLICY", "taker_utxo_age", old_taker_utxo_age) jm_single().config.set("POLICY", "taker_utxo_amtpercent", old_taker_utxo_amtpercent) set_commitment_file(old_commitment_file) jm_single().bc_interface.setQUSFail(False) jm_single().bc_interface.reset_confs() os.remove('dummyext') old_commitment_file = get_commitment_file() with open('dummyext', 'wb') as f: f.write(json.dumps(t_dummy_ext, indent=4).encode('utf-8')) if external: 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_amtpercent = jm_single().config.get( "POLICY", "taker_utxo_amtpercent") if expected_success: # set to defaults for mainnet newtua = "5" newtuap = "20" else: newtua = str(age) 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()}) elif k == "custom-script": # note: this is inspired by fidelity bonds, and currently # uses scripts of that specific timelock type, but is really # only testing the general concept: that commitments must # not be made on any non-standard script type. for k2, v2 in v.items(): priv = os.urandom(32) + b"\x01" tl = random.randrange(1430454400, 1430494400) script_inner = bitcoin.mk_freeze_script( bitcoin.privkey_to_pubkey(priv), tl) script_outer = bitcoin.redeem_script_to_p2wsh_script( script_inner) taker.wallet_service.wallet._script_map[script_outer] = ( "nonstandard_path", ) taker.wallet_service.add_extra_utxo(os.urandom(32), 0, v2, k2, script=script_outer) 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 if failquery: jm_single().bc_interface.setQUSFail(True) 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()