Пример #1
0
    def serialize(self, rtype=hex):
        """ Serialize all the transaction fields arranged in the proper order, resulting in a hexadecimal string
        ready to be broadcast to the network.

        :param self: self
        :type self: TX
        :param rtype: Whether the serialized transaction is returned as a hex str or a byte array.
        :type rtype: hex or bool
        :return: Serialized transaction representation (hexadecimal or bin depending on rtype parameter).
        :rtype: hex str / bin
        """

        if rtype not in [hex, bin]:
            raise Exception(
                "Invalid return type (rtype). It should be either hex or bin.")
        serialized_tx = change_endianness(int2bytes(
            self.version, 4))  # 4-byte version number (LE).

        # INPUTS
        serialized_tx += encode_varint(self.inputs)  # Varint number of inputs.

        for i in range(self.inputs):
            serialized_tx += change_endianness(
                self.prev_tx_id[i]
            )  # 32-byte hash of the previous transaction (LE).
            serialized_tx += change_endianness(
                int2bytes(self.prev_out_index[i],
                          4))  # 4-byte output index (LE)
            serialized_tx += encode_varint(len(self.scriptSig[i].content) /
                                           2)  # Varint input script length.
            # ScriptSig
            serialized_tx += self.scriptSig[i].content  # Input script.
            serialized_tx += int2bytes(self.nSequence[i],
                                       4)  # 4-byte sequence number.

        # OUTPUTS
        serialized_tx += encode_varint(
            self.outputs)  # Varint number of outputs.

        if self.outputs != 0:
            for i in range(self.outputs):
                serialized_tx += change_endianness(int2bytes(
                    self.value[i], 8))  # 8-byte field Satoshi value (LE)
                # ScriptPubKey
                serialized_tx += encode_varint(
                    len(self.scriptPubKey[i].content) /
                    2)  # Varint Output script length.
                serialized_tx += self.scriptPubKey[i].content  # Output script.

        serialized_tx += int2bytes(self.nLockTime, 4)  # 4-byte lock time field

        # If return type has been set to binary, the serialized transaction is converted.
        if rtype is bin:
            serialized_tx = unhexlify(serialized_tx)

        return serialized_tx
Пример #2
0
    def display(self):
        """ Displays all the information related to the transaction object, properly split and arranged.

        Data between parenthesis corresponds to the data encoded following the serialized transaction format.
        (replicates the same encoding being done in serialize method)

        :param self: self
        :type self: TX
        :return: None.
        :rtype: None
        """

        print "version: " + str(self.version) + " (" + change_endianness(
            int2bytes(self.version, 4)) + ")"
        print "number of inputs: " + str(self.inputs) + " (" + encode_varint(
            self.inputs) + ")"
        for i in range(self.inputs):
            print "input " + str(i)
            print "\t previous txid (little endian): " + self.prev_tx_id[i] + \
                  " (" + change_endianness(self.prev_tx_id[i]) + ")"
            print "\t previous tx output (little endian): " + str(self.prev_out_index[i]) + \
                  " (" + change_endianness(int2bytes(self.prev_out_index[i], 4)) + ")"
            print "\t input script (scriptSig) length: " + str(self.scriptSig_len[i]) \
                  + " (" + encode_varint((self.scriptSig_len[i])) + ")"
            print "\t input script (scriptSig): " + self.scriptSig[i].content
            print "\t decoded scriptSig: " + Script.deserialize(
                self.scriptSig[i].content)
            if self.scriptSig[i].type is "P2SH":
                print "\t \t decoded redeemScript: " + InputScript.deserialize(
                    self.scriptSig[i].get_element(-1)[1:-1])
            print "\t nSequence: " + str(self.nSequence[i]) + " (" + int2bytes(
                self.nSequence[i], 4) + ")"
        print "number of outputs: " + str(self.outputs) + " (" + encode_varint(
            self.outputs) + ")"
        for i in range(self.outputs):
            print "output " + str(i)
            print "\t Satoshis to be spent (little endian): " + str(self.value[i]) + \
                  " (" + change_endianness(int2bytes(self.value[i], 8)) + ")"
            print "\t output script (scriptPubKey) length: " + str(self.scriptPubKey_len[i]) \
                  + " (" + encode_varint(self.scriptPubKey_len[i]) + ")"
            print "\t output script (scriptPubKey): " + self.scriptPubKey[
                i].content
            print "\t decoded scriptPubKey: " + Script.deserialize(
                self.scriptPubKey[i].content)

        print "nLockTime: " + str(self.nLockTime) + " (" + int2bytes(
            self.nLockTime, 4) + ")"
