Ejemplo n.º 1
0
class BalanceProof(Message):
    """ A Balance Proof

    If transferred_amount, locked_amount and locksroot are set, balance_proof hash is
    computed using these values. Otherwise a value stored in _balance_hash is returned.

    Serialization will also add these items only if each of transferred_amount, locked_amount
    and locksroot is set.
    """
    def __init__(
        self,
        channel_identifier: ChannelIdentifier,
        token_network_address: Address,

        balance_hash: str = None,
        nonce: int = 0,
        additional_hash: str = '0x%064x' % 0,
        chain_id: int = 1,
        signature: str = None,

        transferred_amount: int = None,
        locked_amount: int = 0,
        locksroot: str = '0x%064x' % 0,
    ) -> None:
        super().__init__()
        assert isinstance(channel_identifier, T_ChannelIdentifier)
        assert is_address(token_network_address)

        self._type = 'BalanceProof'

        self.channel_identifier = channel_identifier
        self.token_network_address = token_network_address

        self._balance_hash = balance_hash
        self.additional_hash = additional_hash
        self.nonce = nonce
        self.chain_id = chain_id
        self.signature = signature

        if transferred_amount and locked_amount and locksroot and balance_hash:
            assert 0 <= transferred_amount <= UINT256_MAX
            assert 0 <= locked_amount <= UINT256_MAX
            assert self.hash_balance_data(
                transferred_amount,
                locked_amount,
                locksroot,
            ) == balance_hash

        self.transferred_amount = transferred_amount
        self.locked_amount = locked_amount
        self.locksroot = locksroot

    def serialize_data(self) -> dict:
        result = {
            'channel_identifier': self.channel_identifier,
            'token_network_address': self.token_network_address,

            'balance_hash': self.balance_hash,
            'additional_hash': self.additional_hash,
            'nonce': self.nonce,
            'chain_id': self.chain_id,
            'signature': self.signature,
        }

        if None not in (self.transferred_amount, self.locked_amount, self.locksroot):
            result['transferred_amount'] = self.transferred_amount
            result['locked_amount'] = self.locked_amount
            result['locksroot'] = self.locksroot

        return result

    def serialize_bin(self):
        return pack_data([
            'bytes32',
            'uint256',
            'bytes32',
            'bytes32',
            'address',
            'uint256',
        ], [
            decode_hex(self.balance_hash),
            self.nonce,
            decode_hex(self.additional_hash),
            decode_hex(self.channel_identifier),
            self.token_network_address,
            self.chain_id,
        ])

    @classmethod
    def deserialize(cls, data):
        jsonschema.validate(data, BALANCE_PROOF_SCHEMA)
        result = cls(
            data['channel_identifier'],
            data['token_network_address'],
            balance_hash=data['balance_hash'],
            nonce=data['nonce'],
            additional_hash=data['additional_hash'],
            chain_id=data['chain_id'],
            signature=data['signature'],

            transferred_amount=data.get('transferred_amount', None),
            locked_amount=data.get('locked_amount', None),
            locksroot=data.get('locksroot', None),
        )
        return result

    token_network_address = address_property('_contract')  # type: ignore
    json_schema = BALANCE_PROOF_SCHEMA

    @property
    def balance_hash(self) -> str:
        if self._balance_hash:
            return self._balance_hash
        if None not in (self.transferred_amount, self.locked_amount, self.locksroot):
            assert isinstance(self.transferred_amount, int)
            return encode_hex(
                self.hash_balance_data(
                    self.transferred_amount,
                    self.locked_amount,
                    self.locksroot,
                ),
            )
        raise ValueError("Can't compute balance hash")

    @balance_hash.setter
    def balance_hash(self, value) -> None:
        self._balance_hash = value

    @property
    def signer(self) -> str:
        signer = eth_verify(
            decode_hex(self.signature),
            self.serialize_bin(),
        )
        return to_checksum_address(signer)

    @staticmethod
    def hash_balance_data(
        transferred_amount: int,
        locked_amount: int,
        locksroot: str,
    ) -> str:
        return Web3.soliditySha3(
            ['uint256', 'uint256', 'bytes32'],
            [transferred_amount, locked_amount, locksroot],
        )
