Ejemplo n.º 1
0
    def get_bytes(self, skip_signature=False, skip_second_signature=False):
        """
        Serializes the given transaction prior to AIP11 (legacy).
        """
        # TODO: rename to to_bytes which makes more sense than get_bytes
        if self.version and self.version != 1:
            raise Exception(
                "Invalid transaction version")  # TODO: better exception

        bytes_data = bytes()
        bytes_data += write_bit8(self.type)
        bytes_data += write_bit32(self.timestamp)
        bytes_data += write_high(self.sender_public_key)

        # Apply a fix for broken type 1 (second signature) and 4 (multi signature)
        # transactions, which were erroneously calculated with a recipient id,
        # also apply a fix for all other broken transactions
        is_broken_type = self.type in [
            TRANSACTION_TYPE_SECOND_SIGNATURE,
            TRANSACTION_TYPE_MULTI_SIGNATURE,
        ]

        if not self.recipient_id or (is_transaction_exception(self.id)
                                     or is_broken_type):
            bytes_data += pack("21x")
        else:
            bytes_data += b58decode_check(self.recipient_id)

        if self.vendor_field:
            encoded_vendor_field = self.vendor_field.encode("utf-8")
            bytes_data += encoded_vendor_field
            num_of_zeroes = 64 - len(encoded_vendor_field)
            if num_of_zeroes > 0:
                bytes_data += pack("{}x".format(num_of_zeroes))
        else:
            bytes_data += pack("64x")

        bytes_data += write_bit64(self.amount)
        bytes_data += write_bit64(self.fee)

        if self.type == TRANSACTION_TYPE_SECOND_SIGNATURE:
            public_key = self.asset["signature"]["publicKey"]
            bytes_data += unhexlify(public_key)
        elif self.type == TRANSACTION_TYPE_DELEGATE_REGISTRATION:
            bytes_data += self.asset["delegate"]["username"].encode()
        elif self.type == TRANSACTION_TYPE_VOTE:
            bytes_data += "".join(self.asset["votes"]).encode()
        elif self.type == TRANSACTION_TYPE_MULTI_SIGNATURE:
            bytes_data += write_bit8(self.asset["multisignature"]["min"])
            bytes_data += write_bit8(self.asset["multisignature"]["lifetime"])
            bytes_data += "".join(
                self.asset["multisignature"]["keysgroup"]).encode()

        if not skip_signature and self.signature:
            bytes_data += write_high(self.signature)

        if not skip_second_signature and self.sign_signature:
            bytes_data += write_high(self.sign_signature)

        return bytes_data
Ejemplo n.º 2
0
 def _serialize_vendor_field(self):
     """Serialize vendor field of the transaction
     """
     bytes_data = bytes()
     if BaseTransaction.can_have_vendor_field(
             self.type) and self.vendor_field:
         data = self.vendor_field.encode("utf-8")
         bytes_data += write_bit8(len(data))
         bytes_data += data
         return bytes_data
     else:
         bytes_data += write_bit8(0x00)
         return bytes_data
Ejemplo n.º 3
0
    def _serialize_vendor_field(self):
        """Serialize vendor field of the transaction
        """
        bytes_data = bytes()
        if Transaction.can_have_vendor_field(self.type):
            if self.vendor_field:
                bytes_data += write_bit8(len(self.vendor_field))
                bytes_data += self.vendor_field.encode('utf-8')
                return bytes_data
            elif self.vendor_field_hex:
                bytes_data += write_bit8(len(self.vendor_field_hex) / 2)
                bytes_data += self.vendor_field_hex.encode('utf-8')
                return bytes_data

        bytes_data += write_bit8(0x00)
        return bytes_data
Ejemplo n.º 4
0
def address_from_public_key(public_key, network_version=None):
    """Get an address from a public key

    Args:
        public_key (str):
        network_version (int, optional):

    Returns:
        bytes:
    """
    # TODO: also check if public key matches the regex, same as in core
    # ```
    #      const pubKeyRegex = /^[0-9A-Fa-f]{66}$/;
    #    if (!pubKeyRegex.test(publicKey)) {
    #        throw new Error(`publicKey '${publicKey}' is invalid`);
    #   }
    #    ```
    # TODO: resolve the network vesion to get it from the config somehow
    # if not network_version:
    #     network = get_network()
    #     network_version = network['version']

    ripemd160 = hashlib.new('ripemd160', unhexlify(public_key.encode()))
    seed = write_bit8(network_version) + ripemd160.digest()
    return b58encode_check(seed).decode()
