def sign_our_inputs(self) -> None: assert self.tx is not None for idx, _in in enumerate(self.inputs): privkey = _in['privkey'] if privkey and 'sig' not in _in: print('signing our input for tx', self.tx.serialize().hex()) inkey = privkey_expand(privkey) inkey_pub = coincurve.PublicKey.from_secret(inkey.secret) # Really horrid hack to produce a signature for the # multisig utxo in tests/helpers.py if privkey == '38204720bc4f9647fd58c6d0a4bd3a6dd2be16d8e4273c4d1bdd5774e8c51eaf': redeemscript = bytes.fromhex('51210253cdf835e328346a4f19de099cf3d42d4a7041e073cd4057a1c4fd7cdbb1228f2103ae903722f21f85e651b8f9b18fc854084fb90eeb76452bdcfd0cb43a16a382a221036c264d68a9727afdc75949f7d7fa71910ae9ae8001a1fbffa6f7ce000976597c21036429fa8a4ef0b2b1d5cb553e34eeb90a32ab19fae1f0024f332ab4f74283a7282103d4232f19ea85051e7b76bf5f01d03e17eea8751463dee36d71413a739de1a92755ae') else: address = P2WPKHBitcoinAddress.from_scriptPubKey(CScript([script.OP_0, Hash160(inkey_pub.format())])) redeemscript = address.to_redeemScript() sighash = script.SignatureHash(redeemscript, self.tx, idx, script.SIGHASH_ALL, amount=_in['sats'], sigversion=script.SIGVERSION_WITNESS_V0) sig = inkey.sign(sighash, hasher=None) + bytes([script.SIGHASH_ALL]) if privkey == '38204720bc4f9647fd58c6d0a4bd3a6dd2be16d8e4273c4d1bdd5774e8c51eaf': _in['sig'] = CTxInWitness(CScriptWitness([bytes([]), sig, redeemscript])) else: _in['sig'] = CTxInWitness(CScriptWitness([sig, inkey_pub.format()]))
def add_witnesses(self, witness_stack) -> str: wits = [] for idx, _in in enumerate(self.inputs): privkey = _in['privkey'] serial_id = _in['serial_id'] if privkey: inkey = privkey_expand(privkey) inkey_pub = coincurve.PublicKey.from_secret(inkey.secret) address = P2WPKHBitcoinAddress.from_scriptPubKey(CScript([script.OP_0, Hash160(inkey_pub.format())])) sighash = script.SignatureHash(address.to_redeemScript(), self.tx, idx, script.SIGHASH_ALL, amount=_in['sats'], sigversion=script.SIGVERSION_WITNESS_V0) sig = inkey.sign(sighash, hasher=None) + bytes([script.SIGHASH_ALL]) wits.append(CTxInWitness(CScriptWitness([sig, inkey_pub.format()]))) continue # Every input from the witness stack will be the accepter's # which is always an odd serial assert(serial_id % 2 == 1) elems = witness_stack.pop(0)['witness_element'] stack = [] for elem in elems: stack.append(bytes.fromhex(elem['witness'])) wits.append(CTxInWitness(CScriptWitness(stack))) self.tx.wit = CTxWitness(wits) return self.tx.serialize().hex()
def get_address_from_pubkey(cls, pubkey): """ Get bitcoin address for a specific hrp (human readable part) bech32 encoded from a public key(secp256k1). :param string pubkey: public key :returns: string bech32 encoded address """ script_pubkey = CScript([OP_0, Hash160(pubkey)]) return str(P2WPKHBitcoinAddress.from_scriptPubKey(script_pubkey))
def from_utxo(txid_in: str, tx_index_in: int, sats: int, privkey: str, fee: int, local_node_privkey: str, local_funding_privkey: str, remote_node_privkey: str, remote_funding_privkey: str, chain_hash: str = regtest_hash) -> Tuple['Funding', str]: """Make a funding transaction by spending this utxo using privkey: return Funding, tx.""" # Create dummy one to start: we will fill in txid at the end. funding = Funding('', 0, sats - fee, local_node_privkey, local_funding_privkey, remote_node_privkey, remote_funding_privkey, chain_hash) # input private key. inkey = privkey_expand(privkey) inkey_pub = coincurve.PublicKey.from_secret(inkey.secret) # use RBF'able input (requirement for dual-funded things) txin = CTxIn(COutPoint(bytes.fromhex(txid_in), tx_index_in), nSequence=0xFFFFFFFD) txout = CTxOut( sats - fee, CScript([script.OP_0, sha256(funding.redeemscript()).digest()])) tx = CMutableTransaction([txin], [txout], nVersion=2, nLockTime=funding.locktime) # now fill in funding txid. funding.txid = tx.GetTxid().hex() funding.tx = tx # while we're here, sign the transaction. address = P2WPKHBitcoinAddress.from_scriptPubKey( CScript([script.OP_0, Hash160(inkey_pub.format())])) sighash = script.SignatureHash(address.to_redeemScript(), tx, 0, script.SIGHASH_ALL, amount=sats, sigversion=script.SIGVERSION_WITNESS_V0) sig = inkey.sign(sighash, hasher=None) + bytes([script.SIGHASH_ALL]) tx.wit = CTxWitness( [CTxInWitness(CScriptWitness([sig, inkey_pub.format()]))]) return funding, tx.serialize().hex()
def do_mesh_sendtoaddress(self, rem) : """ Create a signed transaction and broadcast it over the connected mesh device. The transaction spends some amount of satoshis to the specified address from the local bitcoind wallet and selected network. Usage: mesh_sendtoaddress BECH32 ADDRESS SATS NETWORK(m|t) eg. txTenna> mesh_sendtoaddress 2N4BtwKZBU3kXkWT7ZBEcQLQ451AuDWiau2 13371337 t """ try: proxy = bitcoin.rpc.Proxy() (addr, sats, network) = rem.split() # Create the txout. This time we create the scriptPubKey from a Bitcoin # address. p2wpkh_addr = P2WPKHBitcoinAddress(addr) txout = CMutableTxOut(sats, p2wpkh_addr.to_scriptPubKey()) # Create the unsigned transaction. unfunded_transaction = CMutableTransaction([], [txout]) funded_transaction = proxy.fundrawtransaction(unfunded_transaction) signed_transaction = proxy.signrawtransaction(funded_transaction["tx"]) txhex = b2x(signed_transaction["tx"].serialize()) txid = b2lx(signed_transaction["tx"].GetTxid()) print("sendtoaddress_mesh (tx, txid, network): " + txhex + ", " + txid, ", " + network) # broadcast over mesh self.do_mesh_broadcast_rawtx( txhex + " " + txid + " " + network) except Exception: # pylint: disable=broad-except traceback.print_exc() try : # lock UTXOs used to fund the tx if broadcast successful vin_outpoints = set() for txin in funded_transaction["tx"].vin: vin_outpoints.add(txin.prevout) ## json_outpoints = [{'txid':b2lx(outpoint.hash), 'vout':outpoint.n} ## for outpoint in vin_outpoints] ## print(str(json_outpoints)) proxy.lockunspent(False, vin_outpoints) except Exception: # pylint: disable=broad-except ## TODO: figure out why this is happening print("RPC timeout after calling lockunspent")
def add_input(bitcoind, tx, fees): """Add another input to the transaction to bump the feerate.""" # Don't be dust! if fees < 294: fees = 294 # Create the first stage transaction new_prevout_addr = P2WPKHBitcoinAddress(bitcoind.getnewaddress()) txid = bitcoind.sendtoaddress(str(new_prevout_addr), fees / COIN) out_index = get_output_index(bitcoind.getrawtransaction(txid, decode=True), fees) # Then gather the private key to unlock its output privkey = CKey(wif_decode(bitcoind.dumpprivkey(str(new_prevout_addr)))) # Add the fetched coin as a new input. tx.vin.append(CTxIn(COutPoint(lx(txid), out_index))) # We only do this once, sign it with ALL tx_hash = SignatureHash(new_prevout_addr.to_redeemScript(), tx, 1, SIGHASH_ALL, fees, SIGVERSION_WITNESS_V0) sig = privkey.sign(tx_hash) + bytes([SIGHASH_ALL]) tx.wit.vtxinwit.append(CTxInWitness(CScriptWitness([sig, privkey.pub]))) return tx
def parameterize_witness_template_by_signing(some_input, parameters): """ Take a specific witness template, a bag of parameters, and a transaction, and then produce a parameterized witness (including all necessary valid signatures). Make a sighash for the bitcoin transaction. """ p2wsh_redeem_script = some_input.utxo.p2wsh_redeem_script tx = some_input.transaction.bitcoin_transaction txin_index = some_input.transaction.inputs.index(some_input) computed_witness = [] selection = some_input.witness_template_selection script_template = some_input.utxo.script_template witness_template = script_template.witness_templates[selection] amount = some_input.utxo.amount # TODO: Might have to update the witness_templates values to give a # correct ordering for which signature should be supplied first. # (already did this? Re-check for VerifyScript errors) witness_tmp = witness_template.split(" ") for (idx, section) in enumerate(witness_tmp): if section[0] == "<" and section[-1] == ">": section = section[1:-1] if section == "user_key": computed_witness.append(parameters["user_key"]["public_key"]) continue elif section not in script_template.witness_template_map.keys(): raise VaultException( "Missing key mapping for {}".format(section)) key_param_name = script_template.witness_template_map[section] private_key = parameters[key_param_name]["private_key"] if script_template != UserScriptTemplate: # This is a P2WSH transaction. redeem_script = p2wsh_redeem_script elif script_template == UserScriptTemplate: # This is a P2WPKH transaction. user_address = P2WPKHBitcoinAddress.from_scriptPubKey( CScript( [OP_0, Hash160(parameters["user_key"]["public_key"])])) redeem_script = user_address.to_redeemScript() # P2WPKH redeemScript: OP_DUP OP_HASH160 .... sighash = SignatureHash(redeem_script, tx, txin_index, SIGHASH_ALL, amount=amount, sigversion=SIGVERSION_WITNESS_V0) signature = private_key.sign(sighash) + bytes([SIGHASH_ALL]) computed_witness.append(signature) else: # dunno what to do with this, probably just pass it on really.. computed_witness.append(section) if script_template == UserScriptTemplate: # P2WPKH # Witness already completed. No redeem_script to append. pass else: # P2WSH # Append the p2wsh redeem script. computed_witness.append(p2wsh_redeem_script) computed_witness = CScript(computed_witness) some_input.witness = computed_witness return computed_witness
def initialize(private_key=None): """ Setup and initialize a new vault in the current working directory. This is the primary entrypoint for the prototype. """ check_vaultfile_existence() check_private_key_is_conformant(private_key) #amount = random.randrange(0, 100 * COIN) #amount = 7084449357 amount = 2 * COIN # TODO: A more sophisticated private key system is required, for any real # production use. some_private_keys = [CBitcoinSecret(private_key)] * 6 parameter_names = [ "user_key", "ephemeral_key_1", "ephemeral_key_2", "cold_key1", "cold_key2", "hot_wallet_key", ] parameters = { "num_shards": 5, "enable_burn_transactions": True, "enable_graphviz": True, "enable_graphviz_popup": False, "amount": amount, "unspendable_key_1": CPubKey( x("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798" )), } for some_name in parameter_names: private_key = some_private_keys.pop() public_key = private_key.pub parameters[some_name] = { "private_key": private_key, "public_key": public_key } parameters["user_key_hash160"] = b2x( Hash160(parameters["user_key"]["public_key"])) # consistency check against required parameters required_parameters = ScriptTemplate.get_required_parameters() missing_parameters = False for required_parameter in required_parameters: if required_parameter not in parameters.keys(): logger.error(f"Missing parameter: {required_parameter}") missing_parameters = True if missing_parameters: logger.error("Missing parameters!") sys.exit(1) # connect to bitcoind (ideally, regtest) connection = get_bitcoin_rpc_connection() # setup the user private key (for P2WPKH) connection._call("importprivkey", str(parameters["user_key"]["private_key"]), "user") # Mine some coins into the "user_key" P2WPKH address #user_address = "bcrt1qrnwea7zc93l5wh77y832wzg3cllmcquqeal7f5" # parsed_address = P2WPKHBitcoinAddress(user_address) user_address = P2WPKHBitcoinAddress.from_scriptPubKey( CScript([OP_0, Hash160(parameters["user_key"]["public_key"])])) blocks = 110 if connection._call("getblockchaininfo")["blocks"] < blocks: try: connection._call("sendtoaddress", user_address, 50) except Exception: pass connection._call("generatetoaddress", blocks, str(user_address)) # Now find an unspent UTXO. unspent = connection._call("listunspent", 6, 9999, [str(user_address)], True, {"minimumAmount": amount / COIN}) if len(unspent) == 0: raise VaultException( "can't find a good UTXO for amount {}".format(amount)) # pick the first UTXO utxo_details = unspent[0] txid = utxo_details["txid"] # have to consume the whole UTXO amount = int(utxo_details["amount"] * COIN) initial_tx_txid = lx(utxo_details["txid"]) initial_tx = InitialTransaction(txid=initial_tx_txid) segwit_utxo = PlannedUTXO( name="segwit input coin", transaction=initial_tx, script_template=UserScriptTemplate, amount=amount, ) segwit_utxo._vout_override = utxo_details["vout"] initial_tx.output_utxos = [segwit_utxo] # for establishing vout # =============== # Here's where the magic happens. vault_initial_utxo = setup_vault(segwit_utxo, parameters) # =============== # Check that the tree is conforming to applicable rules. safety_check(segwit_utxo.transaction) # To test that the sharded UTXOs have the right amounts, do the following: # assert (second_utxo_amount * 99) + first_utxo_amount == amount # Display all UTXOs and transactions-- render the tree of possible # transactions. Mostly helpful for debugging purposes. render_planned_tree_to_text_file(segwit_utxo, filename=TEXT_RENDERING_FILENAME) # stats logger.info("*** Stats and numbers") logger.info( f"{PlannedUTXO.__counter__} UTXOs, {PlannedTransaction.__counter__} transactions" ) sign_transaction_tree(segwit_utxo, parameters) save(segwit_utxo) # TODO: Delete the ephemeral keys. # (graph generation can wait until after key deletion) if parameters["enable_graphviz"] == True: generate_graphviz(segwit_utxo, parameters, output_filename="output.gv") # Create another planned transaction tree this time using # OP_CHECKTEMPLATEVERIFY from bip119. This can be performed after key # deletion because OP_CTV standard template hashes are not based on keys # and signatures. make_planned_transaction_tree_using_bip119_OP_CHECKTEMPLATEVERIFY( initial_tx, parameters=parameters) save(segwit_utxo, filename="transaction-store.ctv.json") # A vault has been established. Write the vaultfile. make_vaultfile()
SelectParams("regtest") connection = Proxy() if connection._call("getblockchaininfo")["chain"] != "regtest": sys.stderr.write("This example is intended for regtest only.\n") sys.exit(1) # Create the (in)famous correct brainwallet secret key. h = hashlib.sha256(b'correct horse battery staple').digest() seckey = CBitcoinSecret.from_secret_bytes(h) # Create an address from that private key. public_key = seckey.pub scriptPubKey = CScript([OP_0, Hash160(public_key)]) address = P2WPKHBitcoinAddress.from_scriptPubKey(scriptPubKey) # Give the private key to bitcoind (for ismine, listunspent, etc). connection._call("importprivkey", str(seckey)) # Check if there's any funds available. unspentness = lambda: connection._call("listunspent", 6, 9999, [str(address)], True, {"minimumAmount": 1.0}) unspents = unspentness() while len(unspents) == 0: # mine some funds into the address connection._call("generatetoaddress", 110, str(address)) unspents = unspentness() # Choose the first UTXO, let's spend it! unspent_utxo_details = unspents[0]