def into_transaction(self, dust_secret: CBitcoinSecret, dust_outpoint: OutPointWithTx, feerate): if dust_outpoint.prevout.scriptPubKey != pubkey_to_P2PKH_scriptPubkey( dust_secret.pub): print(b2x(dust_outpoint.prevout.scriptPubKey)) print(b2x(pubkey_to_P2PKH_scriptPubkey(dust_secret.pub))) raise Exception("Outpoint has incorrect scriptPubKey") sum_in = dust_outpoint.prevout.nValue fees = int(tx_size(1, 2) / 1000 * feerate) refund = sum_in - fees - self._life_signal_amount print('fee: %f' % fees) print('amount: %f' % (sum_in - fees)) redeemScript = self.redeemScript unsigned_tx = CTransaction([CTxIn(dust_outpoint.outpoint)], [ CTxOut(self._life_signal_amount, redeemScript.to_p2sh_scriptPubKey()), CTxOut(refund, pubkey_to_P2PKH_scriptPubkey(dust_secret.pub)) ]) # spend the dust input sighash = SignatureHash(dust_outpoint.prevout.scriptPubKey, unsigned_tx, 0, SIGHASH_ALL) sig = dust_secret.sign(sighash) + bytes([SIGHASH_ALL]) sigScript = CScript([sig, dust_secret.pub]) signed_input = [CTxIn(unsigned_tx.vin[0].prevout, sigScript)] return CTransaction(signed_input, unsigned_tx.vout, unsigned_tx.nLockTime)
def overridevaulttx(self, fromvaultaddress, toaddress): vault = self.getvault(fromvaultaddress) # select the input addresses received = self.chaindb.listallreceivedbyvault(fromvaultaddress) if not received: self.logger.warning("Empty vault, exiting, return") return None, None received = received.values()[0] if received['value'] < 2 * utils.calculate_fees(None): self.logger.warning("Insufficient funds in vault, exiting, return") return None, None # calculate remaining amount amount = received['value'] - 2 * utils.calculate_fees(None) # create transaction tx = CTransaction() # to the receiver txout = CTxOut() txout.nValue = amount txout.scriptPubKey = utils.address_to_pay_to_pubkey_hash(toaddress) tx.vout.append(txout) # from the sender nValueIn = 0 nValueOut = amount txin = CTxIn() txin.prevout = COutPoint() txin.prevout.hash = received['txhash'] txin.prevout.n = received['n'] txin.scriptSig = received['scriptPubKey'] tx.vin.append(txin) # calculate nValueIn nValueIn = received['value'] # calculate the total excess amount excessAmount = nValueIn - nValueOut # calculate the fees fees = utils.calculate_fees(tx) # calculate txhash tx.calc_sha256() txhash = str(tx.sha256) key = CKey() key.set_pubkey(vault['public_key']) key.set_privkey(vault['private_key']) signature = key.sign(txhash) # get the script vaultscript = utils.create_vault_script(vault['address'], \ vault['master_address'], vault['timeout'], vault['maxfees']) scriptSig = chr(OP_VAULT_OVERRIDE) + chr(len(vault['master_public_key'])) + \ vault['master_public_key'] + chr(len(signature)) + signature + \ chr(len(vaultscript)) + vaultscript self.logger.debug("Adding signature: %s" % binascii.hexlify(scriptSig)) txin.scriptSig = scriptSig return amount, tx
def __create_new_timestamp_tx_template(self, outpoint, txout_value, change_scriptPubKey): """Create a new timestamp transaction template The transaction created will have one input and two outputs, with the timestamp output set to an invalid dummy. The fee is set to zero, but nSequence is set to opt-in to transaction replacement, so you can find an appropriate fee iteratively. """ return CTransaction([CTxIn(outpoint, nSequence=0xfffffffd)], [CTxOut(txout_value, change_scriptPubKey), CTxOut(-1, CScript())])
def test_init_with_field_keyword_args(self): ins = ( CTxIn(COutPoint(lx('537ecb89e5ed7e872f988447432e6791c0a58b069c4ec8647e1683a383e867a3'), 0), x('473044022043b9aee9187effd7e6c7bc444b09162570f17e36b4a9c02cf722126cc0efa3d502200b3ba14c809fa9a6f7f835cbdbbb70f2f43f6b30beaf91eec6b8b5981c80cea50121025edf500f18f9f2b3f175f823fa996fbb2ec52982a9aeb1dc2e388a651054fb0f')) ) outs = ( CTxOut(114263, x('76a91495efca2c6a6f0e0f0ce9530219b48607a962e77788ac')), CTxOut(2125893, x('76a914f28abfb465126d6772dcb4403b9e1ad2ea28a03488ac')) ) fields_data = {'Timestamp': 1432478808} tx = Transaction(ins, outs, 0, 2, peercoin_fields, fields_data) self.assertEqual(tx.fields, peercoin_fields) self.assertEqual(tx.Timestamp, 1432478808)
def withdrawfromvault(self, fromvaultaddress, toaddress, amount): vault = self.getvault(fromvaultaddress) received = self.chaindb.listreceivedbyvault(fromvaultaddress) received = received.values()[0] if received['value'] < amount + 2 * utils.calculate_fees(None): self.logger.warning("Insufficient funds in vault, exiting, return") return # create transaction tx = CTransaction() # to the receiver txout = CTxOut() txout.nValue = amount txout.scriptPubKey = utils.address_to_pay_to_pubkey_hash(toaddress) tx.vout.append(txout) # from the sender nValueIn = 0 nValueOut = amount txin = CTxIn() txin.prevout = COutPoint() txin.prevout.hash = received['txhash'] txin.prevout.n = received['n'] txin.scriptSig = received['scriptPubKey'] tx.vin.append(txin) # calculate nValueIn nValueIn = received['value'] # calculate the total excess amount excessAmount = nValueIn - nValueOut # calculate the fees fees = 2 * utils.calculate_fees(tx) # create change transaction, if there is any change left if excessAmount > fees: change_txout = CTxOut() change_txout.nValue = excessAmount - fees account = self.getaccount() changeaddress = fromvaultaddress self.logger.debug("Change address: %s" % changeaddress) change_txout.scriptPubKey = \ utils.vault_address_to_pay_to_vault_script(changeaddress) tx.vout.append(change_txout) # calculate txhash tx.calc_sha256() txhash = str(tx.sha256) key = CKey() key.set_pubkey(vault['public_key']) key.set_privkey(vault['private_key']) signature = key.sign(txhash) vaultscript = utils.create_vault_script(vault['address'], \ vault['master_address'], vault['timeout'], vault['maxfees']) scriptSig = chr(OP_VAULT_WITHDRAW) + chr(len(signature)) + signature + \ chr(len(vaultscript)) + vaultscript self.logger.debug("Adding signature: %s" % binascii.hexlify(scriptSig)) txin.scriptSig = scriptSig return tx
def add_output(self, serial_id: int, script: str, sats: int) -> None: txout = CTxOut(sats, CScript(bytes.fromhex(script))) self.outputs.append({'output': txout, 'serial_id': serial_id})
def __update_timestamp_tx(self, old_tx, new_commitment, new_min_block_height, relay_feerate): """Update an existing timestamp transaction Returns the old transaction with a new commitment, and with the fee bumped appropriately. """ delta_fee = int(len(old_tx.serialize()) * relay_feerate) old_change_txout = old_tx.vout[0] assert old_change_txout.nValue - delta_fee > relay_feerate * 3 # FIXME: handle running out of money! return CTransaction(old_tx.vin, [CTxOut(old_change_txout.nValue - delta_fee, old_change_txout.scriptPubKey), CTxOut(0, CScript([OP_RETURN, new_commitment]))], nLockTime=new_min_block_height)
def test_emergency_txout(bitcoind): """Test mostly the emergency tx locktime""" amount = Decimal("50") - Decimal("500") / Decimal(COIN) privkeys = [CKey(os.urandom(32)) for _ in range(4)] pubkeys = [k.pub for k in privkeys] txo = emergency_txout(pubkeys, COIN * amount) addr = str(CBitcoinAddress.from_scriptPubKey(txo.scriptPubKey)) # This makes a transaction with only one vout txid = bitcoind.pay_to(addr, amount) new_amount = amount - Decimal("500") / Decimal(COIN) addr = bitcoind.getnewaddress() txin = CTxIn(COutPoint(lx(txid), 0), nSequence=4464) txout = CTxOut(new_amount * COIN, CBitcoinAddress(addr).to_scriptPubKey()) tx = CMutableTransaction([txin], [txout], nVersion=2) tx_hash = SignatureHash(emergency_script(pubkeys), tx, 0, SIGHASH_ALL, int(amount * COIN), SIGVERSION_WITNESS_V0) sigs = [k.sign(tx_hash) + bytes([SIGHASH_ALL]) for k in privkeys] witness_script = [bytes(0), *sigs, emergency_script(pubkeys)] tx.wit = CTxWitness([CTxInWitness(CScriptWitness(witness_script))]) # 1 month of locktime bitcoind.generate_block(4464 - 2) with pytest.raises(VerifyRejectedError, match="non-BIP68-final"): bitcoind.send_tx(tx.serialize().hex()) bitcoind.generate_block(1) bitcoind.send_tx(tx.serialize().hex()) assert bitcoind.has_utxo(addr)
def as_tx(self): sum_in = sum(prevtx.nValue for _, prevtx, _ in self.prevouts) sig_size = sum(redeemer.spendbytes for _, _, redeemer in self.prevouts) tx_size = ( 4 + # version field 2 + # # of txins len(self.prevouts) * 41 + # txins, excluding sigs sig_size + # txins, sigs only 1 + # # of txouts 34 + # txout 4 # nLockTime field ) feerate = int(self.proxy._call('estimatefee', 1) * COIN) # satoshi's per KB if feerate <= 0: feerate = 10000 fees = int(tx_size * feerate / 1000) tx = CMutableTransaction( [CTxIn(outpoint, nSequence=0) for outpoint, _, _ in self.prevouts], [CTxOut(sum_in - fees, self.payto.to_scriptPubKey())], 0) for n, (_, _, redeemer) in enumerate(self.prevouts): redeemer.mutate_spend(tx, n) unsigned_tx = CTransaction.from_tx(tx) for n, (_, _, redeemer) in enumerate(self.prevouts): txin = CMutableTxIn.from_txin(tx.vin[n]) txin.scriptSig = redeemer.sign_spend(unsigned_tx, n) tx.vin[n] = CTxIn.from_txin(txin) print(b2x(tx.serialize()))
def close_tx(self, fee: int, privkey_dest: str) -> str: """Create a (mutual) close tx""" txin = CTxIn(COutPoint(bytes.fromhex(self.txid), self.output_index)) out_privkey = privkey_expand(privkey_dest) txout = CTxOut(self.amount - fee, CScript([script.OP_0, Hash160(coincurve.PublicKey.from_secret(out_privkey.secret).format())])) tx = CMutableTransaction(vin=[txin], vout=[txout]) sighash = script.SignatureHash(self.redeemscript(), tx, inIdx=0, hashtype=script.SIGHASH_ALL, amount=self.amount, sigversion=script.SIGVERSION_WITNESS_V0) sigs = [key.sign(sighash, hasher=None) for key in self.funding_privkeys_for_tx()] # BOLT #3: # ## Closing Transaction # ... # * `txin[0]` witness: `0 <signature_for_pubkey1> <signature_for_pubkey2>` witness = CScriptWitness([bytes(), sigs[0] + bytes([script.SIGHASH_ALL]), sigs[1] + bytes([script.SIGHASH_ALL]), self.redeemscript()]) tx.wit = CTxWitness([CTxInWitness(witness)]) return tx.serialize().hex()
def build_bounce_tx(self, txid_hex): #Generate p2sh script pub key. redeem_script = self.fund_redeem_script(self.my) redeem_script_hash160 = self.hash160_script(redeem_script) txin_script_pub_key = CScript( [OP_HASH160, redeem_script_hash160["bin"], OP_EQUAL]) #Generate address to receive bounce. if "bounce" not in self.key_pairs: self.key_pairs["bounce"] = self.key_pair_from_address( self.jsonrpc[self.my].getnewaddress(), self.my) #Setup tx inputs and outputs. txid = lx(txid_hex) vout = 0 txin = CTxIn(COutPoint(txid, vout), CScript(), 0) #Sequence number 0. txout = CTxOut( (self.send_amount - decimal.Decimal(coinbend.config["mining_fee"]["standard"])) * COIN, CBitcoinAddress( self.key_pairs["bounce"]["addr"]["base58"]).to_scriptPubKey()) #Locktime is unsigned int 4, unix timestamp in little endian format. #(Conversion to little endian is handled by the library already.) nlock_time = datetime.datetime.now() + datetime.timedelta( seconds=self.future_minutes * 60) nlock_time = int(nlock_time.strftime("%s")) #Create unsigned transaction. tx = CTransaction([txin], [txout], nlock_time) return b2x(tx.serialize())
def spend_command(args): args.addr = CBitcoinAddress(args.addr) redeemScript = hodl_redeemScript(args.privkey, args.nLockTime) scriptPubKey = redeemScript.to_p2sh_scriptPubKey() proxy = bitcoin.rpc.Proxy() prevouts = [] for prevout in args.prevouts: try: txid, n = prevout.split(':') txid = lx(txid) n = int(n) outpoint = COutPoint(txid, n) except ValueError: args.parser.error('Invalid output: %s' % prevout) try: prevout = proxy.gettxout(outpoint) except IndexError: args.parser.error('Outpoint %s not found' % outpoint) prevout = prevout['txout'] if prevout.scriptPubKey != scriptPubKey: args.parser.error('Outpoint not correct scriptPubKey') prevouts.append((outpoint, prevout)) sum_in = sum(prev_txout.nValue for outpoint, prev_txout in prevouts) tx_size = ( 4 + # version field 2 + # # of txins len(prevouts) * 153 + # txins, including sigs 1 + # # of txouts 34 + # txout 4 # nLockTime field ) feerate = int(proxy._call('estimatefee', 1) * COIN) # satoshi's per KB if feerate <= 0: feerate = 10000 fees = int(tx_size / 1000 * feerate) unsigned_tx = CTransaction( [CTxIn(outpoint, nSequence=0) for outpoint, prevout in prevouts], [CTxOut(sum_in - fees, args.addr.to_scriptPubKey())], args.nLockTime) signed_tx = CTransaction([ CTxIn(txin.prevout, spend_hodl_redeemScript(args.privkey, args.nLockTime, unsigned_tx, i), nSequence=0) for i, txin in enumerate(unsigned_tx.vin) ], unsigned_tx.vout, unsigned_tx.nLockTime) print(b2x(signed_tx.serialize()))
def vault_txout(pubkeys, value): """The output of the funding transaction. :param pubkeys: A list containing the pubkey of each stakeholder, as bytes. :param value: The output value in satoshis. :return: A CTxOut paying to a 4of4. """ script = vault_script(pubkeys) p2wsh = CScript([OP_0, hashlib.sha256(script).digest()]) return CTxOut(value, p2wsh)
def create_timestamp(timestamp, calendar_urls, setup_bitcoin=False): """Create a timestamp calendar_urls - List of calendar's to use setup_bitcoin - False if Bitcoin timestamp not desired; set to args.setup_bitcoin() otherwise. """ if setup_bitcoin: proxy = setup_bitcoin() unfunded_tx = CTransaction([], [CTxOut(0, CScript([OP_RETURN, timestamp.msg]))]) r = proxy.fundrawtransaction(unfunded_tx) # FIXME: handle errors funded_tx = r['tx'] r = proxy.signrawtransaction(funded_tx) assert r['complete'] signed_tx = r['tx'] txid = proxy.sendrawtransaction(signed_tx) logging.info('Sent timestamp tx') blockhash = None while blockhash is None: logging.info('Waiting for timestamp tx %s to confirm...' % b2lx(txid)) time.sleep(1) r = proxy.gettransaction(txid) if 'blockhash' in r: # FIXME: this will break when python-bitcoinlib adds RPC # support for gettransaction, due to formatting differences blockhash = lx(r['blockhash']) logging.info('Confirmed by block %s' % b2lx(blockhash)) block = proxy.getblock(blockhash) r = proxy.getblockheader(blockhash, True) blockheight = r['height'] # We have a block hash! We can now generate the attestation from the block. block_timestamp = make_timestamp_from_block(timestamp.msg, block, blockheight) assert block_timestamp is not None timestamp.merge(block_timestamp) for calendar_url in calendar_urls: remote = remote_calendar(calendar_url) logging.info('Submitting to remote calendar %s' % calendar_url) calendar_timestamp = remote.submit(timestamp.msg) timestamp.merge(calendar_timestamp)
def get_outputs(self): vout = [] for i in range(self.model.rowCount()): value, ok = self.model.item(i, 0).data(RawRole).toInt() if not ok: raise Exception('Could not get satoshis for output %d' % i) return out_script = Script( str(self.model.item(i, 1).data(RawRole).toString()).decode('hex')) i_output = CTxOut(value, out_script.get_hex().decode('hex')) vout.append(i_output) return vout
def emergency_txout(pubkeys, value): """The "deep vault". Different pubkeys, and a big timelock. :param pubkeys: A list containing the offline pubkey of each of the stakeholders, as bytes. :param value: The output value in satoshis. :return: A CTxOut paying to a 4of4 of all stakeholers' offline pubkeys after approximatively a month. """ script = emergency_script(pubkeys) p2wsh = CScript([OP_0, hashlib.sha256(script).digest()]) return CTxOut(value, p2wsh)
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 get_first_vout_from_tx_json(cls, tx_json: dict) -> CTxOut: ''' Adapter method for returning first vout. Args: tx_json (dict): dictionary with transaction details Returns: CTxOut: transaction output ''' cscript = script.CScript.fromhex( tx_json['vout'][0]['scriptPubKey']['hex']) nValue = to_base_units(float(tx_json['vout'][0]['value'])) return CTxOut(nValue, cscript)
def accuse(self, dust_op: OutPointWithTx, wallet_op: OutPointWithTx, user_index, secret_sgx): ls_tx = self._life_signals[user_index].into_transaction( secret_sgx, dust_op, feerate) # FIXME: hardcode zero here because life signal is always the first output in a life signal tx nOut_for_ls = 0 ls = self._life_signals[user_index] if ls_tx.vout[ nOut_for_ls].scriptPubKey != ls.redeemScript.to_p2sh_scriptPubKey( ): raise Exception("SGX can't spend the life signal") if wallet_op.prevout.scriptPubKey != self.scriptPubkey(): raise Exception("wallet utxo mismatch") print('ls value: %f' % ls_tx.vout[nOut_for_ls].nValue) sum_in = ls_tx.vout[0].nValue + wallet_op.prevout.nValue fees = int(tx_size(2, 1) / 1000 * feerate) print('fee: %f' % fees) print('amount: %f' % (sum_in - fees)) # note: nVersion=2 is required by CSV unsigned_tx = CTransaction([ CTxIn(COutPoint(ls_tx.GetTxid(), nOut_for_ls), nSequence=ls.relative_timeout), CTxIn(wallet_op.outpoint) ], [ CTxOut(wallet_op.prevout.nValue, self.scriptPubkey(exclude_indices=(user_index, ))) ], nVersion=2) # spend the life signal lifesignal_sigScript = self._life_signals[ user_index].scriptSig_by_key2(unsigned_tx, 0) # spend the wallet wallet_sigScript = self._scriptSig_by_sgx(secret_sgx, unsigned_tx, 1) # return the life signal as well as both transactions return ls, ls_tx, CTransaction([ CTxIn(unsigned_tx.vin[0].prevout, scriptSig=lifesignal_sigScript, nSequence=ls.relative_timeout), CTxIn(wallet_op.outpoint, wallet_sigScript) ], unsigned_tx.vout, unsigned_tx.nLockTime, unsigned_tx.nVersion)
def add_output(): try: val_str = str(output_value.text()) value = 0 if '.' in val_str: value = int(float(val_str) * pow(10, 8)) else: value = int(val_str) out_script = Script.from_human(str(output_script.toPlainText())) new_output = CTxOut(value, out_script.get_hex().decode('hex')) except Exception as e: self.status_message(str(e), True) return else: self.outputs_tree.add_output(new_output) rm_output_edit.setRange(0, len(self.outputs_tree.get_outputs()) - 1)
def unvault_txout(pubkeys, pub_server, value): """The output of the unvaulting transaction (which spends the funding one). This transaction locks coins to server + 2of3 composed of [trader1, trader2, stakeholder1] after 6 blocks, or to a 4of4 composed of [trader1, trader2, stastakeholder1, stastakeholder2] immediately. :param pubkeys: The pubkeys of the 4 stakeholders, as bytes. :param pub_server: The pubkey of the cosigning server, as bytes. :param value: The output value in satoshis. :return: A CTxOut paying to the script detailed above. """ script = unvault_script(*pubkeys, pub_server) p2wsh = CScript([OP_0, hashlib.sha256(script).digest()]) return CTxOut(value, p2wsh)
def htlc_outputs(self, side: Side) -> List[Tuple[HTLC, int, bytes]]: """Give CTxOut, cltv_expiry, redeemscript for each non-trimmed HTLC""" ret: List[Tuple[CTxOut, int, bytes]] = [] for htlc in self.untrimmed_htlcs(side): if htlc.owner == side: redeemscript, sats = self._offered_htlc_output(htlc, side) else: redeemscript, sats = self._received_htlc_output(htlc, side) ret.append( (CTxOut(sats, CScript([script.OP_0, sha256(redeemscript).digest()])), htlc.cltv_expiry, redeemscript)) return ret
def add_input_output(bitcoind, tx): """Add an input and an output to a CMutableTransaction, SIGHASH_ALL.""" # First we get some coins privkey = CKey(os.urandom(32)) scriptPubKey = CScript([OP_0, Hash160(privkey.pub)]) address = CBitcoinAddress.from_scriptPubKey(scriptPubKey) amount = Decimal("50") * Decimal(COIN) - Decimal("500") # This creates a one-output transaction txid = bitcoind.pay_to(str(address), amount / Decimal(COIN)) # We bump the fees by 5000 tx.vout.append(CTxOut(amount - Decimal("5000"), scriptPubKey)) tx.vin.append(CTxIn(COutPoint(lx(txid), 0))) # Sign the new output with ALL tx_hash = SignatureHash(address.to_redeemScript(), tx, 1, SIGHASH_ALL, int(amount), SIGVERSION_WITNESS_V0) sig = privkey.sign(tx_hash) + bytes([SIGHASH_ALL]) tx.wit.vtxinwit.append(CTxInWitness(CScriptWitness([sig, privkey.pub])))
def spend_command(pubkey, nLockTime, prevOuts): addr = P2PKHBitcoinAddress.from_pubkey(x(pubkey)) address = addr redeemScript = hodl_redeemScript(pubkey, nLockTime) scriptPubKey = redeemScript.to_p2sh_scriptPubKey() proxy = bitcoin.rpc.Proxy(btc_conf_file=bitcoin.params.CONF_FILE) prevouts = [] for prevout in prevOuts: try: txid, n = prevout.split(':') txid = lx(txid) n = int(n) outpoint = COutPoint(txid, n) except ValueError: raise Exception('Invalid output: %s' % prevout) try: prevout = proxy.gettxout(outpoint) except IndexError: raise Exception('Outpoint %s not found' % outpoint) prevout = prevout['txout'] if prevout.scriptPubKey != scriptPubKey: raise Exception('Outpoint not correct scriptPubKey') prevouts.append((outpoint, prevout)) sum_in = sum(prev_txout.nValue for outpoint, prev_txout in prevouts) tx_size = ( 4 + # version field 2 + # number of txins len(prevouts) * 153 + # txins, including sigs 1 + # number of txouts 34 + # txout 4) # nLockTime field feerate = int(proxy._call('estimatefee', 1) * COIN) # satoshi's per KB if feerate <= 0: feerate = 10000 fees = int(tx_size / 1000 * feerate) unsigned_tx = CTransaction([ CTxIn(outpoint, redeemScript, nSequence=0) for outpoint, prevout in prevouts ], [CTxOut(sum_in - fees, address.to_scriptPubKey())], nLockTime) return ({'redeemTransaction': b2x(unsigned_tx.serialize())})
def appeal(self, user_index, user_secret: CBitcoinSecret, lifesignal_op: OutPointWithTx): ls = self._life_signals[user_index] if lifesignal_op.prevout.scriptPubKey != ls.redeemScript.to_p2sh_scriptPubKey( ): raise Exception("mismatch scriptPubkey") # spend the life signal into a black hole unsigned_tx = CTransaction([CTxIn(lifesignal_op.outpoint)], [CTxOut(0, CScript([True]))], nVersion=2) return CTransaction([ CTxIn(lifesignal_op.outpoint, scriptSig=ls.scriptSig_by_key1(user_secret, unsigned_tx, 0)) ], unsigned_tx.vout, nVersion=2)
def create_spend_tx(unvault_txid, unvault_vout, addresses): """Create the transaction which spends the unvault_tx after the relative locktime with the given private keys. :param unvault_txid: The id of the unvaulting transaction. :param unvault_vout: The index of the unvault output in this transaction. :param addresses: A dictionary containing address as keys and amount to send in sats as value. :return: The unsigned transaction, a CMutableTransaction. """ txouts = [ CTxOut(value, CBitcoinAddress(address).to_scriptPubKey()) for address, value in addresses.items() ] txin = CTxIn(COutPoint(unvault_txid, unvault_vout), nSequence=6) return CMutableTransaction([txin], txouts, nVersion=2)
def gettxout(self, outpoint, includemempool=True): """Return details about an unspent transaction output. Raises IndexError if outpoint is not found or was spent. includemempool - Include mempool txouts """ r = self._call('gettxout', b2lx(outpoint.hash), outpoint.n, includemempool) if r is None: raise IndexError('%s.gettxout(): unspent txout %r not found' % (self.__class__.__name__, outpoint)) r['txout'] = CTxOut(int(r['value'] * COIN), CScript(unhexlify(r['scriptPubKey']['hex']))) del r['value'] del r['scriptPubKey'] r['bestblock'] = lx(r['bestblock']) return r
def SignatureHash(script, txTo, inIdx, hashtype): if inIdx >= len(txTo.vin): return (1, "inIdx %d out of range (%d)" % (inIdx, len(txTo.vin))) txtmp = CTransaction() txtmp.copy(txTo) for txin in txtmp.vin: txin.scriptSig = b'' txtmp.vin[inIdx].scriptSig = script.vch if (hashtype & 0x1f) == SIGHASH_NONE: txtmp.vout = [] for i in range(len(txtmp.vin)): if i != inIdx: txtmp.vin[i].nSequence = 0 elif (hashtype & 0x1f) == SIGHASH_SINGLE: outIdx = inIdx if outIdx >= len(txtmp.vout): return (1, "outIdx %d out of range (%d)" % (outIdx, len(txtmp.vout))) tmp = txtmp.vout[outIdx] txtmp.vout = [] for i in range(outIdx): txtmp.vout.append(CTxOut()) txtmp.vout.append(tmp) for i in range(len(txtmp.vin)): if i != inIdx: txtmp.vin[i].nSequence = 0 if hashtype & SIGHASH_ANYONECANPAY: tmp = txtmp.vin[inIdx] txtmp.vin = [] txtmp.vin.append(tmp) s = txtmp.serialize() s += struct.pack(b"<I", hashtype) hash = Hash(s) return (hash, )
def forge_prevtx( vouts: Sequence[Tuple[str, int]], network: str = "mainnet") -> Tuple[bytes, messages.TransactionType]: """ Forge a transaction with the given vouts. """ bitcoin.SelectParams(network) input = messages.TxInputType( prev_hash=b"\x00" * 32, prev_index=0xFFFFFFFF, script_sig=b"\x00", sequence=0xFFFFFFFF, ) outputs = [ messages.TxOutputBinType( amount=amount, script_pubkey=bytes(CBitcoinAddress(address).to_scriptPubKey()), ) for address, amount in vouts ] tx = messages.TransactionType( version=1, inputs=[input], bin_outputs=outputs, lock_time=0, ) cin = CTxIn( COutPoint(input.prev_hash, input.prev_index), CScript(input.script_sig), input.sequence, ) couts = [ CTxOut(output.amount, CScript(output.script_pubkey)) for output in tx.bin_outputs ] txhash = CTransaction([cin], couts, tx.lock_time, tx.version).GetTxid()[::-1] bitcoin.SelectParams("mainnet") return txhash, tx
def add_input_output(bitcoind, tx, coin, fees): """Add another input to the transaction to bump the feerate.""" coin_amount = Decimal(coin["amount"]) * Decimal(COIN) # First get the private key from bitcoind's wallet. privkey = CKey(wif_decode(bitcoind.dumpprivkey(coin["address"]))) # Add the fetched coin as a new input. tx.vin.append(CTxIn(COutPoint(lx(coin["txid"]), coin["vout"]))) # And likely add an output, otherwise all goes to the fees. scriptPubKey = CScript([OP_0, Hash160(privkey.pub)]) if coin_amount > fees + 294: # For simplicity, pay to the same script tx.vout.append(CTxOut(coin_amount - Decimal(fees), scriptPubKey)) address = CBitcoinAddress.from_scriptPubKey(scriptPubKey) # We only do this once, sign it with ALL tx_hash = SignatureHash(address.to_redeemScript(), tx, 1, SIGHASH_ALL, int(coin_amount), SIGVERSION_WITNESS_V0) sig = privkey.sign(tx_hash) + bytes([SIGHASH_ALL]) tx.wit.vtxinwit.append( CTxInWitness(CScriptWitness([sig, privkey.pub])) ) return tx
import binascii import hashlib from bitcoin.key import CKey from bitcoin.core import COutPoint, CTxIn, CTxOut, CTransaction # from utils def myhash(s): return hashlib.sha256(hashlib.sha256(s).digest()).digest() previous = COutPoint() txin = CTxIn() txout = CTxOut() tx = CTransaction() # get the outpoint from which we want to spend previous.hash = 0xeccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2 previous.n = 0x01000000 txin.prevout = previous txin.scriptSig = binascii.unhexlify("76a914010966776006953d5567439e5e39f86a0d273bee88ac") # create output transaction txout.nValue = 0x605af40500000000 txout.scriptPubKey = binascii.unhexlify("76a914097072524438d003d23a2f23edb65aae1bb3e46988ac") # set inputs and outputs tx.vin.append(txin) tx.vout.append(txout) sertx = tx.serialize() + binascii.unhexlify("01000000")
def sendtoaddress(self, toaddress, amount): # select the input addresses funds = 0 subaccounts = [] accounts = self.getaccounts() for account in accounts: for address, subaccount in account.iteritems(): if subaccount['balance'] == 0: continue else: subaccounts.append(subaccount) # print "got one subaccount", subaccount # print "subaccounts: ", subaccounts funds = funds + subaccount['balance'] if funds >= amount + utils.calculate_fees(None): break # print "subaccounts 2: ", subaccounts # incase of insufficient funds, return if funds < amount + utils.calculate_fees(None): print "In sufficient funds, exiting, return" return # create transaction tx = CTransaction() # print "subaccounts 3: ", subaccounts # to the receiver txout = CTxOut() txout.nValue = amount txout.scriptPubKey = utils.address_to_pay_to_pubkey_hash(toaddress) tx.vout.append(txout) # from the sender nValueIn = 0 nValueOut = amount public_keys = [] private_keys = [] # secrets = [] # print "subaccounts 4: ", subaccounts for subaccount in subaccounts: # print "subaccount: ", subaccount # get received by from address previous_txouts = subaccount['received'] # print "Previous txouts", previous_txouts for received in previous_txouts: txin = CTxIn() txin.prevout = COutPoint() txin.prevout.hash = received['txhash'] txin.prevout.n = received['n'] txin.scriptSig = binascii.unhexlify(received['scriptPubKey']) tx.vin.append(txin) nValueIn = nValueIn + received['value'] public_keys.append(subaccount['public_key']) private_keys.append(subaccount['private_key']) # secrets.append(subaccount['secret']) if nValueIn >= amount + utils.calculate_fees(tx): break if nValueIn >= amount + utils.calculate_fees(tx): break # calculate the total excess amount excessAmount = nValueIn - nValueOut # calculate the fees fees = utils.calculate_fees(tx) # create change transaction, if there is any change left if excessAmount > fees: change_txout = CTxOut() change_txout.nValue = excessAmount - fees changeaddress = subaccounts[0]['address'] change_txout.scriptPubKey = utils.address_to_pay_to_pubkey_hash(changeaddress) tx.vout.append(change_txout) # calculate txhash tx.calc_sha256() txhash = str(tx.sha256) # sign the transaction for public_key, private_key, txin in zip(public_keys, private_keys, tx.vin): key = CKey() key.set_pubkey(public_key) key.set_privkey(private_key) signature = key.sign(txhash) # scriptSig = chr(len(signature)) + hash_type + signature + chr(len(public_key)) + public_key scriptSig = chr(len(signature)) + signature + chr(len(public_key)) + public_key print "Adding signature: ", binascii.hexlify(scriptSig) txin.scriptSig = scriptSig print "Tx Validity: ", tx.is_valid() return tx
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 = CTxOut(int(args.amount * COIN), payment_address.to_scriptPubKey()) change_txout = CTxOut(0, rpc.getnewaddress().to_scriptPubKey()) tx = CTransaction() 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 = CTxOut(0, CScript([OP_RETURN, b'\x00unsuccessful double-spend attempt\x00'])) tx.vout.append(op_ret_txout) if args.multisig: multisig_txout = CTxOut(args.dust, CScript([1, x('0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71'), b'\x00'*33, 2, OP_CHECKMULTISIG]))
coinbase = "04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73" scriptPubKeyHex = "4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac" # construct previous out point previousOut = COutPoint() previousOut.hash = 0 previousOut.n = 4294967295 # construct txin txin = CTxIn() txin.coinbase = binascii.unhexlify(coinbase) txin.scriptSig = binascii.unhexlify(coinbase) txin.prevout = previousOut # construct txout txout = CTxOut() txout.nValue = 5000000000 txout.scriptPubKey = binascii.unhexlify(scriptPubKeyHex) # create transaction tx = CTransaction() tx.vin.append(txin) tx.vout.append(txout) tx.calc_sha256() print tx print "Transaction: ", tx.is_valid() print "hash: ", hex(tx.sha256) print "Hash: ", "0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b" block = CBlock() block.nVersion = 1
def sendtovault(self, vault_address, amount): # select the input addresses funds = 0 subaccounts = [] accounts = self.getaccounts() for account in accounts: for address, subaccount in account.iteritems(): if subaccount['balance'] == 0: continue else: subaccounts.append(subaccount) funds = funds + subaccount['balance'] if funds >= amount + utils.calculate_fees(None): break # incase of insufficient funds, return if funds < amount + utils.calculate_fees(None): self.logger.warning("Insufficient funds, exiting, return") raise exceptions.InsufficientBalanceException # create transaction tx = CTransaction() # to the receiver txout = CTxOut() txout.nValue = amount txout.scriptPubKey = utils.vault_address_to_pay_to_vault_script(vault_address) tx.vout.append(txout) # from the sender nValueIn = 0 nValueOut = amount public_keys = [] private_keys = [] for subaccount in subaccounts: # get received by from address previous_txouts = subaccount['received'] for received in previous_txouts: txin = CTxIn() txin.prevout = COutPoint() txin.prevout.hash = received['txhash'] txin.prevout.n = received['n'] txin.scriptSig = received['scriptPubKey'] tx.vin.append(txin) nValueIn = nValueIn + received['value'] public_keys.append(subaccount['public_key']) private_keys.append(subaccount['private_key']) if nValueIn >= amount + utils.calculate_fees(tx): break if nValueIn >= amount + utils.calculate_fees(tx): break # calculate the total excess amount excessAmount = nValueIn - nValueOut # calculate the fees fees = utils.calculate_fees(tx) # create change transaction, if there is any change left if excessAmount > fees: change_txout = CTxOut() change_txout.nValue = excessAmount - fees changeaddress = self.getnewaddress()[1] change_txout.scriptPubKey = utils.address_to_pay_to_pubkey_hash(changeaddress) tx.vout.append(change_txout) # calculate txhash tx.calc_sha256() txhash = str(tx.sha256) self.logger.debug("Sending to vault %064x" % tx.sha256) # sign the transaction for public_key, private_key, txin in zip(public_keys, private_keys, tx.vin): key = CKey() key.set_pubkey(public_key) key.set_privkey(private_key) signature = key.sign(txhash) # scriptSig = chr(len(signature)) + hash_type + signature + chr(len(public_key)) + public_key scriptSig = chr(len(signature)) + signature + chr(len(public_key)) + public_key self.logger.debug("Adding signature: %s" % binascii.hexlify(scriptSig)) txin.scriptSig = scriptSig self.logger.debug("Tx Validity: %064x" % tx.is_valid()) # push data to vault tx.calc_sha256() self.set(str("vault:" + vault_address), {'txhash': tx.sha256}) return (vault_address, tx)