Ejemplo n.º 5
0
    def serialize(self):
        """Serialize Transaction
        """
        bytes_data = bytes()  # bytes() or bytes(512)?
        bytes_data += write_bit8(
            0xFF)  # fill, to distinguish between v1 and v2
        bytes_data += write_bit8(self.version or 0x01)
        bytes_data += write_bit8(self.network or config.network["pubKeyHash"])
        bytes_data += write_bit8(self.type)
        bytes_data += write_bit32(self.timestamp)
        bytes_data += write_high(self.sender_public_key.encode("utf-8"))
        bytes_data += write_bit64(self.fee)

        # TODO: test this thorougly as it might be completely wrong
        bytes_data += self._serialize_vendor_field()
        bytes_data += self._serialize_type()
        bytes_data += self._serialize_signatures()

        return hexlify(bytes_data)
Ejemplo n.º 6
0
    def _serialize_signatures(self):
        """Serialize signature data of the transaction
        """
        bytes_data = bytes()
        if self.signature:
            bytes_data += unhexlify(self.signature)

        if self.second_signature:
            bytes_data += unhexlify(self.second_signature)
        elif self.sign_signature:
            bytes_data += unhexlify(self.sign_signature)

        if self.signatures:
            # add 0xff separator to signal start of multi-signature transactions
            bytes_data += write_bit8(0xff)
            bytes_data += unhexlify(''.join(self.signatures))
        return bytes_data
Ejemplo n.º 7
0
def address_from_public_key(public_key, network_version=None):
    """Get an address from a public key

    Args:
        public_key (str):
        network_version (int, optional):

    Returns:
        bytes:
    """
    match = re.fullmatch("^[0-9A-Fa-f]{66}$", public_key)
    if not match:
        raise Exception("Invalid public key")  # TODO: better exception

    if not network_version:
        network_version = config.network["pubKeyHash"]

    ripemd160 = hashlib.new("ripemd160", unhexlify(public_key.encode()))
    payload = write_bit8(network_version) + ripemd160.digest()
    return b58encode_check(payload).decode()
