예제 #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 get_serialized_size(utxo, verbose=True):
    """
    Computes the uncompressed serialized size of an UTXO. This version is slower than get_serialized_size_fast version
    (Don't you say!) since it performs the actual decompress and online calculation of the size of the script.

    Watch out! Use get_serialized_size_fast when parsing the whole UTXO set, this version will make you spend way more
    time.

    :param utxo: unspent output to compute the size
    :type utxo: dict
    :param verbose: Just warns you about using the slow version.
    :type verbose: bool
    :return: size in bytes
    :rtype int
    """

    if verbose:
        print(
            "You're using the non-fast version of get_serialized_size. You may want to use the fast version specially"
            "if parsing the whole UTXO set")

    # Decompress the UTXO script
    out_script = decompress_script(utxo.get('data'), utxo.get('out_type'))
    out_size = len(out_script) / 2

    # Add the number of bytes corresponding to the scriptPubKey length
    out_size += len(encode_varint(out_size)) / 2

    # Add 8 bytes for bitcoin value
    out_size += 8

    return out_size
예제 #3
0
def get_serialized_size(utxo):
    """
    Computes the uncompressed serialized size of an UTXO.

    :param utxo: unspent output to compute the size
    :type utxo: dict
    :return: size in bytes
    :rtype int
    """

    if utxo.get("out_type") is 0:
        # P2PKH: OP_DUP (1 byte) + OP_HASH160 (1 byte) + PUSH (1 byte) + HASH160 (20 bytes) + OP_EQUALVERIFY (1 byte) +
        # OP_CHECKSIG (1 byte) = 25 bytes
        out_size = 25
    elif utxo.get("out_type") is 1:
        # P2SH: OP_HASH160 (1 byte) + PUSH (1 byte) + HAS160 (20 bytes) + OP_EQUAL (1 byte) = 23 bytes
        out_size = 23
    elif utxo.get("out_type") in [2, 3]:
        # P2PK compressed: PUSH (1 byte) + compressed_pk (33 bytes) + OP_CHECKSIG (1 byte) = 35 bytes
        out_size = 35
    elif utxo.get("out_type") in [4, 5]:
        # P2PK uncompressed: PUSH (1 byte) + uncompressed_pk (65 bytes) + OP_CHECKSIG (1 byte) = 67 bytes
        out_size = 67
    else:
        # Any other type will have the full script stored in the utxo
        out_size = len(utxo.get("data")) / 2

    # Add the number of bytes corresponding to the scriptPubKey length
    out_size += len(encode_varint(out_size)) / 2

    # Add 8 bytes for bitcoin value
    out_size += 8

    return out_size
예제 #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)) + ")"
        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) + ")"
예제 #5
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) + ")")