Ejemplo n.º 2
0
class PathsRequest(Message):
    """ A message to request a path from PFS. It is sent from a raiden node to the PFS. """
    def __init__(
        self,
        token_network_address: Address,
        source_address: Address,
        target_address: Address,
        value: int,
        chain_id: int,
        num_paths: int,
        nonce: int,
        signature: str = None,
    ) -> None:
        super().__init__()
        assert is_address(token_network_address)
        assert is_address(source_address)
        assert is_address(target_address)
        assert 0 <= value <= UINT256_MAX
        assert 0 <= num_paths <= UINT256_MAX
        assert 0 <= nonce <= UINT256_MAX

        self._type = 'PathsRequest'
        self.token_network_address = token_network_address
        self.source_address = source_address
        self.target_address = target_address
        self.value = value
        self.num_paths = num_paths
        self.chain_id = chain_id
        self.nonce = nonce
        self.signature = signature

    def serialize_data(self) -> Dict:
        return {
            'token_network_address': self.token_network_address,
            'source_address': self.source_address,
            'target_address': self.target_address,
            'value': self.value,
            'num_paths': self.num_paths,
            'chain_id': self.chain_id,
            'nonce': self.nonce,
            'signature': self.signature,
        }

    def serialize_bin(self):
        """Returns PathsRequest serialized to binary"""
        return pack_data([
            'address',
            'address',
            'address',
            'uint256',
            'uint256',
            'uint256',
            'uint256',
        ], [
            self.token_network_address,
            self.source_address,
            self.target_address,
            self.value,
            self.num_paths,
            self.chain_id,
            self.nonce,
        ])

    @classmethod
    def deserialize(cls, data):
        jsonschema.validate(data, PATHS_REQUEST_SCHEMA)
        ret = cls(
            token_network_address=data['token_network_address'],
            source_address=data['source_address'],
            target_address=data['target_address'],
            value=data['value'],
            num_paths=data['num_paths'],
            chain_id=data['chain_id'],
            nonce=data['nonce'],
            signature=data['signature'],
        )

        return ret

    @property
    def signer(self) -> str:
        signer = eth_verify(
            decode_hex(self.signature),
            self.serialize_bin(),
        )
        return to_checksum_address(signer)

    token_network_address = address_property('_contract')  # type: ignore
    json_schema = PATHS_REQUEST_SCHEMA
Ejemplo n.º 3
0
class MonitorRequest(Message):
    """Message sent by a Raiden node to the MS. It cointains all data required to
    call MSC
    """
    monitor_address = address_property('_monitor_address')  # type: ignore
    _type = 'MonitorRequest'

    def __init__(
        self,
        balance_proof: BalanceProof,
        non_closing_signature: str = None,
        reward_proof_signature: bytes = None,  # bytes
        reward_amount: int = None,  # uint192
        monitor_address: Address = None,
    ) -> None:
        assert non_closing_signature is None or len(
            decode_hex(non_closing_signature)) == 65
        assert reward_amount is None or (reward_amount >=
                                         0) and (reward_amount <= UINT192_MAX)
        # todo: validate reward proof signature
        assert is_address(monitor_address)
        assert isinstance(balance_proof, BalanceProof)

        self._balance_proof = balance_proof
        self.non_closing_signature = non_closing_signature
        self.reward_proof_signature = reward_proof_signature
        self.reward_amount = reward_amount
        self.monitor_address = monitor_address

    def serialize_data(self):
        msg = self.__dict__.copy()
        msg.pop('_balance_proof')
        msg['monitor_address'] = msg.pop('_monitor_address')
        msg['balance_proof'] = self.balance_proof.serialize_data()
        msg['reward_proof_signature'] = self.reward_proof_signature
        return msg

    def serialize_reward_proof(self):
        """Return reward proof data serialized to binary"""
        return pack_data([
            'uint256',
            'uint256',
            'address',
            'uint256',
            'uint256',
        ], [
            self.balance_proof.channel_identifier,
            self.reward_amount,
            self.balance_proof.token_network_address,
            self.balance_proof.chain_id,
            self.balance_proof.nonce,
        ])

    @classmethod
    def deserialize(cls, data):
        jsonschema.validate(data, MONITOR_REQUEST_SCHEMA)
        balance_proof = BalanceProof.deserialize(data['balance_proof'])
        result = cls(
            balance_proof,
            data['non_closing_signature'],
            data['reward_proof_signature'],
            data['reward_amount'],
            data['monitor_address'],
        )
        return result

    @property
    def balance_proof(self):
        return self._balance_proof

    @property
    def reward_proof_signer(self) -> str:
        signer = eth_recover(
            data=self.serialize_reward_proof(),
            signature=decode_hex(self.reward_proof_signature),
        )
        return to_checksum_address(signer)

    @property
    def non_closing_signer(self) -> str:
        serialized = self.balance_proof.serialize_bin(
            msg_type=MessageTypeId.BALANCE_PROOF_UPDATE)
        signer = eth_recover(
            data=serialized + decode_hex(self.balance_proof.signature),
            signature=decode_hex(self.non_closing_signature),
        )
        return to_checksum_address(signer)