Пример #3
0
def ecdsa_tx_sign(unsigned_tx, sk, hashflag=SIGHASH_ALL, deterministic=True):
    """ Performs and ECDSA sign over a given transaction using a given secret key.
    :param unsigned_tx: unsigned transaction that will be double-sha256 and signed.
    :type unsigned_tx: hex str
    :param sk: ECDSA private key that will sign the transaction.
    :type sk: SigningKey
    :param hashflag: hash type that will be used during the signature process and will identify the signature format.
    :type hashflag: int
    :param deterministic: Whether the signature is performed using a deterministic k or not. Set by default.
    :type deterministic: bool
    :return:
    """

    # Encode the hash type as a 4-byte hex value.
    if hashflag in [SIGHASH_ALL, SIGHASH_SINGLE, SIGHASH_NONE]:
        hc = int2bytes(hashflag, 4)
    else:
        raise Exception("Wrong hash flag.")

    # ToDo: Deal with SIGHASH_ANYONECANPAY

    # sha-256 the unsigned transaction together with the hash type (little endian).
    h = sha256(unhexlify(unsigned_tx + change_endianness(hc))).digest()
    # Sign the transaction (using a sha256 digest, that will conclude with the double-sha256)
    # If deterministic is set, the signature will be performed deterministically choosing a k from the given transaction
    if deterministic:
        s = sk.sign_deterministic(h,
                                  hashfunc=sha256,
                                  sigencode=sigencode_der_canonize)
    # Otherwise, k will be chosen at random. Notice that this can lead to a private key disclosure if two different
    # messages are signed using the same k.
    else:
        s = sk.sign(h, hashfunc=sha256, sigencode=sigencode_der_canonize)

    # Finally, add the hashtype to the end of the signature as a 2-byte big endian hex value.
    return hexlify(s) + hc[-2:]
Пример #4
0
    def display(self):
        """ Displays all the information related to the transaction object, properly split and arranged.

        Data between parenthesis corresponds to the data encoded following the serialized transaction format.
        (replicates the same encoding being done in serialize method)

        :param self: self
        :type self: TX
        :return: None.
        :rtype: None
        """

        print("version: " + str(self.version) + " (" +
              change_endianness(int2bytes(self.version, 4)) + ")")
        if self.version == 2:
            print(
                'BIP68 Relative lock-time using consensus-enforced sequence numbers'
            )
        if self.isWitness:
            print('Witness TX')
        else:
            print('Non-Witness TX')
        print("number of inputs: " + str(self.inputs) + " (" +
              encode_varint(self.inputs) + ")")
        for i in range(self.inputs):
            print("input " + str(i))
            print("\t previous txid (little endian): " + self.prev_tx_id[i] +
                  " (" + change_endianness(self.prev_tx_id[i]) + ")")
            print("\t previous tx output (little endian): " +
                  str(self.prev_out_index[i]) + " (" +
                  change_endianness(int2bytes(self.prev_out_index[i], 4)) +
                  ")")
            print("\t input script (scriptSig) length: " +
                  str(self.scriptSig_len[i]) + " (" +
                  encode_varint((self.scriptSig_len[i])) + ")")
            print("\t input script (scriptSig): " + self.scriptSig[i].content)
            print("\t decoded scriptSig: " +
                  Script.deserialize(self.scriptSig[i].content))
            if self.scriptSig[i].type == "P2SH":
                print("\t \t decoded redeemScript: " + InputScript.deserialize(
                    self.scriptSig[i].get_element(-1)[1:-1]))
            print("\t nSequence: " + str(self.nSequence[i]) + " (" +
                  int2bytes(self.nSequence[i], 4) + ")")
            if self.isWitness:  # todo! chack if there a TX with more than 1 witnes vin or with witness 0
                print("\t txinwitness:")
                for _ in self.scriptWitness[i]:
                    print('\t\t', _)

        print("number of outputs: " + str(self.outputs) + " (" +
              encode_varint(self.outputs) + ")")
        for i in range(self.outputs):
            print("output " + str(i))
            print("\t Satoshis to be spent (little endian): " +
                  str(self.value[i]) + " (" +
                  change_endianness(int2bytes(self.value[i], 8)) + ")")
            print("\t output script (scriptPubKey) length: " +
                  str(self.scriptPubKey_len[i]) + " (" +
                  encode_varint(self.scriptPubKey_len[i]) + ")")
            print("\t output script (scriptPubKey): " +
                  self.scriptPubKey[i].content)
            print("\t decoded scriptPubKey: " +
                  Script.deserialize(self.scriptPubKey[i].content))

        print("nLockTime: " + str(self.nLockTime) + " (" +
              int2bytes(self.nLockTime, 4) + ")")