#probably the best solution would be ammending Peter's library: script.CTxIn.stream_selialize #f.write(struct.pack_into(b"<I", 22,value) and add it to the CMutableTxIn. I didn't have the time #to experience with it. unspent['outpoint'] = CMutableTxIn(COutPoint(lx(unspent['txid']), unspent['vout']), nSequence=0xefffffff) del unspent['txid'] del unspent['vout'] total_amount += unspent['amount'] txin.append(unspent['outpoint']) txout = [] txout.append( CMutableTxOut(total_amount, CBitcoinAddress(P2PKH_to_address).to_scriptPubKey())) #This is a version 2 transaction and a time locked too tx = CMutableTransaction(txin, txout, nLockTime=delay_value, nVersion=2) #Create the redeem script that should become part of scriptSig txin_redeemScript = CScript([ byte_delay, OP_NOP3, OP_DROP, OP_DUP, OP_HASH160, Hash160(seckey_pub), OP_EQUALVERIFY, OP_CHECKSIG ]) sighash = SignatureHash(txin_redeemScript, tx, 0, SIGHASH_ALL) sig = CKey(x(decode_hex_priv)).sign(sighash) + bytes([SIGHASH_ALL]) #I couldn't solve this issue. Something is not right here although I followed
def build_bitcoin_tx(utxos, receiver_addr, amount, fee, key_file, change_addr=None): sorted_utxos = utxos.sort_values(by=['block_height', 'value'], ascending=[True, False]) total_balance = 0 utxos_to_spend = [] for i, utxo in sorted_utxos.iterrows(): if total_balance >= amount + fee: break balance = utxo['value'] utxos_to_spend.append({ 'address': utxo['address'], 'txHash': utxo['tx_hash'], 'blockHeight': int(utxo['block_height']), 'outputIdx': int(utxo['tx_output_n']), 'value': int(utxo['value']), 'sigScript': utxo['script'] }) total_balance += balance if total_balance < amount + fee: raise ( f"Not enough balance to send! total balance: {total_balance}, required: {amount + fee}, amount to send: {amount}, fee: {fee}" ) if not change_addr: change_addr = utxos_to_spend[0]['address'] txins = [] for utxo in utxos_to_spend: txin = CMutableTxIn(COutPoint(lx(utxo['txHash']), utxo['outputIdx'])) txins.append(txin) txouts = [] txout = CMutableTxOut(amount, CBitcoinAddress(receiver_addr).to_scriptPubKey()) txouts.append(txout) outs = [{'address': receiver_addr, 'value': amount}] if total_balance > amount + fee: change = total_balance - amount - fee txout = CMutableTxOut(change, CBitcoinAddress(change_addr).to_scriptPubKey()) txouts.append(txout) outs.append({'address': change_addr, 'value': change}) tx = CMutableTransaction(txins, txouts) sig_data = [] for i, utxo in enumerate(utxos_to_spend): sighash = SignatureHash(CScript(x(utxo['sigScript'])), tx, i, SIGHASH_ALL) seckey = fetch_key_for_address(key_file, utxo['address']) if not seckey: raise ( f"Could not find private key for address: {utxo['address']}") sig = seckey.sign(sighash) + bytes([SIGHASH_ALL]) sig_data.append([sig, seckey.pub]) for i, txin in enumerate(txins): txin.scriptSig = CScript(sig_data[i]) tx_hash = b2lx( hashlib.sha256(hashlib.sha256(tx.serialize()).digest()).digest()) return utxos_to_spend, outs, fee, b2x(tx.serialize()), tx_hash
def getaccountaddress(self, account=None): """Return the current Bitcoin address for receiving payments to this account.""" r = self._call('getaccountaddress', account) return CBitcoinAddress(r)
type=str, help='Destination address') parser.add_argument('amount', action='store', type=float, help='Amount to send') args = parser.parse_args() if args.verbose: logging.root.setLevel('DEBUG') if args.testnet: bitcoin.SelectParams('testnet') args.amount = int(args.amount * COIN) args.address = CBitcoinAddress(args.address) rpc = bitcoin.rpc.Proxy() def check_full_rbf_optin(tx): """Return true if tx opts in to full-RBF""" for vin in tx.vin: if vin.nSequence < 0xFFFFFFFF - 1: return True return False tx1 = None if args.prev_txid is not None: try:
def get_keys(funder_address, redeemer_address): fundpubkey = CBitcoinAddress(funder_address) redeempubkey = CBitcoinAddress(redeemer_address) # fundpubkey = bitcoind.getnewaddress() # redeempubkey = bitcoind.getnewaddress() return fundpubkey, redeempubkey
def createTransaction(txid, vout, value, output_address, escrow_index, state): """ Create an transaction from an escrow address, defined by a previous txid, to the output address """ # This will be the return value, a little indirection to not return a Share. tx_deferred = Deferred() def _fire_response(tx): tx_deferred.callback(tx) return def _signatureCallback(signature, shares, hash, transaction): return signature def _computeSignatureShare(hash): def _get_R(R_deferred): R = R_deferred.x() return R def _compute_summand2(R, k_inv_d_share): summand2 = ConstantMultiplicationSmpcValue(state) summand2_deferred = summand2.initialize(R, k_inv_d_share) return summand2_deferred def _final_sum(deferreds): global transaction_ctr summand1 = WrapperSmpcValue(state) summand2 = WrapperSmpcValue(state) summand1.initialize(deferreds[0][1]) summand2.initialize(deferreds[1][1]) s = AdditionSmpcValue( state) # add secret values of summand1, summand2 (see below) s_deferred = s.initialize(summand1, summand2) return s_deferred # Set parameters for creating the share of the signature e = int(hexlify(hash), 16) kG_deferred = state.smpc.getValue('k', escrow_index).getPublicValue() R = state.smpc.getValue('k', escrow_index).getPublicValue() k_inv_share = state.smpc.getValue('ki', escrow_index) k_inv_d_share = state.smpc.getValue('kid', escrow_index) """ Calculation to be performed: S_share = e * k_inv_share + R * k_inv_d_share """ try: summand1 = ConstantMultiplicationSmpcValue(state) summand1_deferred = summand1.initialize(e, k_inv_share) kG_deferred.addCallback(_get_R) kG_deferred.addCallback(_compute_summand2, k_inv_d_share=k_inv_d_share) R.addCallback(_get_R) S_share = DeferredList([summand1_deferred, kG_deferred]) S_share.addCallback(_final_sum) return (S_share, R) except BaseException as ex: log.critical('Error in signature generation! Error: ' + str(ex)) raise RuntimeError('signing_share_failed') def _signatureToDER(S, R): S_der = der.encode_integer(int(S)) R_der = der.encode_integer(int(R)) signature_der = der.encode_sequence(R_der, S_der) + chr(0x01) return signature_der def _reconstruct_signature(S_share): try: global transaction_ctr final_sum = WrapperSmpcValue(state) final_sum.initialize(S_share) S = state.smpc.newValue('rec', state, 'S', transaction_ctr) return S.initialize(final_sum) except BaseException as e: log.critical('S reconstruction failed! ' + str(e)) raise RuntimeError('signing_reconstruct_failed') def _computeSignature(S_share_R): S_share = S_share_R[0][1] R = S_share_R[1][1] def _extract_signature(_): global transaction_ctr signature = state.smpc.getValue('S', transaction_ctr).getPublicValue() transaction_ctr += 1 return signature signature = _reconstruct_signature(S_share) signature.addCallback(_extract_signature) signature.addCallback(_signatureToDER, R=R) return signature def _computeTransaction(signature, tx, script_pubkey, pubkey): txin = tx.vin[0] txin.scriptSig = bc.core.script.CScript([signature, pubkey]) try: VerifyScript(txin.scriptSig, script_pubkey, tx, 0, (bc.core.scripteval.SCRIPT_VERIFY_P2SH, )) except BaseException as e: log.error(str(e)) raise RuntimeError('signing_failed') transaction_serialized = bc.core.b2x(tx.serialize()) return transaction_serialized cpub = CPubKey(state.input.getInputPeer('id', escrow_index)['pubkey']) txid = bc.core.lx(txid) # TXIN information txin = bc.core.CMutableTxIn(bc.core.COutPoint(txid, vout)) txin_scriptPubKey = bc.core.script.CScript([ bc.core.script.OP_DUP, bc.core.script.OP_HASH160, bc.core.Hash160(cpub), bc.core.script.OP_EQUALVERIFY, bc.core.script.OP_CHECKSIG ]) # TXOUT information txout = bc.core.CMutableTxOut( int(value * bc.core.COIN), CBitcoinAddress(output_address).to_scriptPubKey()) # Create unsigned transaction tx = bc.core.CMutableTransaction([txin], [txout]) # Create signature hash sighash = bc.core.script.SignatureHash(txin_scriptPubKey, tx, 0, bc.core.script.SIGHASH_ALL) (S_share, R) = _computeSignatureShare(sighash) deferreds = DeferredList([S_share, R]) deferreds.addCallback(_computeSignature) deferreds.addCallback(_computeTransaction, tx=tx, script_pubkey=txin_scriptPubKey, pubkey=cpub) deferreds.addCallback(_fire_response) return tx_deferred
from bitcoin import SelectParams from bitcoin.base58 import decode from bitcoin.wallet import CBitcoinAddress, CBitcoinSecret, P2PKHBitcoinAddress SelectParams('testnet') #Kye37LGjYaDHEW5hreTtq3Mah2537tZdPFMUdcGHwvABJK2e2F5X # TODO: Fill this in with your private key. my_private_key = CBitcoinSecret( 'cQhezNyeQknhnXrerkvV8yxiUnFWHQyaeQUinqnt7Qrmh7GsTnDv') my_public_key = my_private_key.pub my_address = P2PKHBitcoinAddress.from_pubkey(my_public_key) faucet_address = CBitcoinAddress('mv4rnyY3Su5gjcDNzbMLKBQkBicCtHUtFB')
args = parser.parse_args() logging.root.setLevel('DEBUG') if args.testnet: bitcoin.SelectParams('testnet') rpc = bitcoin.rpc.Proxy() args.dust = int(args.dust * COIN) feeperbyte1 = args.fee1 / 1000 * COIN feeperbyte2 = args.fee2 / 1000 * COIN # Construct payment tx payment_address = CBitcoinAddress(args.address) payment_txout = CMutableTxOut(int(args.amount * COIN), payment_address.to_scriptPubKey()) change_txout = CMutableTxOut(0, rpc.getnewaddress().to_scriptPubKey()) tx = CMutableTransaction() tx.vout.append(change_txout) tx.vout.append(payment_txout) # Add all undesirable txouts meant to reduce propagation if args.op_return: op_ret_txout = CMutableTxOut( 0, CScript([OP_RETURN, b'\x00unsuccessful double-spend attempt\x00'])) tx.vout.append(op_ret_txout)
def get_keys(self, funder_address, redeemer_address): fundpubkey = CBitcoinAddress(funder_address) redeempubkey = CBitcoinAddress(redeemer_address) return fundpubkey, redeempubkey
block_hash = bitcoin_rpc.generate(100)[0] txin = CMutableTxIn(COutPoint(lx(coinbase["txid"]), 0)) # Now select input we received at the "burn" address. listunspent = bitcoin_rpc.listunspent(0, 9999, [str(address)]) assert (len(listunspent) == 1) unspent = listunspent[0] txin2 = CMutableTxIn(COutPoint(lx(unspent["txid"]), unspent["vout"])) # Create an output that sends the all input's coins minus fee # to a newly created address. dest_addr = bitcoin_rpc.getnewaddress() coinbase_amount = coinbase["vout"][0]["value"] fee = 10000 # in satoshi out_amount = coinbase_amount * COIN + burn_amount * COIN - fee txout = CMutableTxOut(out_amount, CBitcoinAddress(dest_addr).to_scriptPubKey()) # Create the transaction tx = CMutableTransaction([txin, txin2], [txout]) # Sign inputs. Start with the coinbase input. coinbase_address = coinbase["vout"][0]["scriptPubKey"]["addresses"][0] seckey_coinbase = CBitcoinSecret(bitcoin_rpc.dumpprivkey(coinbase_address)) sighash = SignatureHash(CScript(x(coinbase["vout"][0]["scriptPubKey"]["hex"])), tx, 0, SIGHASH_ALL) sig = seckey_coinbase.sign(sighash) + bytes([SIGHASH_ALL]) txin.scriptSig = CScript([sig]) # Sign "burn" address input. sighash = SignatureHash(CScript(multisig_script), tx, 1, SIGHASH_ALL) sig = seckey_multisig.sign(sighash) + bytes([SIGHASH_ALL])
def pay(self, pay, change_address=None, allow_zero_conf=False, randomize_change_idx=True, fee_strategy='optimal'): send = {} if isinstance(pay, list): for address, value in pay: send[address] = value else: send = pay coin_selection = self.client.coin_selection( self.identifier, send, lockUTXO=True, allow_zero_conf=allow_zero_conf, fee_strategy=fee_strategy) utxos = coin_selection['utxos'] fee = coin_selection['fee'] change = coin_selection['change'] if change > 0: if change_address is None: _, change_address = self.get_new_address_pair() send[change_address] = change txins = [] for utxo in utxos: txins.append(CMutableTxIn(COutPoint(lx(utxo['hash']), utxo['idx']))) txouts = [] change_txout = None for address, value in send.items(): txout = CMutableTxOut(value, CBitcoinAddress(address).to_scriptPubKey()) if address == change_address: change_txout = txout txouts.append(txout) # randomly move the change_txout if randomize_change_idx and change_txout: txouts.remove(change_txout) txouts.insert(random.randrange(len(txouts) + 1), change_txout) tx = CMutableTransaction(txins, txouts) for idx, utxo in enumerate(utxos): path = utxo['path'].replace("M/", "") key = self.primary_private_key.subkey_for_path(path) redeemScript = CScript(x(utxo['redeem_script'])) sighash = SignatureHash(redeemScript, tx, idx, SIGHASH_ALL) ckey = CBitcoinSecret(key.wif()) sig = ckey.sign(sighash) + struct.pack("B", SIGHASH_ALL) txins[idx].scriptSig = CScript([OP_0, sig, redeemScript]) signed = self.client.send_transaction(self.identifier, b2x(tx.serialize()), [utxo['path'] for utxo in utxos], check_fee=True) return signed['txid']
def test_unvault_txout(bitcoind): """Test that unvault_txout() produces a valid and conform txo. Note that we use python-bitcoinlib for this one, as signrawtransactionwithkey is (apparently?) not happy dealing with exotic scripts. Note also that bitcoinlib's API uses sats, while bitcoind's one uses BTC.. """ amount = 50 * COIN - 500 # The stakeholders stk_privkeys = [CKey(os.urandom(32)) for i in range(4)] stk_pubkeys = [k.pub for k in stk_privkeys] # The cosigning server serv_privkey = CKey(os.urandom(32)) # First, pay to the unvault tx script txo = unvault_txout(stk_pubkeys, serv_privkey.pub, amount) txo_addr = str(CBitcoinAddress.from_scriptPubKey(txo.scriptPubKey)) amount_for_bitcoind = float(Decimal(amount) / Decimal(COIN)) txid = bitcoind.pay_to(txo_addr, amount_for_bitcoind) # We can spend it immediately if all stakeholders sign (emergency or cancel # tx) txin = CTxIn(COutPoint(lx(txid), 0)) amount_min_fees = amount - 500 addr = bitcoind.getnewaddress() new_txo = CTxOut(amount_min_fees, CBitcoinAddress(addr).to_scriptPubKey()) tx = CMutableTransaction([txin], [new_txo], nVersion=2) # We can't test the signing against bitcoind, but we can at least test the # transaction format bitcoind_tx = bitcoind.rpc.createrawtransaction([ {"txid": txid, "vout": 0} ], [ {addr: float(Decimal(amount_min_fees) / Decimal(COIN))} ]) assert b2x(tx.serialize()) == bitcoind_tx tx_hash = SignatureHash(unvault_script(*stk_pubkeys, serv_privkey.pub), tx, 0, SIGHASH_ALL, amount, SIGVERSION_WITNESS_V0) sigs = [key.sign(tx_hash) + bytes([SIGHASH_ALL]) for key in stk_privkeys[::-1]] # Note the reverse here witness_script = [*sigs, unvault_script(*stk_pubkeys, serv_privkey.pub)] witness = CTxInWitness(CScriptWitness(witness_script)) tx.wit = CTxWitness([witness]) bitcoind.send_tx(b2x(tx.serialize())) assert bitcoind.has_utxo(addr) # If two out of three stakeholders sign, we need the signature from the # cosicosigning server and we can't spend it before 6 blocks (csv). # Pay back to the unvault tx script txo = unvault_txout(stk_pubkeys, serv_privkey.pub, amount) txo_addr = str(CBitcoinAddress.from_scriptPubKey(txo.scriptPubKey)) txid = bitcoind.pay_to(txo_addr, amount_for_bitcoind) # Reconstruct the transaction but with only two stakeholders signatures txin = CTxIn(COutPoint(lx(txid), 0), nSequence=6) amount_min_fees = amount - 500 addr = bitcoind.getnewaddress() new_txo = CTxOut(amount_min_fees, CBitcoinAddress(addr).to_scriptPubKey()) tx = CMutableTransaction([txin], [new_txo], nVersion=2) # We can't test the signing against bitcoind, but we can at least test the # transaction format bitcoind_tx = bitcoind.rpc.createrawtransaction([ {"txid": txid, "vout": 0, "sequence": 6} ], [ {addr: float(Decimal(amount_min_fees) / Decimal(COIN))} ]) assert b2x(tx.serialize()) == bitcoind_tx tx_hash = SignatureHash(unvault_script(*stk_pubkeys, serv_privkey.pub), tx, 0, SIGHASH_ALL, amount, SIGVERSION_WITNESS_V0) # The cosigning server sigs = [serv_privkey.sign(tx_hash) + bytes([SIGHASH_ALL])] # We fail the third CHECKSIG !! sigs += [bytes(0)] sigs += [key.sign(tx_hash) + bytes([SIGHASH_ALL]) for key in stk_privkeys[::-1][2:]] # Just the first two witness_script = [*sigs, unvault_script(*stk_pubkeys, serv_privkey.pub)] witness = CTxInWitness(CScriptWitness(witness_script)) tx.wit = CTxWitness([witness]) # Relative locktime ! for i in range(5): with pytest.raises(VerifyRejectedError, match="non-BIP68-final"): bitcoind.send_tx(b2x(tx.serialize())) bitcoind.generate_block(1) # It's been 6 blocks now bitcoind.send_tx(b2x(tx.serialize())) assert bitcoind.has_utxo(addr)