Ejemplo n.º 4
0
class FeeInfo(Message):
    """ A message to update the fee. It is sent from a raiden node to the PFS. """
    def __init__(
        self,
        token_network_address: Address,
        channel_identifier: ChannelIdentifier,
        chain_id: int = 1,
        nonce: int = 0,
        relative_fee: int = 0,  # in parts per million
        signature: str = None,
    ) -> None:
        """ Creates a new FeeInfo message

        Args:
            relative_fee: The fee defined in parts per million, e.g. a value of 10000
                corresponds to a relative fee of one percent.
        """
        super().__init__()
        assert isinstance(channel_identifier, T_ChannelIdentifier)
        assert is_address(token_network_address)

        self._type = 'FeeInfo'

        self.token_network_address = token_network_address
        self.channel_identifier = channel_identifier
        self.chain_id = chain_id
        self.nonce = nonce
        self.relative_fee = relative_fee
        self.signature = signature

    def serialize_data(self) -> Dict:
        return {
            'token_network_address': self.token_network_address,
            'channel_identifier': self.channel_identifier,
            'chain_id': self.chain_id,
            'nonce': self.nonce,
            'relative_fee': self.relative_fee,
            'signature': self.signature,
        }

    def serialize_bin(self) -> bytes:
        """Return FeeInfo serialized to binary"""
        return pack_data([
            'address',
            'bytes32',
            'uint256',
            'uint256',
            'uint256',
        ], [
            self.token_network_address,
            decode_hex(self.channel_identifier),
            self.chain_id,
            self.nonce,
            self.relative_fee,
        ])

    @classmethod
    def deserialize(cls, data):
        jsonschema.validate(data, FEE_INFO_SCHEMA)
        ret = cls(
            token_network_address=data['token_network_address'],
            channel_identifier=data['channel_identifier'],
            chain_id=data['chain_id'],
            nonce=data['nonce'],
            relative_fee=data['relative_fee'],
            signature=data['signature'],
        )

        return ret

    @property
    def signer(self) -> str:
        signer = eth_verify(
            decode_hex(self.signature),
            self.serialize_bin(),
        )
        return to_checksum_address(signer)

    token_network_address = address_property('_contract')  # type: ignore
    json_schema = FEE_INFO_SCHEMA
Ejemplo n.º 5
0
class PathsReply(Message):
    """ A reply message from PFS to a client. It is sent from PFS to a raiden node . """
    def __init__(
        self,
        token_network_address: Address,
        target_address: Address,
        value: int,
        chain_id: int,
        nonce: int,
        paths_and_fees: list = None,
        signature: str = None,
    ) -> None:
        super().__init__()
        assert is_address(token_network_address)
        assert is_address(target_address)
        assert 0 <= value <= UINT256_MAX
        assert 0 <= nonce <= UINT256_MAX

        self._type = 'PathsReply'
        self.token_network_address = token_network_address
        self.target_address = target_address
        self.value = value
        self.chain_id = chain_id
        self.nonce = nonce
        self.paths_and_fees = paths_and_fees
        self.signature = signature

    def serialize_data(self) -> Dict:
        return {
            'token_network_address': self.token_network_address,
            'target_address': self.target_address,
            'value': self.value,
            'chain_id': self.chain_id,
            'nonce': self.nonce,
            'paths_and_fees': self.paths_and_fees,
            'signature': self.signature,
        }

    def serialize_bin(self):
        """Returns PathsReply serialized to binary"""
        return pack_data([
            'address',
            'address',
            'uint256',
            'uint256',
            'uint256',
            'array',
            'signature',
        ], [
            self.token_network_address,
            self.target_address,
            self.value,
            self.chain_id,
            self.nonce,
            self.paths_and_fees,
            self.signature,
        ])

    @classmethod
    def deserialize(cls, data):
        jsonschema.validate(data, PATHS_REPLY_SCHEMA)
        ret = cls(
            token_network_address=data['token_network_address'],
            target_address=data['target_address'],
            value=data['value'],
            chain_id=data['chain_id'],
            nonce=data['nonce'],
            paths_and_fees=data['paths_and_fees'],
            signature=data['signature'],
        )

        return ret

    @property
    def signer(self) -> str:
        signer = eth_recover(
            data=self.serialize_bin(),
            signature=decode_hex(self.signature),
        )
        return to_checksum_address(signer)

    token_network_address = address_property('_contract')  # type: ignore
    json_schema = PATHS_REPLY_SCHEMA
