def __bytes__(self): """ Serializes the object into a byte stream. Returns: b (bytes): byte stream containing the serialized transaction output. """ return pack_u64(self.value) + pack_var_str(bytes(self.script))
def __bytes__(self): """ Serializes the object into a byte stream. Returns: b (bytes): byte stream containing the serialized input. """ return (bytes(self.outpoint) + pack_u32(self.outpoint_index) + pack_var_str(bytes(self.script)) + pack_u32(self.sequence_num))
def __bytes__(self): """ Serializes the object into a byte stream. Returns: b (bytes): byte stream containing the serialized input. """ return ( bytes(self.outpoint) + pack_u32(self.outpoint_index) + pack_var_str(bytes(self.script)) + pack_u32(self.sequence_num) )
def from_hex(h, size_prepended=False): """ Deserializes a hex-encoded string into a Script. Args: h (str): hex-encoded string, starting with the length of the script as a compact int. size_prepended (bool): Should be True if the size of the script has already been prepended. Returns: Script: A Script object. """ b = bytes.fromhex(h) if not size_prepended: b = pack_var_str(b) s, _ = Script.from_bytes(b) return s
def get_utxos(self, address_list): """ Provides all unspent transactions associated with each address in the address_list. Args: address_list (list(str)): List of Base58Check encoded Bitcoin addresses. Returns: dict: A dict keyed by address with each value being a list of UnspentTransactionOutput objects. """ ret = defaultdict(list) for addresses in self._list_chunks(address_list, 199): r = self._request("GET", "addresses/" + ",".join(addresses) + "/unspents") data = r.json() # for each address # { # "transaction_hash": "0bf0de38c261...", # "output_index": 0, # "value": 290000, # "addresses": [ # "1K4nPxBMy6sv7jssTvDLJWk1ADHBZEoUVb" # ], # "script": "OP_DUP OP_HASH160 c6296...", # "script_hex": "76a914c629680b8d1...", # "script_type": "pubkeyhash", # "required_signatures": 1, # "spent": false, # "confirmations": 8758 # }, for d in data: address = d["addresses"][0] txn_hash = Hash(d["transaction_hash"]) script, _ = Script.from_bytes( pack_var_str(bytes.fromhex(d["script_hex"]))) ret[address].append(UnspentTransactionOutput(txn_hash, d["output_index"], d["value"], script, d["confirmations"])) return ret
def build_multisig_sig(sigs, redeem_script): """ Builds a multisig signature script. This script contains the signatures in order given in sigs as well as the redeem script. It is not required to have all required signatures in sigs. However, len(sigs) may not be more than the max number indicated by the redeem script. Args: sigs (list(bytes)): A list of signatures (in DER encoding). The hash_type must already be appended to the byte string for each signature. This function will take care of the relevant data push operations. redeem_script (Script): The script used to redeem the coins. Returns: Script: A multisig signature script. Note: if len(sigs) is less than the minimum number required, the script will not be valid. """ multisig_params = redeem_script.extract_multisig_redeem_info() if len(sigs) > multisig_params['n']: raise ValueError("Too many signatures: %d (given) > %d (max. required)." % len(sigs), multisig_params['n']) # To correct for the early bitcoin-core off-by-1 error. scr = bytes([0x00]) for s in sigs: scr += pack_var_str(s) scr += Script.build_push_str(bytes(redeem_script)) return Script(scr)
def txn_from_json(txn_json): # { # "hash": "0bf0de38c26195919179f...", # "block_hash": "000000000000000...", # "block_height": 303404, # "block_time": "2014-05-30T23:54:55Z", # "chain_received_at": "2015-08-13T10:52:21.718Z", # "confirmations": 69389, # "lock_time": 0, # "inputs": [ # { # "transaction_hash": "0bf0de38c2619...", # "output_hash": "b84a66c46e24fe71f9...", # "output_index": 0, # "value": 300000, # "addresses": [ # "3L7dKYQGNoZub928CJ8NC2WfrM8U8GGBjr" # ], # "script_signature": "03046022100de7b67b9...", # "script_signature_hex": "00493046022100de7b...", # "sequence": 4294967295 # } # ], # "outputs": [ # { # "transaction_hash": "0bf0de38c261959...", # "output_index": 0, # "value": 290000, # "addresses": [ # "1K4nPxBMy6sv7jssTvDLJWk1ADHBZEoUVb" # ], # "script": "OP_DUP OP_HASH160 c629680b8d...", # "script_hex": "76a914c629680b8d13...", # "script_type": "pubkeyhash", # "required_signatures": 1, # "spent": false, # "spending_transaction": null # } # ], # "fees": 10000, # "amount": 290000 # }, # Transaction.DEFAULT_TRANSACTION_VERSION inputs = [] outputs = [] addr_keys = set() for i in txn_json["inputs"]: # Chain doesn't return the stuff about script length etc, so # we need to prepend that. script, _ = Script.from_bytes( pack_var_str(bytes.fromhex(i["script_signature_hex"]))) inputs.append(TransactionInput(Hash(i["output_hash"]), i["output_index"], script, i["sequence"])) if "addresses" in i: addr_keys.add(i["addresses"][0]) for i in txn_json["outputs"]: script, _ = Script.from_bytes( pack_var_str(bytes.fromhex(i["script_hex"]))) outputs.append(TransactionOutput(i["value"], script)) if "addresses" in i: addr_keys.add(i["addresses"][0]) txn = Transaction(Transaction.DEFAULT_TRANSACTION_VERSION, inputs, outputs, txn_json["lock_time"]) return txn, addr_keys
def txn_from_json(txn_json): """ Returns a new Transaction from a JSON-serialized transaction Args: txn_json: JSON with the following format: { "hash": "0bf0de38c26195919179f...", "block_hash": "000000000000000...", "block_height": 303404, "block_time": "2014-05-30T23:54:55Z", "chain_received_at": "2015-08-13T10:52:21.718Z", "confirmations": 69389, "lock_time": 0, "inputs": [ { "transaction_hash": "0bf0de38c2619...", "output_hash": "b84a66c46e24fe71f9...", "output_index": 0, "value": 300000, "addresses": [ "3L7dKYQGNoZub928CJ8NC2WfrM8U8GGBjr" ], "script_signature": "03046022100de7b67b9...", "script_signature_hex": "00493046022100de7b...", "sequence": 4294967295 } ], "outputs": [ { "transaction_hash": "0bf0de38c261959...", "output_index": 0, "value": 290000, "addresses": [ "1K4nPxBMy6sv7jssTvDLJWk1ADHBZEoUVb" ], "script": "OP_DUP OP_HASH160 c629680b8d...", "script_hex": "76a914c629680b8d13...", "script_type": "pubkeyhash", "required_signatures": 1, "spent": false, "spending_transaction": null } ], "fees": 10000, "amount": 290000 }, Transaction.DEFAULT_TRANSACTION_VERSION Returns: two1.lib.bitcoin.Transaction: a deserialized transaction derived from the provided json. """ inputs = [] outputs = [] addr_keys = set() for i in txn_json["inputs"]: if 'coinbase' in i: inputs.append( CoinbaseInput(height=txn_json["block_height"] or 0, raw_script=bytes.fromhex(i['coinbase']), sequence=i['sequence'], block_version=1)) else: # Script length etc. are not returned so we need to # prepend that. script, _ = Script.from_bytes( pack_var_str(bytes.fromhex(i["script_signature_hex"]))) inputs.append( TransactionInput(Hash(i["output_hash"]), i["output_index"], script, i["sequence"])) if "addresses" in i: addr_keys.add(i["addresses"][0]) for i in txn_json["outputs"]: script, _ = Script.from_bytes( pack_var_str(bytes.fromhex(i["script_hex"]))) outputs.append(TransactionOutput(i["value"], script)) if "addresses" in i: addr_keys.add(i["addresses"][0]) txn = Transaction(Transaction.DEFAULT_TRANSACTION_VERSION, inputs, outputs, txn_json["lock_time"]) return txn, addr_keys
def txn_from_json(txn_json): """ Args: txn_json: Json with the following format: { "block_hash": "0000000000000000af64802c79...", "block_height": 292586, "hash": "b4735a0690dab16b8789fceaf81c511f...", "addresses": [ "18KXZzuC3xvz6upUMQpsZzXrBwNPWZjdSa", "1AAuRETEcHDqL4VM3R97aZHP8DSUHxpkFV", "1DEP8i3QJCsomS4BSMY2RpU1upv62aGvhD", "1VxsEDjo6ZLMT99dpcLu4RQonMDVEQQTG" ], "total": 3537488, "fees": 20000, "size": 438, "preference": "medium", "relayed_by": "", "confirmed": "2014-03-26T17:08:04Z", "received": "2014-03-26T17:08:04Z", "ver": 1, "lock_time": 0, "double_spend": false, "vin_sz": 2, "vout_sz": 2, "confirmations": 64492, "confidence": 1, "inputs": [ { "prev_hash": "729f6469b59fea5da7...", "output_index": 0, "script": "483045022100d06cdad1a...", "output_value": 3500000, "sequence": 4294967295, "addresses": [ "1VxsEDjo6ZLMT99dpcLu4RQonMDVEQQTG" ], "script_type": "pay-to-pubkey-hash" }, ... ], "outputs": [ { "value": 3500000, "script": "76a9148629647bd642a237...", "addresses": [ "1DEP8i3QJCsomS4BSMY2RpU1upv62aGvhD" ], "script_type": "pay-to-pubkey-hash" } ]... Returns: An Object of type Transaction """ inputs = [] outputs = [] addr_keys = set() for i in txn_json["inputs"]: # Chain doesn't return the stuff about script length etc, so # we need to prepend that. script, _ = Script.from_bytes( pack_var_str(bytes.fromhex(i["script"]))) inputs.append( TransactionInput(Hash(i["prev_hash"]), i["output_index"], script, i["sequence"])) if "addresses" in i and i["addresses"]: addr_keys.add(i["addresses"][0]) for i in txn_json["outputs"]: script, _ = Script.from_bytes( pack_var_str(bytes.fromhex(i["script"]))) outputs.append(TransactionOutput(i["value"], script)) if "addresses" in i and i["addresses"]: addr_keys.add(i["addresses"][0]) txn = Transaction(Transaction.DEFAULT_TRANSACTION_VERSION, inputs, outputs, txn_json["lock_time"]) return txn, addr_keys
def txn_from_json(txn_json): """ Returns a new Transaction from a JSON-serialized transaction Args: txn_json: JSON with the following format: { "hash": "0bf0de38c26195919179f...", "block_hash": "000000000000000...", "block_height": 303404, "block_time": "2014-05-30T23:54:55Z", "chain_received_at": "2015-08-13T10:52:21.718Z", "confirmations": 69389, "lock_time": 0, "inputs": [ { "transaction_hash": "0bf0de38c2619...", "output_hash": "b84a66c46e24fe71f9...", "output_index": 0, "value": 300000, "addresses": [ "3L7dKYQGNoZub928CJ8NC2WfrM8U8GGBjr" ], "script_signature": "03046022100de7b67b9...", "script_signature_hex": "00493046022100de7b...", "sequence": 4294967295 } ], "outputs": [ { "transaction_hash": "0bf0de38c261959...", "output_index": 0, "value": 290000, "addresses": [ "1K4nPxBMy6sv7jssTvDLJWk1ADHBZEoUVb" ], "script": "OP_DUP OP_HASH160 c629680b8d...", "script_hex": "76a914c629680b8d13...", "script_type": "pubkeyhash", "required_signatures": 1, "spent": false, "spending_transaction": null } ], "fees": 10000, "amount": 290000 }, Transaction.DEFAULT_TRANSACTION_VERSION Returns: two1.lib.bitcoin.Transaction: a deserialized transaction derived from the provided json. """ inputs = [] outputs = [] addr_keys = set() for i in txn_json["inputs"]: if 'coinbase' in i: inputs.append( CoinbaseInput( height=txn_json["block_height"] or 0, raw_script=bytes.fromhex(i['coinbase']), sequence=i['sequence'], block_version=1)) else: # Script length etc. are not returned so we need to # prepend that. script, _ = Script.from_bytes( pack_var_str(bytes.fromhex(i["script_signature_hex"]))) inputs.append(TransactionInput(Hash(i["output_hash"]), i["output_index"], script, i["sequence"])) if "addresses" in i: addr_keys.add(i["addresses"][0]) for i in txn_json["outputs"]: script, _ = Script.from_bytes( pack_var_str(bytes.fromhex(i["script_hex"]))) outputs.append(TransactionOutput(i["value"], script)) if "addresses" in i: addr_keys.add(i["addresses"][0]) txn = Transaction(Transaction.DEFAULT_TRANSACTION_VERSION, inputs, outputs, txn_json["lock_time"]) return txn, addr_keys
def txn_from_json(txn_json): """ Args: txn_json: Json with the following format: { "block_hash": "0000000000000000af64802c79...", "block_height": 292586, "hash": "b4735a0690dab16b8789fceaf81c511f...", "addresses": [ "18KXZzuC3xvz6upUMQpsZzXrBwNPWZjdSa", "1AAuRETEcHDqL4VM3R97aZHP8DSUHxpkFV", "1DEP8i3QJCsomS4BSMY2RpU1upv62aGvhD", "1VxsEDjo6ZLMT99dpcLu4RQonMDVEQQTG" ], "total": 3537488, "fees": 20000, "size": 438, "preference": "medium", "relayed_by": "", "confirmed": "2014-03-26T17:08:04Z", "received": "2014-03-26T17:08:04Z", "ver": 1, "lock_time": 0, "double_spend": false, "vin_sz": 2, "vout_sz": 2, "confirmations": 64492, "confidence": 1, "inputs": [ { "prev_hash": "729f6469b59fea5da7...", "output_index": 0, "script": "483045022100d06cdad1a...", "output_value": 3500000, "sequence": 4294967295, "addresses": [ "1VxsEDjo6ZLMT99dpcLu4RQonMDVEQQTG" ], "script_type": "pay-to-pubkey-hash" }, ... ], "outputs": [ { "value": 3500000, "script": "76a9148629647bd642a237...", "addresses": [ "1DEP8i3QJCsomS4BSMY2RpU1upv62aGvhD" ], "script_type": "pay-to-pubkey-hash" } ]... Returns: An Object of type Transaction """ inputs = [] outputs = [] addr_keys = set() for i in txn_json["inputs"]: # Chain doesn't return the stuff about script length etc, so # we need to prepend that. script, _ = Script.from_bytes( pack_var_str(bytes.fromhex(i["script"]))) inputs.append(TransactionInput(Hash(i["prev_hash"]), i["output_index"], script, i["sequence"])) if "addresses" in i and i["addresses"]: addr_keys.add(i["addresses"][0]) for i in txn_json["outputs"]: script, _ = Script.from_bytes( pack_var_str(bytes.fromhex(i["script"]))) outputs.append(TransactionOutput(i["value"], script)) if "addresses" in i and i["addresses"]: addr_keys.add(i["addresses"][0]) txn = Transaction(Transaction.DEFAULT_TRANSACTION_VERSION, inputs, outputs, txn_json["lock_time"]) return txn, addr_keys
def sign_input(self, input_index, hash_type, private_key, sub_script): """ Signs an input. Args: input_index (int): The index of the input to sign. hash_type (int): What kind of signature hash to do. private_key (crypto.PrivateKey): private key with which to sign the transaction. sub_script (Script): the scriptPubKey of the corresponding utxo being spent if the outpoint is P2PKH or the redeem script if the outpoint is P2SH. """ if input_index < 0 or input_index >= len(self.inputs): raise ValueError("Invalid input index.") inp = self.inputs[input_index] curr_script_sig = inp.script multisig = False multisig_params = None multisig_key_index = -1 if sub_script.is_multisig_redeem(): multisig = True multisig_params = sub_script.extract_multisig_redeem_info() elif not sub_script.is_p2pkh(): raise TypeError("Signing arbitrary redeem scripts is not currently supported.") tmp_script = sub_script.remove_op("OP_CODESEPARATOR") compressed = False if hash_type & 0x1f == self.SIG_HASH_SINGLE and len(self.inputs) > len(self.outputs): # This is to deal with the bug where specifying an index # that is out of range (wrt outputs) results in a # signature hash of 0x1 (little-endian) msg_to_sign = 0x1.to_bytes(32, 'little') else: txn_copy = self._copy_for_sig(input_index, hash_type, tmp_script) if multisig: # Determine which of the public keys this private key # corresponds to. public_keys = multisig_params['public_keys'] pub_key_full = self._get_public_key_bytes(private_key, False) pub_key_comp = self._get_public_key_bytes(private_key, True) for i, p in enumerate(public_keys): if pub_key_full == p or pub_key_comp == p: multisig_key_index = i break if multisig_key_index == -1: raise ValueError( "Public key derived from private key does not match any of the public keys in redeem script.") else: # Before signing we should verify that the address in the # sub_script corresponds to that of the private key script_pub_key_h160_hex = tmp_script.get_hash160() if script_pub_key_h160_hex is None: raise ValueError("Couldn't find public key hash in sub_script!") # first try uncompressed key h160 = None for compressed in [True, False]: h160 = private_key.public_key.hash160(compressed) if h160 != bytes.fromhex(script_pub_key_h160_hex[2:]): h160 = None else: break if h160 is None: raise ValueError("Address derived from private key does not match sub_script!") msg_to_sign = bytes(Hash.dhash(bytes(txn_copy) + pack_u32(hash_type))) sig = private_key.sign(msg_to_sign, False) if multisig: # For multisig, we need to determine if there are already # signatures and if so, where we insert this signature inp.script = self._do_multisig_script([dict(index=multisig_key_index, signature=sig)], msg_to_sign, curr_script_sig, tmp_script, hash_type) else: pub_key_bytes = self._get_public_key_bytes(private_key, compressed) pub_key_str = pack_var_str(pub_key_bytes) script_sig = pack_var_str( sig.to_der() + pack_compact_int(hash_type)) + pub_key_str inp.script = Script(script_sig) return True