def __bytes__(self): inp = int_to_varint(len(self.TxIn)) + b''.join(map(bytes, self.TxIn)) out = int_to_varint(len(self.TxOut)) + b''.join(map(bytes, self.TxOut)) wit = b''.join([w.witness for w in self.TxIn]) return b''.join([ self.version, MARKER if wit else b'', FLAG if wit else b'', inp, out, wit, self.locktime ])
def calculate_preimages(tx_obj, inputs_parameters): """Calculates preimages for provided transaction structure and input values. :param tx_obj: The transaction object used to calculate preimage from using a transaction digest algorithm, such as BIP-143 for Segwit inputs. This transaction object must hence have scriptCodes filled into the corresponding scriptSigs in the inputs. :type tx_obj: :object:`~core.transaction.TxObj` :param inputs_parameters: A list of tuples with input index as integer, hash type as integer and a boolean flag to denote if the input is spending from a Segwit output. For example: [(0, 1, True), (2, 1, False), (...)] :type inputs_parameters: A `list` of `tuple` """ # Tx object data: input_count = int_to_varint(len(tx_obj.TxIn)) output_count = int_to_varint(len(tx_obj.TxOut)) output_block = b''.join([bytes(o) for o in tx_obj.TxOut]) hashPrevouts = double_sha256(b''.join( [i.txid + i.txindex for i in tx_obj.TxIn])) hashSequence = double_sha256(b''.join([i.sequence for i in tx_obj.TxIn])) hashOutputs = double_sha256(output_block) preimages = [] for input_index, hash_type, segwit_input in inputs_parameters: # We can only handle hashType == 1: if hash_type != HASH_TYPE: raise ValueError('Bit only support hashType of value 1.') # Calculate prehashes: if segwit_input: # BIP-143 preimage: hashed = sha256( tx_obj.version + hashPrevouts + hashSequence + tx_obj.TxIn[input_index].txid + tx_obj.TxIn[input_index].txindex + tx_obj.TxIn[input_index].script_sig_len + # scriptCode length tx_obj.TxIn[input_index].script_sig + # scriptCode (includes amount) tx_obj.TxIn[input_index].sequence + hashOutputs + tx_obj.locktime + hash_type) else: hashed = sha256( tx_obj.version + input_count + b''.join(ti.txid + ti.txindex + OP_0 + ti.sequence for ti in islice(tx_obj.TxIn, input_index)) + tx_obj.TxIn[input_index].txid + tx_obj.TxIn[input_index].txindex + tx_obj.TxIn[input_index].script_sig_len + # scriptCode length tx_obj.TxIn[input_index].script_sig + # scriptCode tx_obj.TxIn[input_index].sequence + b''.join( ti.txid + ti.txindex + OP_0 + ti.sequence for ti in islice(tx_obj.TxIn, input_index + 1, None)) + output_count + output_block + tx_obj.locktime + hash_type) preimages.append(hashed) return preimages
def __init__(self, script_sig, txid, txindex, witness=b'', amount=None, sequence=SEQUENCE, segwit_input=False): self.script_sig = script_sig self.script_sig_len = int_to_varint(len(script_sig)) self.txid = txid self.txindex = txindex self.witness = witness self.amount = amount self.sequence = sequence self.segwit_input = segwit_input
def deserialize(tx): if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): return deserialize(hex_to_bytes(tx)) segwit_tx = TxObj.is_segwit(tx) version, tx = read_bytes(tx, 4) if segwit_tx: _, tx = read_bytes(tx, 1) # ``marker`` is nulled _, tx = read_bytes(tx, 1) # ``flag`` is nulled ins, tx = read_var_int(tx) inputs = [] for i in range(ins): txid, tx = read_bytes(tx, 32) txindex, tx = read_bytes(tx, 4) script_sig, tx = read_var_string(tx) sequence, tx = read_bytes(tx, 4) inputs.append(TxIn(script_sig, txid, txindex, sequence=sequence)) outs, tx = read_var_int(tx) outputs = [] for _ in range(outs): amount, tx = read_bytes(tx, 8) script_pubkey, tx = read_var_string(tx) outputs.append(TxOut(amount, script_pubkey)) if segwit_tx: for i in range(ins): wnum, tx = read_var_int(tx) witness = int_to_varint(wnum) for _ in range(wnum): w, tx = read_segwit_string(tx) witness += w inputs[i].witness = witness locktime, _ = read_bytes(tx, 4) txobj = TxObj(version, inputs, outputs, locktime) return txobj
def __init__(self, amount, script_pubkey): self.amount = amount self.script_pubkey = script_pubkey self.script_pubkey_len = int_to_varint(len(script_pubkey))
def sign_tx(private_key, tx, *, unspents): """Signs inputs in provided transaction object for which unspents are provided and can be signed by the private key. :param private_key: Private key :type private_key: ``PrivateKey`` or ``MultiSig`` :param tx: Transaction object :type tx: ``TxObj`` :param unspents: For inputs to be signed their corresponding Unspent objects must be provided. :returns: The signed transaction as hex. :rtype: ``str`` """ # input_dict contains those unspents that can be signed by private_key, # providing additional information for segwit-inputs (the amount to spend) input_dict = {} try: for unspent in unspents: if not private_key.can_sign_unspent(unspent): continue tx_input = hex_to_bytes(unspent.txid)[::-1] + \ unspent.txindex.to_bytes(4, byteorder='little') input_dict[tx_input] = unspent.to_dict() except TypeError: raise ValueError('Please provide as unspents at least all inputs to ' 'be signed with the function call.') # Determine input indices to sign from input_dict (allows for transaction batching) sign_inputs = [ j for j, i in enumerate(tx.TxIn) if i.txid + i.txindex in input_dict ] segwit_tx = TxObj.is_segwit(tx) public_key = private_key.public_key public_key_push = script_push(len(public_key)) hash_type = HASH_TYPE # Make input parameters for preimage calculation inputs_parameters = [] for i in sign_inputs: # Create transaction object for preimage calculation tx_input = tx.TxIn[i].txid + tx.TxIn[i].txindex segwit_input = input_dict[tx_input]['segwit'] tx.TxIn[i].segwit_input = segwit_input script_code = private_key.scriptcode script_code_len = int_to_varint(len(script_code)) # Use scriptCode for preimage calculation of transaction object: tx.TxIn[i].script_sig = script_code tx.TxIn[i].script_sig_len = script_code_len if segwit_input: tx.TxIn[i].script_sig += input_dict[tx_input]['amount']\ .to_bytes(8, byteorder='little') inputs_parameters.append([i, hash_type, segwit_input]) preimages = calculate_preimages(tx, inputs_parameters) # Calculate signature scripts: for hash, (i, _, segwit_input) in zip(preimages, inputs_parameters): # signature = private_key.sign(hash) + b'\x01' signature = private_key.sign(hash) + b'\x61' script_sig = b'\x16' + private_key.segwit_scriptcode witness = ((b'\x02' if segwit_input else b'') + # witness counter len(signature).to_bytes(1, byteorder='little') + signature + public_key_push + public_key) script_sig = script_sig if segwit_input else witness witness = witness if segwit_input else b'\x00' if segwit_tx else b'' # Providing the signature(s) to the input tx.TxIn[i].script_sig = script_sig tx.TxIn[i].script_sig_len = int_to_varint(len(script_sig)) tx.TxIn[i].witness = witness return tx.to_hex()
def legacy_repr(self): inp = int_to_varint(len(self.TxIn)) + b''.join(map(bytes, self.TxIn)) out = int_to_varint(len(self.TxOut)) + b''.join(map(bytes, self.TxOut)) return b''.join([self.version, inp, out, self.locktime])