Ejemplo n.º 1
0
 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
     ])
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
 def __init__(self, amount, script_pubkey):
     self.amount = amount
     self.script_pubkey = script_pubkey
     self.script_pubkey_len = int_to_varint(len(script_pubkey))
Ejemplo n.º 6
0
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()
Ejemplo n.º 7
0
 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])