def main(finalizer=None, finalizer_args=None): #Will only be used by client log.startLogging(sys.stdout) load_coinjoinxt_config() #to allow testing of confirm/unconfirm callback for multiple txs if isinstance(cjxt_single().bc_interface, RegtestBitcoinCoreInterface): cjxt_single().bc_interface.tick_forward_chain_interval = 2 cjxt_single().bc_interface.simulating = True wallet_name = sys.argv[1] server, port = sys.argv[2:4] #depth 0: spend in, depth 1: receive out, depth 2: for backout transactions. max_mix_depth = 3 wallet_dir = os.path.join(cjxt_single().homedir, 'wallets') if not os.path.exists(os.path.join(wallet_dir, wallet_name)): wallet = SegwitWallet(wallet_name, None, max_mix_depth, 6, wallet_dir=wallet_dir) else: while True: try: pwd = get_password("Enter wallet decryption passphrase: ") wallet = SegwitWallet(wallet_name, pwd, max_mix_depth, 6, wallet_dir=wallet_dir) except WalletError: print("Wrong password, try again.") continue except Exception as e: print("Failed to load wallet, error message: " + repr(e)) sys.exit(0) break """ Uncomment this for auto-funding on regtest if isinstance(cjxt_single().bc_interface, RegtestBitcoinCoreInterface): #funding the wallet with outputs specifically suitable for the starting point. funding_utxo_addr = wallet.get_new_addr(0, 0, True) bob_promise_utxo_addr = wallet.get_new_addr(0, 0, True) cjxt_single().bc_interface.grab_coins(funding_utxo_addr, 1.0) cjxt_single().bc_interface.grab_coins(bob_promise_utxo_addr, 0.5) """ sync_wallet(wallet, fast=False) wallet.used_coins = None factory = OCCServerProtocolFactory(wallet) start_daemon(server, port, factory) if finalizer: reactor.addSystemEventTrigger("after", "shutdown", finalizer, finalizer_args) reactor.run()
def get_current_blockheight(): """returns current blockheight as integer. Assumes existence of valid blockchain interface instance, instantiated via config, in the jmclient package. """ blockchainInfo = cjxt_single().bc_interface.jsonRpc.call( "getblockchaininfo", []) return blockchainInfo["blocks"]
def push(self): """Broadcast the transcation to the network if it is fully signed; return True and txid in case of success, or False and an error message otherwise. """ assert self.fully_signed() self.attach_signatures() self.set_txid() if not cjxt_single().bc_interface.pushtx(self.fully_signed_tx): return ("Failed to push transaction, id: " + self.txid, False) else: return (self.txid, True)
def on_OCC_SIGS_RESPONSE(self, funding_sigs): ba = cjxt_single().config.getint("POLICY", "broadcast_all") funding_sigs = json.loads(funding_sigs) #Verify all, including funding, then broadcast. for i, tx in enumerate(self.realtxs[1:]): for j in range(len(tx.ins)): x = self.template.txs[i + 1].ins[j] if x.spk_type == "NN" or 1 in tx.keys["ins"][j]: #pop removes the used signature for the next iteration tx.include_signature(j, 1, self.counterparty_sigs.pop(0)) if not ba == 1: tx.attach_signatures() for tx in self.realbackouttxs: for j in range(len(tx.ins)): tx.include_signature(j, 1, self.counterparty_sigs.pop(0)) if not ba == 1: tx.attach_signatures() #Now all transactions except Funding are validly, fully signed, #so we are safe to complete signing on the Funding and broadcast #that one first. We'll print out all transactions for broadcast, #too. for i in range(len(self.realtxs[0].ins)): if 0 in self.realtxs[0].keys["ins"][i]: self.realtxs[0].sign_at_index(i) if 1 in self.realtxs[0].keys["ins"][i]: self.realtxs[0].include_signature(i, 1, funding_sigs.pop(0)) #push the funding txid, reason = self.realtxs[0].push() if not txid: cjxtlog.info("Failed to push transaction, reason: " + reason) else: cjxtlog.info("Succeeded push, txid: " + txid) with open("occresults.txt", "wb") as f: f.write("Here are the rest of the transactions to push:\n") for i, tx in enumerate(self.realtxs[1:]): f.write("Transaction number: " + str(i) + "\n") f.write(str(tx) + "\n") for i, tx in enumerate(self.realbackouttxs): f.write("Backout transaction number: " + str(i) + "\n") f.write(str(tx) + "\n") if ba == 1: #we'll push all the others, one by one for i in range(len(self.realtxs) - 1): reactor.callLater(float(i / 10.0), self.realtxs[i + 1].push) reactor.callLater(5.0, self.final_checks) return {"accepted": True}
def final_checks(self): """Check that our keys have received the right funds in the wallet (all the single-owned outpoints to p2sh-p2wpkh outpoints should contain utxos that own the intended number of coins). """ match = True total_coins = 0 for i, tx in enumerate(self.template.txs): txid = self.realtxs[i].txid for j, tout in enumerate(tx.outs): if tout.counterparty == 0: expected_amount = tout.amount print("We expected this amount out: ", expected_amount) actual_key = self.realtxs[i].keys["outs"][j][0] actual_address = btc.pubkey_to_p2sh_p2wpkh_address( actual_key, get_p2sh_vbyte()) #direct query on blockchain for the transaction, #then check if it pays to our address and in what amount res = cjxt_single().bc_interface.rpc( 'gettxout', [txid, j, True]) if not ("scriptPubKey" in res and "addresses" in res["scriptPubKey"]): print("Failed to query the tx: ", txid) found_address = str(res["scriptPubKey"]["addresses"][0]) if not found_address == actual_address: print("Error, transaction, vout: ", txid, j, "has address: ", found_address, ", but should have been address: ", actual_address) print("Amount received was: ", res["value"], " at address: ", actual_address) sat_value = btc_to_satoshis(res["value"]) total_coins += res["value"] if not sat_value == expected_amount or not actual_address == found_address: match = False if match: print("Success! Received back total coins: ", total_coins) else: print( "Failure! Not all expected coins received, see above summary.") reactor.stop()
def start_reactor(host, port, factory, ish=True): startLogging(sys.stdout) reactor.connectTCP(host, int(port), factory) reactor.run(installSignalHandlers=ish) if isinstance(cjxt_single().bc_interface, RegtestBitcoinCoreInterface): cjxt_single().bc_interface.shutdown_signal = True
def start_reactor(host, port, factory, ish=True): startLogging(sys.stdout) reactor.connectTCP(host, int(port), factory) reactor.run(installSignalHandlers=ish) if isinstance(cjxt_single().bc_interface, RegtestBitcoinCoreInterface): cjxt_single().bc_interface.shutdown_signal = True if __name__ == "__main__": load_coinjoinxt_config() wallet_name = sys.argv[1] serv, port = sys.argv[2:4] max_mix_depth = 3 wallet_dir = os.path.join(cjxt_single().homedir, 'wallets') if not os.path.exists(os.path.join(wallet_dir, wallet_name)): wallet = SegwitWallet(wallet_name, None, max_mix_depth, 6, wallet_dir=wallet_dir) else: while True: try: pwd = get_password("Enter wallet decryption passphrase: ") wallet = SegwitWallet(wallet_name, pwd, max_mix_depth, 6, wallet_dir=wallet_dir)