def calculate_fidelity_bond_values(fidelity_bonds_info): if len(fidelity_bonds_info) == 0: return {} interest_rate = get_interest_rate() blocks = jm_single().bc_interface.get_current_block_height() mediantime = jm_single().bc_interface.get_best_block_median_time() validated_bonds = {} for bond_data in fidelity_bonds_info: try: fb_proof = FidelityBondProof.parse_and_verify_proof_msg( bond_data["counterparty"], bond_data["takernick"], bond_data["proof"]) except ValueError: continue if fb_proof.utxo in validated_bonds: continue utxo_data = FidelityBondMixin.get_validated_timelocked_fidelity_bond_utxo( fb_proof.utxo, fb_proof.utxo_pub, fb_proof.locktime, fb_proof.cert_expiry, blocks) if utxo_data is not None: validated_bonds[fb_proof.utxo] = (fb_proof, utxo_data) fidelity_bond_values = { bond_data.maker_nick: FidelityBondMixin.calculate_timelocked_fidelity_bond_value( utxo_data["value"], jm_single().bc_interface.get_block_time( jm_single().bc_interface.get_block_hash(blocks - utxo_data["confirms"] + 1)), bond_data.locktime, mediantime, interest_rate) for bond_data, utxo_data in validated_bonds.values() } return fidelity_bond_values
def test_fidelity_bond_seen(valid, fidelity_bond_proof, maker_nick, taker_nick): proof = FidelityBondProof( maker_nick, taker_nick, hextobin(fidelity_bond_proof['certificate-pubkey']), fidelity_bond_proof['certificate-expiry'], hextobin(fidelity_bond_proof['certificate-signature']), (hextobin(fidelity_bond_proof['txid']), fidelity_bond_proof['vout']), hextobin(fidelity_bond_proof['utxo-pubkey']), fidelity_bond_proof['locktime']) serialized = proof._serialize_proof_msg( fidelity_bond_proof['nick-signature']) ob = get_ob() ob.msgchan.nick = taker_nick ob.on_fidelity_bond_seen(maker_nick, fidelity_bond_cmd_list[0], serialized) rows = ob.db.execute("SELECT * FROM fidelitybonds;").fetchall() assert len(rows) == 1 assert rows[0]["counterparty"] == maker_nick assert rows[0]["takernick"] == taker_nick try: parsed_proof = FidelityBondProof.parse_and_verify_proof_msg( rows[0]["counterparty"], rows[0]["takernick"], rows[0]["proof"]) except ValueError: parsed_proof = None if valid: assert parsed_proof is not None assert parsed_proof.utxo[0] == hextobin(fidelity_bond_proof["txid"]) assert parsed_proof.utxo[1] == fidelity_bond_proof["vout"] assert parsed_proof.locktime == fidelity_bond_proof["locktime"] assert parsed_proof.cert_expiry == fidelity_bond_proof[ "certificate-expiry"] assert parsed_proof.utxo_pub == hextobin( fidelity_bond_proof["utxo-pubkey"]) else: assert parsed_proof is None
def get_fidelity_bond_data(taker): with taker.dblock: fbonds = taker.db.execute("SELECT * FROM fidelitybonds;").fetchall() blocks = jm_single().bc_interface.get_current_block_height() mediantime = jm_single().bc_interface.get_best_block_median_time() interest_rate = get_interest_rate() bond_utxo_set = set() fidelity_bond_data = [] bond_outpoint_conf_times = [] fidelity_bond_values = [] for fb in fbonds: try: parsed_bond = FidelityBondProof.parse_and_verify_proof_msg( fb["counterparty"], fb["takernick"], fb["proof"]) except ValueError: continue bond_utxo_data = FidelityBondMixin.get_validated_timelocked_fidelity_bond_utxo( parsed_bond.utxo, parsed_bond.utxo_pub, parsed_bond.locktime, parsed_bond.cert_expiry, blocks) if bond_utxo_data == None: continue #check for duplicated utxos i.e. two or more makers using the same UTXO # which is obviously not allowed, a fidelity bond must only be usable by one maker nick utxo_str = parsed_bond.utxo[0] + b":" + str( parsed_bond.utxo[1]).encode("ascii") if utxo_str in bond_utxo_set: continue bond_utxo_set.add(utxo_str) fidelity_bond_data.append((parsed_bond, bond_utxo_data)) conf_time = jm_single().bc_interface.get_block_time( jm_single().bc_interface.get_block_hash( blocks - bond_utxo_data["confirms"] + 1)) bond_outpoint_conf_times.append(conf_time) bond_value = FidelityBondMixin.calculate_timelocked_fidelity_bond_value( bond_utxo_data["value"], conf_time, parsed_bond.locktime, mediantime, interest_rate) fidelity_bond_values.append(bond_value) return (fidelity_bond_data, fidelity_bond_values, bond_outpoint_conf_times)
def test_duplicate_fidelity_bond_rejected(): fidelity_bond_info = (({ "nick-signature": (b'0E\x02!\x00\xdbb\x15\x96\xa0\x87\xb8\x1d\xe05\xddV\xa1\x1bn\x8f' + b'q\x90&\x8cG@\x89"2\xb2\x81\x9b\xc00\xa5\xb6\x02 \x03\x14l\xd7BR\xba\x8c:\x88(' + b'\x8e3l\xac\xf5`T\x87\xfa\xf5\xa9\x1f\x19\xc0\xb6\xe9\xbb\xdc\xc7y\x99' ), "certificate-signature": ("3045022100eb512af938113badb4d7b29e0c22061c51dadb113a9395e" + "9ed81a46103391213022029170de414964f07228c4f0d404b1386272bae337f0133f1329d948a" + "252fa2a0"), "certificate-pubkey": "0258efb077960d6848f001904857f062fa453de26c1ad8736f55497254f56e8a74", "certificate-expiry": 1, "utxo-pubkey": "02f54f027377e84171296453828aa863c23fc4489453025f49bd3addfb3a359b3d", "txid": "84c88fafe0bb75f507fe3bfb29a93d10b2e80c15a63b2943c1a5fecb5a55cba2", "vout": 0, "locktime": 1640995200 }, "J5A4k9ecQzRRDfBx", "J55VZ6U6ZyFDNeuv"), ({ "nick-signature": (b'0E\x02!\x00\x80\xc6$\x0c\xa1\x15YS\xacHB\xb33\xfa~\x9f\xb9`\xb3' + b'\xfe\xed0\xadHq\xc1~\x03.B\xbb#\x02 #y~]\xd9\xbbX2\xc0\x1b\xe57\xf4\x0f\x1f' + b'\xd6$\x01\xf9\x15Z\xc9X\xa5\x18\xbe\x83\x1a&4Y\xd4'), "certificate-signature": ("304402205669ea394f7381e9abf0b3c013fac2b79d24c02feb86ff153" + "cff83c658d7cf7402200b295ace655687f80738f3733c1dc5f1e2b8f351c017a05b8bd31983dd" + "4d723f"), "certificate-pubkey": "031d1c006a6310dbdf57341efc19c3a43c402379d7ccd2480416cadc7579f973f7", "certificate-expiry": 1, "utxo-pubkey": "02616c56412eb738a9eacfb0550b43a5a2e77e5d5205ea9e2ca8dfac34e50c9754", "txid": "84c88fafe0bb75f507fe3bfb29a93d10b2e80c15a63b2943c1a5fecb5a55cba2", "vout": 1, "locktime": 1893456000 }, "J54LS6YyJPoseqFS", "J55VZ6U6ZyFDNeuv")) ob = get_ob() fidelity_bond_proof1, maker_nick1, taker_nick1 = fidelity_bond_info[0] proof = FidelityBondProof( maker_nick1, taker_nick1, hextobin(fidelity_bond_proof1['certificate-pubkey']), fidelity_bond_proof1['certificate-expiry'], hextobin(fidelity_bond_proof1['certificate-signature']), (hextobin(fidelity_bond_proof1['txid']), fidelity_bond_proof1['vout']), hextobin(fidelity_bond_proof1['utxo-pubkey']), fidelity_bond_proof1['locktime']) serialized1 = proof._serialize_proof_msg( fidelity_bond_proof1['nick-signature']) ob.msgchan.nick = taker_nick1 ob.on_fidelity_bond_seen(maker_nick1, fidelity_bond_cmd_list[0], serialized1) rows = ob.db.execute("SELECT * FROM fidelitybonds;").fetchall() assert len(rows) == 1 #show the same fidelity bond message again, check it gets rejected as duplicate ob.on_fidelity_bond_seen(maker_nick1, fidelity_bond_cmd_list[0], serialized1) rows = ob.db.execute("SELECT * FROM fidelitybonds;").fetchall() assert len(rows) == 1 #show a different fidelity bond and check it does get accepted fidelity_bond_proof2, maker_nick2, taker_nick2 = fidelity_bond_info[1] proof2 = FidelityBondProof( maker_nick1, taker_nick1, hextobin(fidelity_bond_proof2['certificate-pubkey']), fidelity_bond_proof2['certificate-expiry'], hextobin(fidelity_bond_proof2['certificate-signature']), (hextobin(fidelity_bond_proof2['txid']), fidelity_bond_proof2['vout']), hextobin(fidelity_bond_proof2['utxo-pubkey']), fidelity_bond_proof2['locktime']) serialized2 = proof2._serialize_proof_msg( fidelity_bond_proof2['nick-signature']) ob.msgchan.nick = taker_nick2 ob.on_fidelity_bond_seen(maker_nick2, fidelity_bond_cmd_list[0], serialized2) rows = ob.db.execute("SELECT * FROM fidelitybonds;").fetchall() assert len(rows) == 2
def create_orderbook_table(self, btc_unit, rel_unit): result = '' try: self.taker.dblock.acquire(True) rows = self.taker.db.execute('SELECT * FROM orderbook;').fetchall() finally: self.taker.dblock.release() if not rows: return 0, result rows = [o for o in rows if o["ordertype"] in filtered_offername_list] if jm_single().bc_interface == None: for row in rows: row["bondvalue"] = "No data" else: blocks = jm_single().bc_interface.get_current_block_height() mediantime = jm_single().bc_interface.get_best_block_median_time() interest_rate = get_interest_rate() for row in rows: with self.taker.dblock: fbond_data = self.taker.db.execute( "SELECT * FROM fidelitybonds WHERE counterparty=?;", (row["counterparty"], )).fetchall() if len(fbond_data) == 0: row["bondvalue"] = "0" continue else: try: parsed_bond = FidelityBondProof.parse_and_verify_proof_msg( fbond_data[0]["counterparty"], fbond_data[0]["takernick"], fbond_data[0]["proof"]) except ValueError: row["bondvalue"] = "0" continue utxo_data = FidelityBondMixin.get_validated_timelocked_fidelity_bond_utxo( parsed_bond.utxo, parsed_bond.utxo_pub, parsed_bond.locktime, parsed_bond.cert_expiry, blocks) if utxo_data == None: row["bondvalue"] = "0" continue bond_value = FidelityBondMixin.calculate_timelocked_fidelity_bond_value( utxo_data["value"], jm_single().bc_interface.get_block_time( jm_single().bc_interface.get_block_hash( blocks - utxo_data["confirms"] + 1)), parsed_bond.locktime, mediantime, interest_rate) row["bondvalue"] = satoshi_to_unit_power( bond_value, 2 * unit_to_power[btc_unit]) order_keys_display = (('ordertype', ordertype_display), ('counterparty', do_nothing), ('oid', order_str), ('cjfee', cjfee_display), ('txfee', satoshi_to_unit), ('minsize', satoshi_to_unit), ('maxsize', satoshi_to_unit), ('bondvalue', do_nothing)) # somewhat complex sorting to sort by cjfee but with swabsoffers on top def orderby_cmp(x, y): if x['ordertype'] == y['ordertype']: return cmp(Decimal(x['cjfee']), Decimal(y['cjfee'])) return cmp(offername_list.index(x['ordertype']), offername_list.index(y['ordertype'])) for o in sorted(rows, key=cmp_to_key(orderby_cmp)): result += ' <tr>\n' for key, displayer in order_keys_display: result += ' <td>' + displayer(o[key], o, btc_unit, rel_unit) + '</td>\n' result += ' </tr>\n' return len(rows), result
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)