def header_from_insight_block(d): version = int(d["version"]) prev_block = lx(d["previousblockhash"]) merkle_root = lx(d["merkleroot"]) time = int(d["time"]) bits = int(d["bits"], 16) nonce = int(d["nonce"]) return BlockHeader(version, prev_block, merkle_root, time, bits, nonce).as_hex()
def header_from_insight_block(d): version = int(d['version']) prev_block = lx(d['previousblockhash']) merkle_root = lx(d['merkleroot']) time = int(d['time']) bits = int(d['bits'], 16) nonce = int(d['nonce']) return BlockHeader(version, prev_block, merkle_root, time, bits, nonce).as_hex()
def test_serialization(self): auxpow = CAuxPow.deserialize(x('02000000010000000000000000000000000000000000000000000000000000000000000000ffffffff39030464072cfabe6d6d394c537ad0e73d1f8a57a254b5473715c691cfcde79836c89ae9dc6823e61faa01000000000000001896fc0116000000000000000100f2052a010000001976a914ea89052eb52e70571a62b7fa3a7d764a753516de88ac0000000091dd3d8a296162ca8d7a54bd76344a6f8ee11759db878f892a6e497f458b9bea00000000000000000000020000001db92c00e6354176a5aeb38a2719f659ed91b848479354e9241030691de0cc19b2ae9676a9a93b5d1270a3f243cae979855e3d65691cd6002f8e17c050115306f9acb1546868031df9b7b233')) testnet_auxpow_block = CAltcoinBlockHeader(nVersion=6422786, hashPrevBlock=lx('403615a0bc7b1621bca47657316a396edf6a92a31732f2c1bd787de46a0e2c84'), hashMerkleRoot=lx('5435db45daf1f9d923c6d0cdbb8941fdb318622274416d38a0d61ef5360cb38e'), nTime=1420930337, nBits=0x1e011a1e, nNonce=0x0000000, auxpow=auxpow) serialized = testnet_auxpow_block.serialize() testnet_auxpow_block2 = CAltcoinBlockHeader.deserialize(serialized) self.assertEqual(testnet_auxpow_block, testnet_auxpow_block2)
def getrawtransaction(self, txid, verbose=False): """Return transaction with hash txid Raises IndexError if transaction not found. verbse - If true a dict is returned instead with additional information on the transaction. Note that if all txouts are spent and the transaction index is not enabled the transaction may not be available. """ try: r = self._call('getrawtransaction', b2lx(txid), 1 if verbose else 0) except JSONRPCException as ex: raise IndexError('%s.getrawtransaction(): %s (%d)' % (self.__class__.__name__, ex.error['message'], ex.error['code'])) if verbose: r['tx'] = CTransaction.deserialize(unhexlify(r['hex'])) del r['hex'] del r['txid'] del r['version'] del r['locktime'] del r['vin'] del r['vout'] r['blockhash'] = lx(r['blockhash']) if 'blockhash' in r else None else: r = CTransaction.deserialize(unhexlify(r)) return r
def native(self): tx_hex = self.output.transaction_hash # Convert a little-endian hex string to bytes txid = lx(tx_hex) vout = self.output.index outpoint = COutPoint(txid, vout) return CTxIn(outpoint)
def get_locator(self): """ Get a block locator object to give our remote peer when fetching headers/merkle blocks. """ locator = CBlockLocator() parent = self.get_block_id(self.get_height()) def rollback(parent, n): for i in range(n): parent = self._get_parent(parent) return parent step = -1 start = 0 height = self.get_height() while(True): if start >= 10: step *= 2 start = 0 locator.vHave.append(lx(parent)) parent = rollback(parent, abs(step)) start += 1 height += step if height <= self._get_starting_height() + abs(step): break return locator
def listunspent(self, minconf=0, maxconf=9999999, addrs=None): """Return unspent transaction outputs in wallet Outputs will have between minconf and maxconf (inclusive) confirmations, optionally filtered to only include txouts paid to addresses in addrs. """ r = None if addrs is None: r = self._call('listunspent', minconf, maxconf) else: addrs = [str(addr) for addr in addrs] r = self._call('listunspent', minconf, maxconf, addrs) r2 = [] for unspent in r: unspent['outpoint'] = COutPoint(lx(unspent['txid']), unspent['vout']) del unspent['txid'] del unspent['vout'] # address isn't always available as Bitcoin Core allows scripts w/o # an address type to be imported into the wallet, e.g. non-p2sh # segwit try: unspent['address'] = CBitcoinAddress(unspent['address']) except KeyError: pass unspent['scriptPubKey'] = CScript(unhexlify(unspent['scriptPubKey'])) unspent['amount'] = int(unspent['amount'] * COIN) r2.append(unspent) return r2
def listunspent(self, minconf=0, maxconf=9999999, addrs=None): """Return unspent transaction outputs in wallet Outputs will have between minconf and maxconf (inclusive) confirmations, optionally filtered to only include txouts paid to addresses in addrs. """ r = None if addrs is None: r = self._call('listunspent', minconf, maxconf) else: addrs = [str(addr) for addr in addrs] r = self._call('listunspent', minconf, maxconf, addrs) r2 = [] for unspent in r: unspent['outpoint'] = COutPoint(lx(unspent['txid']), unspent['vout']) del unspent['txid'] del unspent['vout'] unspent['address'] = CBitcoinAddress(unspent['address']) unspent['scriptPubKey'] = CScript(unhexlify(unspent['scriptPubKey'])) unspent['amount'] = int(unspent['amount'] * COIN) r2.append(unspent) return r2
def fundrawtransaction(self, given_transaction, *args, **kwargs): """ Make up some inputs for the given transaction. """ # just use any txid here vintxid = lx("99264749804159db1e342a0c8aa3279f6ef4031872051a1e52fb302e51061bef") if isinstance(given_transaction, str): given_bytes = x(given_transaction) elif isinstance(given_transaction, CMutableTransaction): given_bytes = given_transaction.serialize() else: raise FakeBitcoinProxyException("Wrong type passed to fundrawtransaction.") # this is also a clever way to not cause a side-effect in this function transaction = CMutableTransaction.deserialize(given_bytes) for vout_counter in range(0, self._num_fundrawtransaction_inputs): txin = CMutableTxIn(COutPoint(vintxid, vout_counter)) transaction.vin.append(txin) # also allocate a single output (for change) txout = make_txout() transaction.vout.append(txout) transaction_hex = b2x(transaction.serialize()) return {"hex": transaction_hex, "fee": 5000000}
def getraw(proxy, mytx): try: mytx = proxy.getrawtransaction(lx(mytx)) except Exception, e: if str(e) == 'Proxy.getrawtransaction(): No information available about transaction (-5)': print "The transaction you entered isn't vaild, or haven't got to the mempool yet.\n" \ "If you sure it's vaild try again in 10-15 seconds" sys.exit(0) if str(e) == 'Non-hexadecimal digit found': try: mytx = proxy.getrawtransaction(mytx) except: if str(e) == 'Proxy.getrawtransaction(): No information available about transaction (-5)': print "The transaction you entered isn't vaild, or haven't got to the mempool yet.\n" \ "If you sure it's vaild try again in 10-15 seconds" sys.exit(0) else: print e sys.exit(0) else: print e sys.exit(0)
def make_unsigned(cls, outpoints, output_address, tx_fee=TRANSACTION_FEE, testnet=False, out_value=None): """ Build an unsigned transaction. Args: outpoints: A `list` of `dict` objects which contain a txid, vout, value, and scriptPubkey. output_address: The address to send the full value (minus the tx fee) of the inputs to. tx_fee: The Bitcoin network fee to be paid on this transaction. testnet: Should this transaction be built for testnet? out_value: used if you want to specify a specific output value otherwise the full value of the inputs (minus the tx fee) will be used. """ # build the inputs from the outpoints object SelectParams("testnet" if testnet else "mainnet") txins = [] in_value = 0 for outpoint in outpoints: in_value += outpoint["value"] txin = CMutableTxIn(COutPoint(lx(outpoint["txid"]), outpoint["vout"])) txin.scriptSig = CScript(x(outpoint["scriptPubKey"])) txins.append(txin) # build the output value = out_value if out_value is not None else (in_value - tx_fee) txout = CMutableTxOut(value, CBitcoinAddress(output_address).to_scriptPubKey()) # make the transaction tx = CMutableTransaction(txins, [txout]) return BitcoinTransaction(tx)
def main(): ''' Our main function. ''' SelectParams('mainnet') decoded_transaction = eval(open('transaction_to_sign.txt').read()) # pylint: disable=eval-used txin_txid = lx(decoded_transaction['vin'][0]['txid']) txin_vout = 0 tx_in = CMutableTxIn(COutPoint(txin_txid, txin_vout)) tx_out = [] for idx in range(len(decoded_transaction['vout'])): satoshis = int(COIN * decoded_transaction['vout'][idx]['value']) script_pub_key = CScript(bytes.fromhex(decoded_transaction['vout'][idx]['scriptPubKey']['hex'])) tx_out.append(CMutableTxOut(satoshis, script_pub_key)) tx_to_spend = CMutableTransaction([tx_in], tx_out) priv_1 = CBitcoinSecret.from_secret_bytes(bytes.fromhex(PRIV_HEX_1)) priv_2 = CBitcoinSecret.from_secret_bytes(bytes.fromhex(PRIV_HEX_2)) txin_redeem_script = CScript(bytes.fromhex(decoded_transaction['vin'][0]['scriptSig']['hex'])) # Input 0 is fixed. sighash = SignatureHash(txin_redeem_script, tx_to_spend, 0, SIGHASH_ALL) signatures = [] for priv in [priv_1, priv_2]: signatures.append(priv.sign(sighash) + bytes([SIGHASH_ALL])) tx_in.scriptSig = CScript([CScriptOp(0x00), signatures[0], signatures[1], txin_redeem_script]) # script_pub_key Defined in cycle. VerifyScript(tx_in.scriptSig, txin_redeem_script, tx_to_spend, 0, (SCRIPT_VERIFY_P2SH,)) print(b2x(tx_to_spend.serialize()))
def getrawtransaction(self, txid, verbose=False): """Return transaction with hash txid Raises IndexError if transaction not found. verbose - If true a dict is returned instead with additional information on the transaction. Note that if all txouts are spent and the transaction index is not enabled the transaction may not be available. """ try: r = self._call("getrawtransaction", b2lx(txid), 1 if verbose else 0) except JSONRPCError as ex: raise IndexError( "%s.getrawtransaction(): %s (%d)" % (self.__class__.__name__, ex.error["message"], ex.error["code"]) ) if verbose: r["tx"] = CTransaction.deserialize(unhexlify(r["hex"])) del r["hex"] del r["txid"] del r["version"] del r["locktime"] del r["vin"] del r["vout"] r["blockhash"] = lx(r["blockhash"]) if "blockhash" in r else None else: r = CTransaction.deserialize(unhexlify(r)) return r
def getblockheader(self, block_hash, verbose=False): """Get block header <block_hash> verbose - If true a dict is returned with the values returned by getblockheader that are not in the block header itself (height, nextblockhash, etc.) Raises IndexError if block_hash is not valid. """ try: block_hash = b2lx(block_hash) except TypeError: raise TypeError('%s.getblockheader(): block_hash must be bytes; got %r instance' % (self.__class__.__name__, block_hash.__class__)) try: r = self._call('getblockheader', block_hash, verbose) except InvalidAddressOrKeyError as ex: raise IndexError('%s.getblockheader(): %s (%d)' % (self.__class__.__name__, ex.error['message'], ex.error['code'])) if verbose: nextblockhash = None if 'nextblockhash' in r: nextblockhash = lx(r['nextblockhash']) return {'confirmations':r['confirmations'], 'height':r['height'], 'mediantime':r['mediantime'], 'nextblockhash':nextblockhash, 'chainwork':x(r['chainwork'])} else: return CBlockHeader.deserialize(unhexlify(r))
def insight_parse_raw_tx(res): version = int(res.get('version')) locktime = int(res.get('locktime')) vin = [] vout = [] for i in res.get('vin'): prev_txid = i['txid'] prev_n = int(i['n']) seq = int(i['sequence']) script_asm = i['scriptSig']['asm'] script = Script.from_human(script_asm) tx_outpoint = COutPoint(lx(prev_txid), prev_n) tx_input = CTxIn(tx_outpoint, x(script.get_hex()), seq) vin.append(tx_input) for o in res.get('vout'): value = float(o['value']) value = int(value * pow(10, 8)) script_asm = o['scriptPubKey']['asm'] script = Script.from_human(script_asm) tx_output = CTxOut(value, x(script.get_hex())) vout.append(tx_output) tx = Transaction(vin, vout, locktime, version) return b2x(tx.serialize())
def abe_parse_raw_tx(res): version = int(res.get('ver')) locktime = int(res.get('lock_time')) vin = [] vout = [] for i in res.get('in'): prev_txid = i['prev_out']['hash'] prev_n = int(i['prev_out']['n']) tx_outpoint = COutPoint(lx(prev_txid), prev_n) scriptSig = Script(x( i['raw_scriptSig'] )) sequence = int(i['sequence']) tx_input = CTxIn(tx_outpoint, x(scriptSig.get_hex()), sequence) vin.append(tx_input) for o in res.get('out'): value = float(o['value']) value = int(value * pow(10, 8)) script = Script(x( o['raw_scriptPubKey'] )) tx_output = CTxOut(value, x(script.get_hex())) vout.append(tx_output) tx = Transaction(vin, vout, locktime, version) return b2x(tx.serialize())
def test_repr(self): def T(outpoint, expected): actual = repr(outpoint) self.assertEqual(actual, expected) T( COutPoint(), 'COutPoint()') T( COutPoint(lx('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'), 0), "COutPoint(lx('4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b'), 0)")
def generate(self, numblocks): """Mine blocks immediately (before the RPC call returns) numblocks - How many blocks are generated immediately. Returns iterable of block hashes generated. """ r = self._call('generate', numblocks) return (lx(blk_hash) for blk_hash in r)
def test(self): sig = BlockHeaderSig('bitcoin-mainnet', x('010000000000000000000000000000000000000000000000000000000000000000000000'), x('29ab5f49ffff001d1dac2b7c')) block_index = set([lx('000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f')]) nTime = sig.verify(x('3ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a'), block_index) self.assertEqual(nTime, 1231006505)
def getrawmempool(self, verbose=False): """Return the mempool""" if verbose: return self._call('getrawmempool', verbose) else: r = self._call('getrawmempool') r = [lx(txid) for txid in r] return r
def sendmany(self, fromaccount, payments, minconf=1, comment='', subtractfeefromamount=[]): """Send amount to given addresses. payments - dict with {address: amount} """ json_payments = {str(addr):float(amount)/COIN for addr, amount in payments.items()} r = self._call('sendmany', fromaccount, json_payments, minconf, comment, subtractfeefromamount) return lx(r)
def test(self): msg = lx('0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9') tx_op = PathOp_SHA256(b'\x01\x00\x00\x00\x01', b'\x00\x00\x00\x00HG0D\x02 NE\xe1i2\xb8\xafQIa\xa1\xd3\xa1\xa2_\xdf?Ow2\xe9\xd6$\xc6\xc6\x15H\xab_\xb8\xcdA\x02 \x18\x15"\xec\x8e\xca\x07\xdeH`\xa4\xac\xdd\x12\x90\x9d\x83\x1c\xc5l\xbb\xacF"\x08"!\xa8v\x8d\x1d\t\x01\xff\xff\xff\xff\x02\x00\xca\x9a;\x00\x00\x00\x00CA\x04\xae\x1ab\xfe\t\xc5\xf5\x1b\x13\x90_\x07\xf0k\x99\xa2\xf7\x15\x9b"%\xf3t\xcd7\x8dq0/\xa2\x84\x14\xe7\xaa\xb3s\x97\xf5T\xa7\xdf_\x14,!\xc1\xb70;\x8a\x06&\xf1\xba\xde\xd5\xc7*pO~l\xd8L\xac\x00(k\xee\x00\x00\x00\x00CA\x04\x11\xdb\x93\xe1\xdc\xdb\x8a\x01kI\x84\x0f\x8cS\xbc\x1e\xb6\x8a8.\x97\xb1H.\xca\xd7\xb1H\xa6\x90\x9a\\\xb2\xe0\xea\xdd\xfb\x84\xcc\xf9tDd\xf8.\x16\x0b\xfa\x9b\x8bd\xf9\xd4\xc0?\x99\x9b\x86C\xf6V\xb4\x12\xa3\xac\x00\x00\x00\x00') merkle_op = PathOp_SHA256(lx('b1fea52486ce0c62bb442b530a3f0132b826c74e473d1f2c220bfa78111c5082'),b'') path = Path([tx_op, PathOp_SHA256(b'',b''), merkle_op, PathOp_SHA256(b'',b'')]) sig = BlockHeaderSig('bitcoin-mainnet', x('0100000055bd840a78798ad0da853f68974f3d183e2bd1db6a842c1feecf222a00000000'), x('51b96a49ffff001d283e9e70')) block_index = set([lx('00000000d1145790a8694403d4063f323d499e655c83426834d4ce2f8dd4a2ee')]) stamp = Timestamp(path, sig) nTime = stamp.verify(msg, block_index) self.assertEqual(nTime, 1231731025)
def add_prevout(self, txid, vout, redeemer): outpoint = COutPoint(lx(txid), vout) try: prevout = self.proxy.gettxout(outpoint) except IndexError: raise Exception("Outpoint %s not found" % (outpoint,)) prevtx = prevout['txout'] if prevtx.scriptPubKey != redeemer.p2sh_scriptPubKey: raise Exception("Outpoint %s has incorrect scriptPubKey (%s; expected %s)" % (outpoint, b2x(prevtx.scriptPubKey), b2x(redeemer.p2sh_scriptPubKey))) self.prevouts.append((outpoint, prevtx, redeemer))
def getblockhash(self, height): """Return hash of block in best-block-chain at height. Raises IndexError if height is not valid. """ try: return lx(self._call('getblockhash', height)) except JSONRPCException as ex: raise IndexError('%s.getblockhash(): %s (%d)' % (self.__class__.__name__, ex.error['message'], ex.error['code']))
def _format_utxos(self, utxos, address, **kwargs): formattedUTXOs = [] for utxo in utxos: utxo['hash'] = utxo['tx_hash'] utxo['n'] = utxo['tx_output_n'] utxo['vout'] = self._get_utxo_vout(utxo, address) utxo['outpoint'] = COutPoint(lx(utxo['hash'])) utxo['address'] = CBitcoinAddress(address) utxo['scriptPubKey'] = CScript(binascii.unhexlify(utxo['script'])) utxo['value'] = int(utxo['value']) return utxos
def format_query_str(cls, query_str): """ Takes a string, convert it to an object which can be used to query the Address class & returns it. Otherwise it returns False. """ try: hash = core.lx(query_str) except binascii.Error: return False else: return hash
def get_inputs(self): vin = [] for i in range(self.model.rowCount()): prev_hash, prev_vout = str(self.model.item(i, 0).text()).split(':') in_script = str(self.model.item(i, 1).data(RawRole).toString()) sequence = int(self.model.item(i, 2).text()) outpoint = COutPoint(lx(prev_hash), int(prev_vout)) i_input = CTxIn(outpoint, in_script.decode('hex'), sequence) vin.append(i_input) return vin
def getblockhash(self, height): """Return hash of block in best-block-chain at height. Raises IndexError if height is not valid. """ try: return lx(self._call("getblockhash", height)) except JSONRPCError as ex: raise IndexError( "%s.getblockhash(): %s (%d)" % (self.__class__.__name__, ex.error["message"], ex.error["code"]) )
def mock_listunspent(self, addrs): output1 = {'outpoint': COutPoint(lx('34eb81bc0d1a822369f75174fd4916b1ec490d8fbcba33168e820cc78a52f608'), 0), 'confirmations': 62952, 'address': P2PKHBitcoinAddress('mz7poFND7hVGRtPWjiZizcCnjf6wEDWjjT'), 'spendable': False, 'amount': 49000000, 'solvable': False, 'scriptPubKey': CScript( [OP_DUP, OP_HASH160, x('cc0a909c4c83068be8b45d69b60a6f09c2be0fda'), OP_EQUALVERIFY, OP_CHECKSIG]), 'account': ''} output2 = {'address': P2PKHBitcoinAddress('mz7poFND7hVGRtPWjiZizcCnjf6wEDWjjT'), 'amount': 2750, 'account': '', 'spendable': False, 'solvable': False, 'confirmations': 62932, 'outpoint': COutPoint(lx('6773785b4dc5d2cced67d26fc0820329307a8e10dfaef50d506924984387bf0b'), 1), 'scriptPubKey': CScript( [OP_DUP, OP_HASH160, x('cc0a909c4c83068be8b45d69b60a6f09c2be0fda'), OP_EQUALVERIFY, OP_CHECKSIG])} output3 = {'address': P2PKHBitcoinAddress('mz7poFND7hVGRtPWjiZizcCnjf6wEDWjjT'), 'amount': 2750, 'account': '', 'spendable': False, 'solvable': False, 'confirmations': 62932, 'outpoint': COutPoint(lx('6773785b4dc5d2cced67d26fc0820329307a8e10dfaef50d506924984387bf0b'), 5), 'scriptPubKey': CScript( [OP_DUP, OP_HASH160, x('cc0a909c4c83068be8b45d69b60a6f09c2be0fda'), OP_EQUALVERIFY, OP_CHECKSIG])} unspent_outputs = [output1, output2, output3] return unspent_outputs
def sendrawtransaction(self, tx, allowhighfees=False): """Submit transaction to local node and network. allowhighfees - Allow even if fees are unreasonably high. """ hextx = hexlify(tx.serialize()) if allowhighfees: r = self._call('sendrawtransaction', hextx, True) else: r = self._call('sendrawtransaction', hextx) return lx(r)
def getbestblockhash(self): """Return hash of best (tip) block in longest block chain.""" return lx(self._call('getbestblockhash'))
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)
def block(hash): block = m.Block.query.filter_by(hash=core.lx(hash)).first() return render_template('block.html', block=block)
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 get_vault_from_unvault(self, txid): """Get the vault corresponding to this unvault transaction.""" for v in self.vaults: if v["unvault_tx"].GetTxid() == lx(txid): return v return None
def sendtoaddress(self, addr, amount, comment='', commentto='', subtractfeefromamount=False): """Send amount to a given address""" addr = str(addr) amount = float(amount)/COIN r = self._call('sendtoaddress', addr, amount, comment, commentto, subtractfeefromamount) return lx(r)
def get_tx_details(txid): # must convert txid string to bytes x(txid) fund_txinfo = bitcoind.gettransaction(lx(txid)) return fund_txinfo['details'][0]
def parse_secret(txid): decoded = bitcoind.getrawtransaction(lx(txid), 1) # decoded = bitcoind.decoderawtransaction(raw) asm = decoded['vin'][0]['scriptSig']['asm'].split(" ") print(asm[2])
def fund_htlc(p2sh, amount): send_amount = float(amount) * COIN fund_txid = bitcoind.sendtoaddress(p2sh, send_amount) txid = b2x(lx(b2x(fund_txid))) print("funding btc sell address:", txid) return txid
def sendmany_command(payments): proxy = bitcoin.rpc.Proxy(btc_conf_file=bitcoin.params.CONF_FILE) txid = lx(proxy.sendmany("", payments).hex()).hex() return (txid)
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 test_increase_revault_tx_feerate(bitcoind): """This tests that any of the stakeholders can increase the feerate of any of the revaulting transactions in a timely manner. Will justice rule?""" # The stakeholders, the first two are the traders. stk_privkeys = [os.urandom(32) for i in range(4)] stk_pubkeys = [CKey(k).pub for k in stk_privkeys] # Same, but for the EDV emer_privkeys = [os.urandom(32) for i in range(4)] emer_pubkeys = [CKey(k).pub for k in emer_privkeys] # The co-signing server, required by the spend tx serv_privkey = os.urandom(32) serv_pubkey = CKey(serv_privkey).pub # Test the vault emergency amount_vault = 50 * COIN - 500 txid = send_vault_tx(bitcoind, stk_pubkeys, amount_vault) amount_emer = amount_vault - 500 CTx = create_emergency_vault_tx(lx(txid), 0, amount_emer, emer_pubkeys) sigs = [sign_emergency_vault_tx(CTx, p, stk_pubkeys, amount_vault) for p in stk_privkeys] # Sanity checks don't hurt assert all(sig[-1] == SIGHASH_SINGLE | SIGHASH_ANYONECANPAY for sig in sigs) CMTx = CMutableTransaction.from_tx( form_emergency_vault_tx(CTx, stk_pubkeys, sigs) ) fees_before = tx_fees(bitcoind, CMTx) add_input_output(bitcoind, CMTx) fees_after = tx_fees(bitcoind, CMTx) assert fees_after > fees_before bitcoind.send_tx(CMTx.serialize().hex()) # Test the emer unvault amount_vault = 50 * COIN - 500 amount_unvault = amount_vault - 500 txid = send_unvault_tx(bitcoind, stk_privkeys, stk_pubkeys, serv_pubkey, amount_vault, amount_unvault) amount_emer = amount_unvault - 500 CTx = create_emer_unvault_tx(txid, 0, emer_pubkeys, amount_emer) sigs = [sign_emer_unvault_tx(CTx, p, stk_pubkeys, serv_pubkey, amount_unvault) for p in stk_privkeys] # Sanity checks don't hurt assert all(sig[-1] == SIGHASH_SINGLE | SIGHASH_ANYONECANPAY for sig in sigs) CMTx = CMutableTransaction.from_tx( form_emer_unvault_tx(CTx, sigs, stk_pubkeys, serv_pubkey) ) fees_before = tx_fees(bitcoind, CMTx) add_input_output(bitcoind, CMTx) fees_after = tx_fees(bitcoind, CMTx) assert fees_after > fees_before bitcoind.send_tx(CMTx.serialize().hex()) # Test the cancel unvault amount_vault = 50 * COIN - 500 amount_unvault = amount_vault - 500 txid = send_unvault_tx(bitcoind, stk_privkeys, stk_pubkeys, serv_pubkey, amount_vault, amount_unvault) amount_cancel = amount_unvault - 500 CTx = create_cancel_tx(txid, 0, emer_pubkeys, amount_cancel) sigs = [sign_cancel_tx(CTx, p, stk_pubkeys, serv_pubkey, amount_unvault) for p in stk_privkeys] # Sanity checks don't hurt assert all(sig[-1] == SIGHASH_SINGLE | SIGHASH_ANYONECANPAY for sig in sigs) CMTx = CMutableTransaction.from_tx( form_cancel_tx(CTx, sigs, stk_pubkeys, serv_pubkey) ) fees_before = tx_fees(bitcoind, CMTx) add_input_output(bitcoind, CMTx) fees_after = tx_fees(bitcoind, CMTx) assert fees_after > fees_before bitcoind.send_tx(CMTx.serialize().hex())
def sendtoaddress(self, addr, amount): """Sent amount to a given address""" addr = str(addr) amount = float(amount) / COIN r = self._call('sendtoaddress', addr, amount) return lx(r)
def create_timestamp(timestamp, calendar_urls, args): """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. """ setup_bitcoin = args.setup_bitcoin if args.use_btc_wallet else False 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) m = args.m n = len(calendar_urls) if m > n or m <= 0: logging.error( "m (%d) cannot be greater than available calendar%s (%d) neither less or equal 0" % (m, "" if n == 1 else "s", n)) sys.exit(1) logging.debug("Doing %d-of-%d request, timeout is %d second%s" % (m, n, args.timeout, "" if n == 1 else "s")) q = Queue() for calendar_url in calendar_urls: submit_async(calendar_url, timestamp.msg, q, args.timeout) start = time.time() merged = 0 for i in range(n): try: remaining = args.timeout - (time.time() - start) result = q.get(block=True, timeout=remaining) try: if isinstance(result, Timestamp): timestamp.merge(result) merged += 1 else: logging.debug(str(result)) except Exception as error: logging.debug(str(error)) except Empty: # Timeout continue if merged < m: logging.error( "Failed to create timestamp: need at least %d attestation%s but received %s within timeout" % (m, "" if m == 1 else "s", merged)) sys.exit(1) logging.debug("%.2f seconds elapsed" % (time.time() - start))
def disconnect_block(self, block): ser_prevhash = b2lx(block.hashPrevBlock) prevmeta = BlkMeta() prevmeta.deserialize(self.db.get(('blkmeta:'+ser_prevhash).encode())) tup = self.unique_outputs(block) if tup is None: return False outputs = tup[0] # mark deps as unspent with self.db.write_batch(transaction=True) as batch: for output in outputs: self.clear_txout(output[0], output[1], batch) # update tx index and memory pool for tx in block.vtx: ser_hash = b2lx(tx.GetTxid()) batch.delete(('tx:'+ser_hash).encode()) if not tx.is_coinbase(): self.mempool_add(tx) # update database pointers for best chain batch.put(b'misc:total_work', int_to_bytes(prevmeta.work)) batch.put(b'misc:height', struct.pack('i', prevmeta.height)) batch.put(b'misc:tophash', lx(ser_prevhash)) # TODO: # [x] Search block cache for block and marked as orphaned # [x] Search transaction cache and delete # # [x] Mark block as orphaned # [x] Remove transactions from transaction table, mempool add done above # [x] Revert balance changes # # Disconnects happen infrequently so we can do these updates to postgres DB immediately bhash = b2lx(block.GetHash()) key = ('pg_block:%s' % bhash).encode() cached_block = self.db.get(key) if cached_block: cached_block = json.loads(cached_block.decode('utf-8')) cached_block['orphaned'] = True batch.put(key, (json.dumps(cached_block)).encode()) for tx in block.vtx: if tx.is_coinbase(): continue ser_hash = b2lx(tx.GetTxid()) key = ('pg_tx:%s' % ser_hash) batch.delete(key) Block.update(orphaned=True).where(Block.hash == b2lx(block.GetHash())).execute() Transaction.delete().where(Transaction.block == b2lx(block.GetHash())).execute() for tx in block.vtx: txid = b2lx(tx.GetTxid()) for idx, vin in enumerate(tx.vin): if tx.is_coinbase() and idx == 0: continue preaddress, prevalue = self.getutxo(b2lx(vin.prevout.hash), vin.prevout.n) if preaddress in self.address_changes: self.address_changes[preaddress]['balance'] += prevalue self.address_changes[preaddress]['sent'] -= prevalue else: self.address_changes[preaddress] = { 'balance': prevalue, 'sent': -prevalue, # subtract from sent 'received': 0, } for idx, vout in enumerate(tx.vout): address = self._address_from_vout(txid, vout) value = vout.nValue if address in self.address_changes: self.address_changes[address]['balance'] -= value self.address_changes[address]['received'] -= value else: self.address_changes[address] = { 'balance': -value, 'received': -value, 'sent': 0 } self._update_address_index() self.checkaddresses(force=True) self.log.info("ChainDb(disconn): height %d, block %s" % (prevmeta.height, b2lx(block.hashPrevBlock))) return True
# Create P2SH scriptPubKey from redeemScript. txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey() print("p2sh_scriptPubKey", b2x(txin_scriptPubKey)) # Convert the P2SH scriptPubKey to a base58 Bitcoin address txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) p2sh = str(txin_p2sh_address) print('Pay to:', p2sh) # AUTOMATE Send funds to p2sh amount = 1.0*COIN # sendtoaddress return the id of the created tx fund_tx = proxy.sendtoaddress(txin_p2sh_address, amount) print('fund tx sent. It\'s id is:', b2x(lx(b2x(fund_tx)))) print('Now redeeming.........') # AUTOMATE getting vout of funding tx txinfo = proxy.gettransaction(fund_tx) details = txinfo['details'][0] vout = details['vout'] # Create the txin structure. scriptSig defaults to being empty. # The input is the p2sh funding transaction txid, vout is its index txin = CMutableTxIn(COutPoint(fund_tx, vout)) # Create the txout. Pays out to recipient, so uses recipient's pubkey # Withdraw full amount minus fee default_fee = 0.001*COIN txout = CMutableTxOut(amount - default_fee, recipientpubkey.to_scriptPubKey())
def create_txin(txid, utxo_index): return CMutableTxIn(COutPoint(lx(txid), utxo_index))
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: args.prev_txid = lx(args.prev_txid) except ValueError as err: parser.error('Invalid txid: %s' % str(err)) if len(args.prev_txid) != 32: parser.error('Invalid txid: Wrong length.') tx1 = rpc.getrawtransaction(args.prev_txid) elif not args.no_reuse: # Try to find an unconfirmed transaction with full-RBF enabled and a change # output > amount txids_seen = set() for unspent in rpc.listunspent(0, 0): txid = unspent['outpoint'].hash if txid not in txids_seen:
# Generate blocks (and receive coinbase reward) if the balance is too small. if bitcoin_rpc.getbalance() < 1.0: bitcoin_rpc.generate(101) bitcoin_rpc.importaddress(str(address)) burn_txid = bitcoin_rpc.sendtoaddress(str(address), burn_amount) print("Victim sent %d btc to \"burn\" address (txid: %s)" % (burn_amount, burn_txid)) bitcoin_rpc.generate(1) # Select transaction inputs. # First take just some other input the attacker is allowed to spend. block_hash = bitcoin_rpc.generate(1)[0] block = bitcoin_rpc.getblock(block_hash) coinbase = bitcoin_rpc.getrawtransaction(block["tx"][0], 1) 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())
return "{}:{}".format(self.ip, self.port) def discover_new_addresses(new_addresses): global addresses new_addr = [Address(address.ip, address.port, address.nServices) for address in new_addresses] with address_lock: addresses += [addr for addr in new_addr if addr not in addresses] # Simple way to guess the last block: # Initiate a circular buffer and push the block hash every time we get a new block latest_blocks = collections.deque(maxlen=200) latest_blocks_lock = threading.Lock() # Add the genesis block to make sure we start with something meaningful for i in range(100): latest_blocks.append(lx("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")) def guess_latest_block(): """ Returns most common block in the last 20 block encountered """ with latest_blocks_lock: return max(set(latest_blocks), key=latest_blocks.count) def append_latest_block(hash_): with latest_blocks_lock: latest_blocks.append(hash_) temp_lock = threading.Lock() pushes = []
def transaction(hash): transaction = m.Transaction.query.filter_by(txid=core.lx(hash)).first() return render_template('transaction.html', transaction=transaction)
def mock_listunspent(self, addrs): print('mock listunspent') output1 = { 'outpoint': COutPoint( lx('34eb81bc0d1a822369f75174fd4916b1ec490d8fbcba33168e820cc78a52f608' ), 0), 'confirmations': 62952, 'address': P2PKHBitcoinAddress('mz7poFND7hVGRtPWjiZizcCnjf6wEDWjjT'), 'spendable': False, 'amount': 49000000, 'solvable': False, 'scriptPubKey': CScript([ OP_DUP, OP_HASH160, x('cc0a909c4c83068be8b45d69b60a6f09c2be0fda'), OP_EQUALVERIFY, OP_CHECKSIG ]), 'account': '' } output2 = { 'address': P2PKHBitcoinAddress('mz7poFND7hVGRtPWjiZizcCnjf6wEDWjjT'), 'amount': 2750, 'account': '', 'spendable': False, 'solvable': False, 'confirmations': 62932, 'outpoint': COutPoint( lx('6773785b4dc5d2cced67d26fc0820329307a8e10dfaef50d506924984387bf0b' ), 1), 'scriptPubKey': CScript([ OP_DUP, OP_HASH160, x('cc0a909c4c83068be8b45d69b60a6f09c2be0fda'), OP_EQUALVERIFY, OP_CHECKSIG ]) } output3 = { 'address': P2PKHBitcoinAddress('mz7poFND7hVGRtPWjiZizcCnjf6wEDWjjT'), 'amount': 2750, 'account': '', 'spendable': False, 'solvable': False, 'confirmations': 62932, 'outpoint': COutPoint( lx('6773785b4dc5d2cced67d26fc0820329307a8e10dfaef50d506924984387bf0b' ), 5), 'scriptPubKey': CScript([ OP_DUP, OP_HASH160, x('cc0a909c4c83068be8b45d69b60a6f09c2be0fda'), OP_EQUALVERIFY, OP_CHECKSIG ]) } unspent_outputs = [output1, output2, output3] return unspent_outputs
def _filename_to_key(self, filename): hex_hash, str_n = filename.split(':') return bitcoin.core.COutPoint(lx(hex_hash), int(str_n))
def mock_broadcast(self, transaction): return lx( 'b59bef6934d043ec2b6c3be7e853b3492e9f493b3559b3bd69864283c122b257')
def fake_squeak_hash(): return lx( 'DEADBEAFDEADBEAFDEADBEAFDEADBEAFDEADBEAFDEADBEAFDEADBEAFDEADBEAF')
txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey) p2sh = str(txin_p2sh_address) print( 'Bob -- Assuming Alice has created other tx on Zcash blockchain, send funds to this p2sh address:', p2sh) ## TODO: IMPORT ZCASH XCAT FUNCTIONS # ========================= FUND BITCOIN P2SH ========================= response = input( "Bob -- Type 'enter' to allow zbxcat to fund the Bitcoin p2sh on your behalf:" ) send_amount = 1.0 * COIN fund_tx = bitcoind.sendtoaddress(txin_p2sh_address, send_amount) print('Alice -- Bitcoin fund tx was sent, please wait for confirmation. Txid:', b2x(lx(b2x(fund_tx)))) # ========================= PART 2: BITCOIN P2SH FUNDED, REDEEM OR REFUND ========================= # Check that fund_tx is on the blockchain to the right address, then notify receiver # Importing address so we can watch it bitcoind.importaddress(p2sh) # Get details of funding transaction fund_txinfo = bitcoind.gettransaction(fund_tx) fund_details = fund_txinfo[ 'details'] # "fund_details" is an array, for now we can assume it only has one destination address outputAddress = fund_details[0]['address'] fund_vout = fund_details[0]['vout'] if (outputAddress != p2sh): print( 'Fund tx sent to wrong address! p2sh was {0}, funding tx was sent to {1}' .format(p2sh, outputAddress))