Ejemplo n.º 6
0
class BalanceProof(Message):
    """ A Balance Proof

    This optionally includse the data for calculating the balance_hash.
    """
    def __init__(
        self,
        channel_identifier: ChannelIdentifier,
        token_network_address: Address,
        balance_hash: str = None,
        nonce: int = 0,
        additional_hash: str = None,
        chain_id: int = 1,
        signature: str = None,
        transferred_amount: int = None,
        locked_amount: int = None,
        locksroot: str = None,
    ) -> None:
        super().__init__()
        assert channel_identifier > 0
        assert is_address(token_network_address)

        self._type = 'BalanceProof'

        self.channel_identifier = channel_identifier
        self.token_network_address = token_network_address

        self._balance_hash = balance_hash
        self.additional_hash = additional_hash
        self.nonce = nonce
        self.chain_id = chain_id
        self.signature = signature

        if transferred_amount and locked_amount and locksroot and balance_hash:
            assert 0 <= transferred_amount <= UINT256_MAX
            assert 0 <= locked_amount <= UINT256_MAX
            assert self.hash_balance_data(transferred_amount, locked_amount,
                                          locksroot) == balance_hash

        self.transferred_amount = transferred_amount
        self.locked_amount = locked_amount
        self.locksroot = locksroot

    def serialize_data(self) -> dict:
        result = {
            'channel_identifier': self.channel_identifier,
            'token_network_address': self.token_network_address,
            'balance_hash': self.balance_hash,
            'additional_hash': self.additional_hash,
            'nonce': self.nonce,
            'chain_id': self.chain_id,
            'signature': self.signature,
        }

        if None not in (self.transferred_amount, self.locked_amount,
                        self.locksroot):
            result['transferred_amount'] = self.transferred_amount
            result['locked_amount'] = self.locked_amount
            result['locksroot'] = self.locksroot

        return result

    def serialize_bin(self):
        return pack_data(
            ['bytes32', 'uint256', 'bytes32', 'uint256', 'address', 'uint256'],
            [
                decode_hex(self.balance_hash), self.nonce,
                decode_hex(self.additional_hash), self.channel_identifier,
                self.token_network_address, self.chain_id
            ])

    @classmethod
    def deserialize(cls, data):
        jsonschema.validate(data, BALANCE_PROOF_SCHEMA)
        result = cls(
            data['channel_identifier'],
            data['token_network_address'],
            balance_hash=data['balance_hash'],
            nonce=data['nonce'],
            additional_hash=data['additional_hash'],
            chain_id=data['chain_id'],
            signature=data['signature'],
            transferred_amount=data.get('transferred_amount', None),
            locked_amount=data.get('locked_amount', None),
            locksroot=data.get('locksroot', None),
        )
        return result

    token_network_address = address_property('_contract')  # type: ignore
    json_schema = BALANCE_PROOF_SCHEMA

    @property
    def balance_hash(self) -> str:
        if self._balance_hash:
            return self._balance_hash
        if None not in (self.transferred_amount, self.locked_amount,
                        self.locksroot):
            return encode_hex(
                self.hash_balance_data(self.transferred_amount,
                                       self.locked_amount, self.locksroot))
        raise ValueError("Can't compute balance hash")

    @property
    def signer(self) -> str:
        return eth_verify(decode_hex(self.signature), self.serialize_bin())

    @staticmethod
    def hash_balance_data(transferred_amount: int, locked_amount: int,
                          locksroot: str) -> str:
        return Web3.soliditySha3(
            ['uint256', 'uint256', 'bytes32'],
            [transferred_amount, locked_amount, locksroot])