Ejemplo n.º 8
0
    def _serialize_type(self):
        """Serialize transaction specific data (eg. delegate registration)
        """
        bytes_data = bytes()

        if self.type == TRANSACTION_TYPE_TRANSFER:
            bytes_data += write_bit64(self.amount)
            bytes_data += write_bit32(self.expiration or 0)
            bytes_data += write_high(
                hexlify(b58decode_check(self.recipient_id)))

        elif self.type == TRANSACTION_TYPE_SECOND_SIGNATURE:
            bytes_data += unhexlify(
                self.asset['signature']['publicKey'].encode('utf-8'))

        elif self.type == TRANSACTION_TYPE_DELEGATE_REGISTRATION:
            delegate_bytes = hexlify(
                self.asset['delegate']['username'].encode('utf-8'))
            bytes_data += write_bit8(len(delegate_bytes))
            bytes_data += unhexlify(delegate_bytes)

        elif self.type == TRANSACTION_TYPE_VOTE:
            vote_bytes = []
            for vote in self.asset['votes']:
                if vote.startswith('+'):
                    vote_bytes.append('01{}'.format(vote[1:]))
                else:
                    vote_bytes.append('00{}'.format(vote[1:]))
            bytes_data += write_bit8(len(self.asset['votes']))
            bytes_data += unhexlify(''.join(vote_bytes))

        elif self.type == TRANSACTION_TYPE_MULTI_SIGNATURE:
            keysgroup = []
            if self.version is None or self.version == 1:
                for key in self.asset['multisignature']['keysgroup']:
                    keysgroup.append(key[1:] if key.startswith('+') else key)
            else:
                keysgroup = self.asset['multisignature']['keysgroup']

            bytes_data += write_bit8(self.asset['multisignature']['min'])
            bytes_data += write_bit8(
                len(self.asset['multisignature']['keysgroup']))
            bytes_data += write_bit8(self.asset['multisignature']['lifetime'])
            bytes_data += unhexlify(''.join(keysgroup))

        elif self.type == TRANSACTION_TYPE_IPFS:
            bytes_data += write_bit8(len(self.asset['ipfs']['dag']) // 2)
            bytes_data += unhexlify(self.asset['ipfs']['dag'])

        elif self.type == TRANSACTION_TYPE_TIMELOCK_TRANSFER:
            bytes_data += write_bit64(self.amount)
            bytes_data += write_bit8(self.timelock_type)
            bytes_data += write_bit64(self.timelock)
            bytes_data += hexlify(b58decode_check(self.recipientId))

        elif self.type == TRANSACTION_TYPE_MULTI_PAYMENT:
            bytes_data += write_bit32(len(self.asset['payments']))
            for payment in self.asset['payments']:
                bytes_data += write_bit64(payment['amount'])
                bytes_data += hexlify(b58decode_check(payment['recipientId']))

        elif self.type == TRANSACTION_TYPE_DELEGATE_RESIGNATION:
            pass
        else:
            raise Exception(
                'Transaction type is invalid')  # TODO: better exception
        return bytes_data
Ejemplo n.º 9
0
    def _serialize_type(self):
        """Serialize transaction specific data (eg. delegate registration)
        """
        bytes_data = bytes()

        if self.type == TRANSACTION_TYPE_TRANSFER:
            bytes_data += write_bit64(self.amount)
            bytes_data += write_bit32(self.expiration or 0)
            bytes_data += write_high(
                hexlify(b58decode_check(self.recipient_id)))

        elif self.type == TRANSACTION_TYPE_SECOND_SIGNATURE:
            bytes_data += unhexlify(
                self.asset["signature"]["publicKey"].encode("utf-8"))

        elif self.type == TRANSACTION_TYPE_DELEGATE_REGISTRATION:
            delegate_bytes = hexlify(
                self.asset["delegate"]["username"].encode("utf-8"))
            bytes_data += write_bit8(len(delegate_bytes))
            bytes_data += unhexlify(delegate_bytes)

        elif self.type == TRANSACTION_TYPE_VOTE:
            vote_bytes = []
            for vote in self.asset["votes"]:
                if vote.startswith("+"):
                    vote_bytes.append("01{}".format(vote[1:]))
                else:
                    vote_bytes.append("00{}".format(vote[1:]))
            bytes_data += write_bit8(len(self.asset["votes"]))
            bytes_data += unhexlify("".join(vote_bytes))

        elif self.type == TRANSACTION_TYPE_MULTI_SIGNATURE:
            keysgroup = []
            if self.version is None or self.version == 1:
                for key in self.asset["multisignature"]["keysgroup"]:
                    keysgroup.append(key[1:] if key.startswith("+") else key)
            else:
                keysgroup = self.asset["multisignature"]["keysgroup"]

            bytes_data += write_bit8(self.asset["multisignature"]["min"])
            bytes_data += write_bit8(
                len(self.asset["multisignature"]["keysgroup"]))
            bytes_data += write_bit8(self.asset["multisignature"]["lifetime"])
            bytes_data += unhexlify("".join(keysgroup).encode("utf-8"))

        elif self.type == TRANSACTION_TYPE_IPFS:
            bytes_data += write_bit8(len(self.asset["ipfs"]["dag"]) // 2)
            bytes_data += unhexlify(self.asset["ipfs"]["dag"])

        elif self.type == TRANSACTION_TYPE_TIMELOCK_TRANSFER:
            bytes_data += write_bit64(self.amount)
            bytes_data += write_bit8(self.timelock_type)
            bytes_data += write_bit64(self.timelock)
            bytes_data += b58decode_check(self.recipient_id)

        elif self.type == TRANSACTION_TYPE_MULTI_PAYMENT:
            bytes_data += write_bit32(len(self.asset["payments"]))
            for payment in self.asset["payments"]:
                bytes_data += write_bit64(payment["amount"])
                bytes_data += b58decode_check(payment["recipientId"])

        elif self.type == TRANSACTION_TYPE_DELEGATE_RESIGNATION:
            pass
        else:
            raise Exception(
                "Transaction type is invalid")  # TODO: better exception
        return bytes_data