def _do_multisig_script(self, sigs, message, current_script_sig, redeem_script, hash_type): # If the current script is empty or None, create it sig_script = None if current_script_sig is None or not str(current_script_sig): sig_bytes = [s["signature"].to_der() + pack_compact_int(hash_type) for s in sigs] sig_script = Script.build_multisig_sig(sigs=sig_bytes, redeem_script=redeem_script) else: # Need to extract all the sigs already present multisig_params = redeem_script.extract_multisig_redeem_info() sig_info = current_script_sig.extract_multisig_sig_info() # Do a few quick sanity checks if str(sig_info["redeem_script"]) != str(redeem_script): raise ValueError("Redeem script in signature script does not match redeem_script!") if len(sig_info["signatures"]) == multisig_params["n"]: # Already max number of signatures return current_script_sig # Go through the signatures and match them up to the public keys # in the redeem script pub_keys = [] for pk in multisig_params["public_keys"]: pub_keys.append(crypto.PublicKey.from_bytes(pk)) existing_sigs = [] for s in sig_info["signatures"]: s1, h = s[:-1], s[-1] # Last byte is hash_type existing_sigs.append(crypto.Signature.from_der(s1)) if h != hash_type: raise ValueError("hash_type does not match that of the existing signatures.") # Match them up existing_sig_indices = self._match_sigs_to_pub_keys(existing_sigs, pub_keys, message) sig_indices = {s["index"]: s["signature"] for s in sigs} # Make sure there are no dups all_indices = set(list(existing_sig_indices.keys()) + list(sig_indices.keys())) if len(all_indices) < len(existing_sig_indices) + len(sig_indices): raise ValueError("At least one signature matches an existing signature.") if len(all_indices) > multisig_params["n"]: raise ValueError("There are too many signatures.") all_sigs = [] for i in sorted(all_indices): if i in existing_sig_indices: all_sigs.append(existing_sig_indices[i]) elif i in sig_indices: all_sigs.append(sig_indices[i]) all_sigs_bytes = [s.to_der() + pack_compact_int(hash_type) for s in all_sigs] sig_script = Script.build_multisig_sig(all_sigs_bytes, redeem_script) return sig_script
def set_txn_side_effect_for_hd_discovery(self): # For each used account, there are at least 2 calls required: # 1 for the first DISCOVERY_INCREMENT payout addresses and 1 # for the first DISCOVERY_INCREMENT change # addresses. Depending on the number of used addresses for the # account, this will change. effects = [] n = self._num_used_accounts if n == 0: n = 1 for acct_num in range(n): for change in [0, 1]: num_used = self._num_used_addresses[acct_num][change] r = math.ceil( (num_used + HDAccount.GAP_LIMIT) / self.address_increment) k = 'change_addresses' if change else 'payout_addresses' addr_list = self._acct_keys[acct_num][k] if change: metadata = dict( block=234790 + r, block_hash=Hash( "000000000000000007d57f03ebe36dbe4f87ab2f340e93b45999ab249b6dc0df" ), confirmations=23890 - r) else: metadata = dict(block=None, block_hash=None, confirmations=0) if r == 0: r = 1 for i in range(r): start = i * self.address_increment end = (i + 1) * self.address_increment addr_range = range(start, end) out = TransactionOutput(value=10000, script=Script.build_p2pkh( address_to_key_hash( addr_list[i])[1])) dummy_txn = Transaction(1, [], [out], 0) m = MockTxnDict(num_used=num_used, addr_range=addr_range, addr_list=addr_list, used_value=[ dict(metadata=metadata, transaction=dummy_txn) ], unused_value=[]) effects.append(m) self.get_transactions.side_effect = effects return len(effects)
def set_txn_side_effect_for_hd_discovery(self): # For each used account, there are at least 2 calls required: # 1 for the first DISCOVERY_INCREMENT payout addresses and 1 # for the first DISCOVERY_INCREMENT change # addresses. Depending on the number of used addresses for the # account, this will change. effects = [] n = self._num_used_accounts if n == 0: n = 1 for acct_num in range(n): for change in [0, 1]: num_used = self._num_used_addresses[acct_num][change] r = math.ceil((num_used + HDAccount.GAP_LIMIT) / self.address_increment) k = 'change_addresses' if change else 'payout_addresses' addr_list = self._acct_keys[acct_num][k] if change: metadata = dict(block=234790 + r, block_hash=Hash("000000000000000007d57f03ebe36dbe4f87ab2f340e93b45999ab249b6dc0df"), confirmations=23890 - r) else: metadata = dict(block=None, block_hash=None, confirmations=0) if r == 0: r = 1 for i in range(r): start = i * self.address_increment end = (i + 1) * self.address_increment addr_range = range(start, end) out = TransactionOutput(value=10000, script=Script.build_p2pkh( address_to_key_hash( addr_list[i])[1])) dummy_txn = Transaction(1, [], [out], 0) m = MockTxnDict(num_used=num_used, addr_range=addr_range, addr_list=addr_list, used_value=[dict(metadata=metadata, transaction=dummy_txn)], unused_value=[]) effects.append(m) self.get_transactions.side_effect = effects return len(effects)
def __init__(self, height, raw_script, sequence=MAX_INT, block_version=3): self.height = height if block_version == 1: scr = raw_script else: scr = Script.build_push_int(self.height) + raw_script # Coinbase scripts are basically whatever, so we don't # try to create a script object from them. super().__init__(self.NULL_OUTPOINT, self.MAX_INT, scr, sequence)
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] multisig = False if sub_script.is_multisig_redeem(): multisig = True elif not sub_script.is_p2pkh(): raise TypeError( "Signing arbitrary redeem scripts is not currently supported.") tmp_script = sub_script.remove_op("OP_CODESEPARATOR") # Before signing we should verify that the address in the # sub_script corresponds to that of the private key m = self._match_public_key(private_key, tmp_script) if not m['match']: if multisig: msg = "Public key derived from private key does not match any of the public keys in redeem script." else: msg = "Address derived from private key does not match sub_script!" raise ValueError(msg) sig, signed_message = self.get_signature_for_input( input_index, hash_type, private_key, sub_script) 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=m['info']['multisig_key_index'], signature=sig)], signed_message, inp.script, tmp_script, hash_type) else: pub_key_bytes = self._get_public_key_bytes(private_key, m['info']['compressed']) inp.script = Script( [sig.to_der() + pack_compact_int(hash_type), pub_key_bytes]) return True
def _copy_for_sig(self, input_index, hash_type, sub_script): """ Returns a copy of this txn appropriate for signing, based on hash_type. """ new_txn = copy.deepcopy(self) # First deal w/the inputs # For the SIG_HASH_ANY case, we only care about # self.inputs[input_index] if hash_type == self.SIG_HASH_ANY: ti = new_txn.inputs[input_index] new_txn.inputs = [ti] else: for i, inp in enumerate(new_txn.inputs): inp.script = sub_script if i == input_index else Script("") if hash_type & 0x1f in [ self.SIG_HASH_NONE, self.SIG_HASH_SINGLE ] and input_index != i: # Sequence numbers (nSequence) must be set to 0 for all but # the input we care about. inp.sequence_num = 0 # Now deal with outputs if hash_type & 0x1f == self.SIG_HASH_NONE: new_txn.outputs = [] elif hash_type & 0x1f == self.SIG_HASH_SINGLE: # Resize output vector to input_index + 1 new_txn.outputs = new_txn.outputs[:input_index + 1] # All outputs except outputs[i] have a value of -1 (0xffffffff) # and a blank script for i, out in enumerate(new_txn.outputs): if i != input_index: out.script = Script("") out.value = 0xffffffff return new_txn
def txn_from_json(txn_json): inputs = [] outputs = [] addr_keys = set() for i in sorted(txn_json["vin"], key=lambda i: i["n"]): if 'coinbase' in i: inputs.append(CoinbaseInput(height=0, raw_script=bytes.fromhex(i['coinbase']), sequence=i['sequence'], block_version=1)) else: script = Script.from_hex(i["scriptSig"]["hex"]) inputs.append(TransactionInput(Hash(i["txid"]), i["vout"], script, i["sequence"])) if "addr" in i: addr_keys.add(i["addr"]) for o in sorted(txn_json["vout"], key=lambda o: o["n"]): script = Script.from_hex(o["scriptPubKey"]["hex"]) value = int(decimal.Decimal(str(o["value"])) * decimal.Decimal('1e8')) outputs.append(TransactionOutput(value, script)) if "addresses" in o["scriptPubKey"]: for a in o["scriptPubKey"]["addresses"]: addr_keys.add(a) txn = Transaction(Transaction.DEFAULT_TRANSACTION_VERSION, inputs, outputs, txn_json["locktime"]) assert txn.hash == Hash(txn_json['txid']) return txn, addr_keys
def from_bytes(b): """ Deserializes a byte stream into a TransactionOutput object. Args: b (bytes): byte-stream beginning with the value. Returns: tuple: First element of the tuple is a TransactionOutput, the second is the remainder of the byte stream. """ value, b0 = unpack_u64(b) script_len, b0 = unpack_compact_int(b0) return (TransactionOutput(value, Script(b0[:script_len])), b0[script_len:])
def from_bytes(b): """ Deserializes a byte stream into a TransactionInput. Args: b (bytes): byte stream starting with the outpoint. Returns: tuple: First element of the tuple is the TransactionInput object and the second is the remaining byte stream. """ outpoint = b[0:32] outpoint_index, b1 = unpack_u32(b[32:]) script, b1 = Script.from_bytes(b1) sequence_num, b1 = unpack_u32(b1) return (TransactionInput(Hash(outpoint), outpoint_index, script, sequence_num), b1)
def _verify_input(self, input_index, sub_script, partial_multisig=False): p2sh = sub_script.is_p2sh() sig_script = self.inputs[input_index].script si = ScriptInterpreter(txn=self, input_index=input_index, sub_script=sub_script) try: si.run_script(sig_script) except ScriptInterpreterError: return False # This copy_stack and the restore_stack emulate the behavior # found in bitcoin core for evaluating P2SH scripts. See: # https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp#L1170 if p2sh: si.copy_stack() try: si.run_script(sub_script) except ScriptInterpreterError: return False rv = si.valid if p2sh: si.restore_stack() redeem_script = Script(si.stack.pop()) si._sub_script = redeem_script try: if sig_script.is_multisig_sig() and partial_multisig: # This is a hack for partial verification partial_script = copy.deepcopy(redeem_script) partial_script.ast[-1] = 'OP_CHECKPARTIALMULTISIG' sig_info = sig_script.extract_multisig_sig_info() si.run_script(partial_script) rv &= si.match_count > 0 and si.match_count <= len( sig_info['signatures']) else: si.run_script(redeem_script) rv &= si.valid except: rv = False return rv
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
from two1.lib.bitcoin.txn import TransactionOutput from two1.lib.bitcoin.script import Script from two1.lib.bitcoin.utils import address_to_key_hash from two1.lib.bitcoin.utils import bytes_to_str address = '137KzxStaf6vw5yGujViK3Tkigoix9N3v7' _, hash160 = address_to_key_hash(address) out_script = Script.build_p2pkh(hash160) out1 = TransactionOutput(value=100000, script=out_script) # Print the script print("%s" % (out_script)) # Print the address print("Addresses = %r" % (out1.get_addresses())) # Print the value print("Value: %d" % (out1.value)) # Serialize out1_bytes = bytes(out1) print(bytes_to_str(out1_bytes))
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 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 sorted(txn_json["vin"], key=lambda i: i["n"]): if 'coinbase' in i: inputs.append(CoinbaseInput(height=0, raw_script=bytes.fromhex(i['coinbase']), sequence=i['sequence'], block_version=1)) else: script = Script.from_hex(i["scriptSig"]["hex"]) inputs.append(TransactionInput(Hash(i["txid"]), i["vout"], script, i["sequence"])) if "addr" in i: addr_keys.add(i["addr"]) for o in sorted(txn_json["vout"], key=lambda o: o["n"]): script = Script.from_hex(o["scriptPubKey"]["hex"]) value = int(decimal.Decimal(str(o["value"])) * decimal.Decimal('1e8')) outputs.append(TransactionOutput(value, script)) if "addresses" in o["scriptPubKey"]: for a in o["scriptPubKey"]["addresses"]: addr_keys.add(a) txn = Transaction(Transaction.DEFAULT_TRANSACTION_VERSION, inputs, outputs, txn_json["locktime"]) assert txn.hash == Hash(txn_json['txid']) 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 _do_multisig_script(self, sigs, message, current_script_sig, redeem_script, hash_type): # If the current script is empty or None, create it sig_script = None if current_script_sig is None or not str(current_script_sig): sig_bytes = [ s['signature'].to_der() + pack_compact_int(hash_type) for s in sigs ] sig_script = Script.build_multisig_sig(sigs=sig_bytes, redeem_script=redeem_script) else: # Need to extract all the sigs already present multisig_params = redeem_script.extract_multisig_redeem_info() sig_info = current_script_sig.extract_multisig_sig_info() # Do a few quick sanity checks if str(sig_info['redeem_script']) != str(redeem_script): raise ValueError( "Redeem script in signature script does not match redeem_script!" ) if len(sig_info['signatures']) == multisig_params['n']: # Already max number of signatures return current_script_sig # Go through the signatures and match them up to the public keys # in the redeem script pub_keys = [] for pk in multisig_params['public_keys']: pub_keys.append(crypto.PublicKey.from_bytes(pk)) existing_sigs = [] for s in sig_info['signatures']: s1, h = s[:-1], s[-1] # Last byte is hash_type existing_sigs.append(crypto.Signature.from_der(s1)) if h != hash_type: raise ValueError( "hash_type does not match that of the existing signatures." ) # Match them up existing_sig_indices = self._match_sigs_to_pub_keys( existing_sigs, pub_keys, message) sig_indices = {s['index']: s['signature'] for s in sigs} # Make sure there are no dups all_indices = set(list(existing_sig_indices.keys()) + \ list(sig_indices.keys())) if len(all_indices) < len(existing_sig_indices) + len(sig_indices): raise ValueError( "At least one signature matches an existing signature.") if len(all_indices) > multisig_params['n']: raise ValueError("There are too many signatures.") all_sigs = [] for i in sorted(all_indices): if i in existing_sig_indices: all_sigs.append(existing_sig_indices[i]) elif i in sig_indices: all_sigs.append(sig_indices[i]) all_sigs_bytes = [ s.to_der() + pack_compact_int(hash_type) for s in all_sigs ] sig_script = Script.build_multisig_sig(all_sigs_bytes, redeem_script) return sig_script
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
from two1.lib.bitcoin.txn import Transaction from two1.lib.wallet import Wallet from two1.lib.bitcoin.script import Script from two1.lib.blockchain.twentyone_provider import TwentyOneProvider import two1.lib.bitcoin as bitcoin provider = TwentyOneProvider() wallet = Wallet() pubkey = input("Please enter the public key that was used to create the script") tx_hex = input("Please enter the transaction hex") server_pubkey = input("Please enter server pub key") white_pubkey = input("Please enter white pub key") black_pubkey = input("Please enter black pub key") their_pubkey = PublicKey.from_bytes(pubkey) tx = Transaction.from_hex(tx_hex) private_key = wallet.get_private_for_public(their_pubkey) public_keys = [PublicKey.from_bytes(server_pubkey).compressed_bytes, PublicKey.from_bytes(white_pubkey).compressed_bytes, PublicKey.from_bytes(black_pubkey).compressed_bytes] redeem_script = Script.build_multisig_redeem(2, public_keys) for i, inp in enumerate(tx.inputs): tx.sign_input(i, bitcoin.Transaction.SIG_HASH_ALL, private_key, redeem_script) txid = provider.broadcast_transaction(tx.to_hex()) print("Transaction ID: {}".format(txid))