Exemplo n.º 1
0
    def _register_secret_batch(self, secrets):
        gas_limit = self.proxy.estimate_gas('registerSecretBatch', secrets)
        gas_limit = safe_gas_limit(
            gas_limit,
            len(secrets) * GAS_REQUIRED_PER_SECRET_IN_BATCH)
        transaction_hash = self.proxy.transact('registerSecretBatch',
                                               gas_limit, secrets)
        self.client.poll(transaction_hash)
        receipt_or_none = check_transaction_threw(self.client,
                                                  transaction_hash)

        if receipt_or_none:
            raise TransactionThrew('registerSecretBatch', receipt_or_none)

        return transaction_hash
Exemplo n.º 2
0
    def register_endpoint(self, node_address, endpoint):
        if node_address != self.client.sender:
            raise ValueError("node_address doesnt match this node's address")

        transaction_hash = self.proxy.transact(
            'registerEndpoint',
            endpoint,
        )

        self.client.poll(transaction_hash)

        receipt_or_none = check_transaction_threw(self.client,
                                                  transaction_hash)
        if receipt_or_none:
            raise TransactionThrew('Register Endpoint', receipt_or_none)
Exemplo n.º 3
0
    def unlock(
        self,
        channel_identifier: typing.ChannelID,
        partner: typing.Address,
        merkle_tree_leaves: typing.MerkleTreeLeaves,
    ):
        log_details = {
            'token_network': pex(self.address),
            'node': pex(self.node_address),
            'partner': pex(partner),
            'merkle_tree_leaves': merkle_tree_leaves,
        }

        if merkle_tree_leaves is None or not merkle_tree_leaves:
            log.info('skipping unlock, tree is empty', **log_details)
            return

        log.info('unlock called', **log_details)

        leaves_packed = b''.join(lock.encoded for lock in merkle_tree_leaves)

        transaction_hash = self.proxy.transact(
            'unlock',
            self.node_address,
            partner,
            leaves_packed,
        )

        self.client.poll(transaction_hash)
        receipt_or_none = check_transaction_threw(self.client,
                                                  transaction_hash)

        if receipt_or_none:
            channel_settled = self.channel_is_settled(self.node_address,
                                                      partner)

            if channel_settled is False:
                log.critical(
                    'unlock failed. Channel is not in a settled state',
                    **log_details)
                raise ChannelIncorrectStateError(
                    'Channel is not in a settled state. An unlock cannot be made',
                )

            log.critical('unlock failed', **log_details)
            raise TransactionThrew('Unlock', receipt_or_none)

        log.info('unlock successful', **log_details)
Exemplo n.º 4
0
    def withdraw(
        self,
        channel_identifier: typing.ChannelID,
        partner: typing.Address,
        total_withdraw: int,
        partner_signature: typing.Address,
        signature: typing.Signature,
    ):
        log_details = {
            'token_network': pex(self.address),
            'node': pex(self.node_address),
            'partner': pex(partner),
            'total_withdraw': total_withdraw,
            'partner_signature': encode_hex(partner_signature),
            'signature': encode_hex(signature),
        }
        log.info('withdraw called', **log_details)

        self._check_for_outdated_channel(
            self.node_address,
            partner,
            channel_identifier,
        )

        with self.channel_operations_lock[partner]:
            transaction_hash = self.proxy.transact(
                'setTotalWithdraw',
                self.node_address,
                partner,
                total_withdraw,
                partner_signature,
                signature,
            )
            self.client.poll(transaction_hash)

            receipt_or_none = check_transaction_threw(self.client,
                                                      transaction_hash)
            if receipt_or_none:
                log.critical('withdraw failed', **log_details)
                channel_opened = self.channel_is_opened(
                    self.node_address, partner)
                if channel_opened is False:
                    raise ChannelIncorrectStateError(
                        'Channel is not in an opened state. A withdraw cannot be made',
                    )
                raise TransactionThrew('Withdraw', receipt_or_none)

            log.info('withdraw successful', **log_details)
Exemplo n.º 5
0
    def withdraw(self, unlock_proofs):
        # force a list to get the length (could be a generator)
        unlock_proofs = list(unlock_proofs)

        if log.isEnabledFor(logging.INFO):
            log.info('withdraw called', contract=pex(self.address))

        failed = False
        for merkle_proof, locked_encoded, secret in unlock_proofs:
            if isinstance(locked_encoded, messages.Lock):
                raise ValueError(
                    'unlock must be called with a lock encoded `.as_bytes`')

            merkleproof_encoded = ''.join(merkle_proof)

            transaction_hash = estimate_and_transact(
                self.proxy.withdraw,
                self.startgas,
                self.gasprice,
                locked_encoded,
                merkleproof_encoded,
                secret,
            )

            self.client.poll(transaction_hash.decode('hex'),
                             timeout=self.poll_timeout)
            receipt_or_none = check_transaction_threw(self.client,
                                                      transaction_hash)
            lock = messages.Lock.from_bytes(locked_encoded)
            if receipt_or_none:
                lock = messages.Lock.from_bytes(locked_encoded)
                log.critical(
                    'withdraw failed',
                    contract=pex(self.address),
                    lock=lock,
                )
                self._check_exists()
                failed = True

            if log.isEnabledFor(logging.INFO):
                log.info(
                    'withdraw sucessfull',
                    contract=pex(self.address),
                    lock=lock,
                )

        if failed:
            raise TransactionThrew('Withdraw', receipt_or_none)
Exemplo n.º 6
0
    def add_token(self, token_address: typing.TokenAddress):
        if not isaddress(token_address):
            raise InvalidAddress('Expected binary address format for token')

        log.info(
            'add_token called',
            node=pex(self.node_address),
            token_address=pex(token_address),
            registry_address=pex(self.address),
        )

        transaction_hash = self.proxy.transact('createERC20TokenNetwork',
                                               token_address)

        self.client.poll(unhexlify(transaction_hash),
                         timeout=self.poll_timeout)
        receipt_or_none = check_transaction_threw(self.client,
                                                  transaction_hash)
        if receipt_or_none:
            log.info(
                'add_token failed',
                node=pex(self.node_address),
                token_address=pex(token_address),
                registry_address=pex(self.address),
            )
            raise TransactionThrew('createERC20TokenNetwork', receipt_or_none)

        token_network_address = self.token_to_tokennetwork(token_address)

        if token_network_address is None:
            log.info(
                'add_token failed and check_transaction_threw didnt detect it',
                node=pex(self.node_address),
                token_address=pex(token_address),
                registry_address=pex(self.address),
            )

            raise RuntimeError('token_to_token_networks failed')

        log.info(
            'add_token sucessful',
            node=pex(self.node_address),
            token_address=pex(token_address),
            registry_address=pex(self.address),
            token_network_address=pex(token_network_address),
        )

        return token_network_address
Exemplo n.º 7
0
    def set_total_deposit(self, total_deposit):
        """ Set the total deposit of token in the channel.

        Raises:
            AddressWithoutCode: If the channel was settled prior to the call.
            ChannelBusyError: If the channel is busy with another operation
            RuntimeError: If the netting channel token address is empty.
        """
        if not isinstance(total_deposit, int):
            raise ValueError('total_deposit needs to be an integral number.')
        log.info(
            'set_total_deposit called',
            node=pex(self.node_address),
            contract=pex(self.address),
            amount=total_deposit,
        )

        if not self.channel_operations_lock.acquire(blocking=False):
            raise ChannelBusyError(
                f'Channel with address {self.address} is '
                f'busy with another ongoing operation.', )

        with releasing(self.channel_operations_lock):
            transaction_hash = self.proxy.transact(
                'setTotalDeposit',
                total_deposit,
            )

            self.client.poll(unhexlify(transaction_hash))

            receipt_or_none = check_transaction_threw(self.client,
                                                      transaction_hash)
            if receipt_or_none:
                log.critical(
                    'set_total_deposit failed',
                    node=pex(self.node_address),
                    contract=pex(self.address),
                )

                self._check_exists()
                raise TransactionThrew('Deposit', receipt_or_none)

            log.info(
                'set_total_deposit successful',
                node=pex(self.node_address),
                contract=pex(self.address),
                amount=total_deposit,
            )
Exemplo n.º 8
0
    def add_token(self, token_address: typing.TokenAddress):
        if not is_binary_address(token_address):
            raise InvalidAddress('Expected binary address format for token')

        log_details = {
            'node': pex(self.node_address),
            'token_address': pex(token_address),
            'registry_address': pex(self.address),
        }
        log.debug('createERC20TokenNetwork called', **log_details)

        transaction_hash = self.proxy.transact(
            'createERC20TokenNetwork',
            safe_gas_limit(GAS_REQUIRED_FOR_CREATE_ERC20_TOKEN_NETWORK),
            token_address,
        )

        self.client.poll(transaction_hash)
        receipt_or_none = check_transaction_threw(self.client,
                                                  transaction_hash)
        if receipt_or_none:
            if self.get_token_network(token_address):
                msg = 'Token already registered'
                log.info(f'createERC20TokenNetwork failed, {msg}',
                         **log_details)
                raise RaidenRecoverableError(msg)

            log.critical(f'createERC20TokenNetwork failed', **log_details)
            raise TransactionThrew('createERC20TokenNetwork', receipt_or_none)

        token_network_address = self.get_token_network(token_address)

        if token_network_address is None:
            log.critical(
                'createERC20TokenNetwork failed and check_transaction_threw didnt detect it',
                **log_details,
            )

            raise RuntimeError('token_to_token_networks failed')

        log.info(
            'createERC20TokenNetwork successful',
            token_network_address=pex(token_network_address),
            **log_details,
        )

        return token_network_address
Exemplo n.º 9
0
    def update_transfer(
        self,
        partner: typing.Address,
        nonce: typing.Nonce,
        balance_hash: typing.BalanceHash,
        additional_hash: typing.AdditionalHash,
        closing_signature: typing.Signature,
        non_closing_signature: typing.Signature,
    ):
        log_details = {
            'token_network': pex(self.address),
            'node': pex(self.node_address),
            'partner': pex(partner),
            'nonce': nonce,
            'balance_hash': encode_hex(balance_hash),
            'additional_hash': encode_hex(additional_hash),
            'closing_signature': encode_hex(closing_signature),
            'non_closing_signature': encode_hex(non_closing_signature),
        }
        log.info('updateNonClosingBalanceProof called', **log_details)

        transaction_hash = self.proxy.transact(
            'updateNonClosingBalanceProof',
            partner,
            self.node_address,
            balance_hash,
            nonce,
            additional_hash,
            closing_signature,
            non_closing_signature,
        )

        self.client.poll(unhexlify(transaction_hash))

        receipt_or_none = check_transaction_threw(self.client,
                                                  transaction_hash)
        if receipt_or_none:
            log.critical('updateNonClosingBalanceProof failed', **log_details)
            channel_closed = self.channel_is_closed(self.node_address, partner)
            if channel_closed is False:
                raise ChannelIncorrectStateError(
                    'Channel is not in a closed state')
            raise TransactionThrew('Update NonClosing balance proof',
                                   receipt_or_none)

        log.info('updateNonClosingBalanceProof successful', **log_details)
Exemplo n.º 10
0
    def register_endpoint(self, node_address, endpoint):
        if node_address != self.client.sender:
            raise ValueError("node_address doesnt match this node's address")

        transaction_hash = self.proxy.registerEndpoint.transact(
            endpoint,
            gasprice=self.gasprice,
            startgas=DISCOVERY_REGISTRATION_GAS)

        self.client.poll(
            transaction_hash.decode('hex'),
            timeout=self.poll_timeout,
        )

        receipt_or_none = check_transaction_threw(self.client,
                                                  transaction_hash)
        if receipt_or_none:
            raise TransactionThrew('Register Endpoint', receipt_or_none)
Exemplo n.º 11
0
    def approve(self, contract_address, allowance):
        """ Aprove `contract_address` to transfer up to `deposit` amount of token. """
        # TODO: check that `contract_address` is a netting channel and that
        # `self.address` is one of the participants (maybe add this logic into
        # `NettingChannel` and keep this straight forward)

        transaction_hash = estimate_and_transact(
            self.proxy.approve,
            self.startgas,
            self.gasprice,
            contract_address,
            allowance,
        )

        self.client.poll(transaction_hash.decode('hex'), timeout=self.poll_timeout)
        receipt_or_none = check_transaction_threw(self.client, transaction_hash)
        if receipt_or_none:
            raise TransactionThrew('Approve', receipt_or_none)
Exemplo n.º 12
0
    def withdraw(self, unlock_proof):
        if log.isEnabledFor(logging.INFO):
            log.info(
                'withdraw called',
                node=pex(self.node_address),
                contract=pex(self.address),
            )

        if isinstance(unlock_proof.lock_encoded, messages.Lock):
            raise ValueError(
                'unlock must be called with a lock encoded `.as_bytes`')

        merkleproof_encoded = ''.join(unlock_proof.merkle_proof)

        transaction_hash = estimate_and_transact(
            self.proxy,
            'withdraw',
            unlock_proof.lock_encoded,
            merkleproof_encoded,
            unlock_proof.secret,
        )

        self.client.poll(unhexlify(transaction_hash),
                         timeout=self.poll_timeout)
        receipt_or_none = check_transaction_threw(self.client,
                                                  transaction_hash)

        if receipt_or_none:
            log.critical(
                'withdraw failed',
                node=pex(self.node_address),
                contract=pex(self.address),
                lock=unlock_proof,
            )
            self._check_exists()
            raise TransactionThrew('Withdraw', receipt_or_none)

        elif log.isEnabledFor(logging.INFO):
            log.info(
                'withdraw sucessfull',
                node=pex(self.node_address),
                contract=pex(self.address),
                lock=unlock_proof,
            )
Exemplo n.º 13
0
    def settle(self):
        if log.isEnabledFor(logging.INFO):
            log.info('settle called')

        transaction_hash = estimate_and_transact(
            self.proxy.settle,
            self.startgas,
            self.gasprice,
        )

        self.client.poll(transaction_hash.decode('hex'), timeout=self.poll_timeout)
        receipt_or_none = check_transaction_threw(self.client, transaction_hash)
        if receipt_or_none:
            log.info('settle failed', contract=pex(self.address))
            self._check_exists()
            raise TransactionThrew('Settle', receipt_or_none)

        if log.isEnabledFor(logging.INFO):
            log.info('settle sucessfull', contract=pex(self.address))
Exemplo n.º 14
0
    def unlock(self, partner: typing.Address,
               merkle_tree_leaves: typing.MerkleTreeLeaves):
        log.info(
            'unlock called',
            token_network=pex(self.address),
            node=pex(self.node_address),
            partner=pex(partner),
        )

        # TODO see if we need to do any checks for the unlock_proof

        transaction_hash = self.proxy.transact(
            'unlock',
            self.node_address,
            partner,
            merkle_tree_leaves,
        )

        self.client.poll(unhexlify(transaction_hash),
                         timeout=self.poll_timeout)
        receipt_or_none = check_transaction_threw(self.client,
                                                  transaction_hash)

        if receipt_or_none:
            log.critical(
                'unlock failed',
                token_network=pex(self.address),
                node=pex(self.node_address),
                partner=pex(partner),
            )
            channel_settled = self.channel_is_settled(partner)
            if channel_settled is False:
                raise ChannelIncorrectStateError(
                    'Channel is not in a settled state. An unlock cannot be made',
                )
            raise TransactionThrew('Unlock', receipt_or_none)

        log.info(
            'unlock successful',
            token_network=pex(self.address),
            node=pex(self.node_address),
            partner=pex(partner),
        )
Exemplo n.º 15
0
    def settle(self):
        """ Settle the channel.

        Raises:
            ChannelBusyError: If the channel is busy with another operation
        """
        if log.isEnabledFor(logging.INFO):
            log.info(
                'settle called',
                node=pex(self.node_address),
            )

        if not self.channel_operations_lock.acquire(0):
            raise ChannelBusyError(
                f'Channel with address {self.address} is '
                f'busy with another ongoing operation'
            )

        self.channel_operations_lock.release()

        with self.channel_operations_lock:
            transaction_hash = estimate_and_transact(
                self.proxy,
                'settle',
            )

            self.client.poll(unhexlify(transaction_hash), timeout=self.poll_timeout)
            receipt_or_none = check_transaction_threw(self.client, transaction_hash)
            if receipt_or_none:
                log.info(
                    'settle failed',
                    node=pex(self.node_address),
                    contract=pex(self.address),
                )
                self._check_exists()
                raise TransactionThrew('Settle', receipt_or_none)

            if log.isEnabledFor(logging.INFO):
                log.info(
                    'settle successful',
                    node=pex(self.node_address),
                    contract=pex(self.address),
                )
Exemplo n.º 16
0
    def register_secret(self, secret: typing.Secret):
        secrethash = sha3(secret)
        if self.check_registered(secrethash):
            log.info(
                'secret already registered',
                node=pex(self.node_address),
                contract=pex(self.address),
                secrethash=encode_hex(secrethash),
            )
            return

        log.info(
            'registerSecret called',
            node=pex(self.node_address),
            contract=pex(self.address),
        )

        transaction_hash = self.proxy.transact(
            'registerSecret',
            secret,
        )

        self.client.poll(unhexlify(transaction_hash),
                         timeout=self.poll_timeout)
        receipt_or_none = check_transaction_threw(self.client,
                                                  transaction_hash)

        if receipt_or_none:
            log.critical(
                'registerSecret failed',
                node=pex(self.node_address),
                contract=pex(self.address),
                secret=secret,
            )
            raise TransactionThrew('registerSecret', receipt_or_none)

        log.info(
            'registerSecret successful',
            node=pex(self.node_address),
            contract=pex(self.address),
            secret=secret,
        )
Exemplo n.º 17
0
    def unlock(self, unlock_proof):
        log.info(
            'unlock called',
            node=pex(self.node_address),
            contract=pex(self.address),
        )

        if isinstance(unlock_proof.lock_encoded, messages.Lock):
            raise ValueError(
                'unlock must be called with a lock encoded `.as_bytes`')

        merkleproof_encoded = b''.join(unlock_proof.merkle_proof)

        transaction_hash = self.proxy.transact(
            'unlock',
            unlock_proof.lock_encoded,
            merkleproof_encoded,
            unlock_proof.secret,
        )

        self.client.poll(unhexlify(transaction_hash),
                         timeout=self.poll_timeout)
        receipt_or_none = check_transaction_threw(self.client,
                                                  transaction_hash)

        if receipt_or_none:
            log.critical(
                'unlock failed',
                node=pex(self.node_address),
                contract=pex(self.address),
                lock=unlock_proof,
            )
            self._check_exists()
            raise TransactionThrew('unlock', receipt_or_none)

        log.info(
            'unlock successful',
            node=pex(self.node_address),
            contract=pex(self.address),
            lock=unlock_proof,
        )
Exemplo n.º 18
0
    def settle(self):
        """ Settle the channel.

        Raises:
            ChannelBusyError: If the channel is busy with another operation
        """
        log.info(
            'settle called',
            node=pex(self.node_address),
        )

        if not self.channel_operations_lock.acquire(blocking=False):
            raise ChannelBusyError(
                f'Channel with address {self.address} is '
                f'busy with another ongoing operation',
            )

        with releasing(self.channel_operations_lock):
            transaction_hash = self.proxy.transact(
                'settle',
            )

            self.client.poll(unhexlify(transaction_hash), timeout=self.poll_timeout)
            receipt_or_none = check_transaction_threw(self.client, transaction_hash)
            if receipt_or_none:
                log.info(
                    'settle failed',
                    node=pex(self.node_address),
                    contract=pex(self.address),
                )
                self._check_exists()
                raise TransactionThrew('Settle', receipt_or_none)

            log.info(
                'settle successful',
                node=pex(self.node_address),
                contract=pex(self.address),
            )
Exemplo n.º 19
0
    def transfer(self, to_address: Address, amount: TokenAmount):
        # Note that given_block_identifier is not used here as there
        # are no preconditions to check before sending the transaction
        log_details = {
            "node": pex(self.node_address),
            "contract": pex(self.address),
            "to_address": pex(to_address),
            "amount": amount,
        }
        log.debug("transfer called", **log_details)

        startgas = GAS_LIMIT_FOR_TOKEN_CONTRACT_CALL
        transaction_hash = self.proxy.transact(
            "transfer", safe_gas_limit(startgas), to_checksum_address(to_address), amount
        )

        self.client.poll(transaction_hash)
        receipt_or_none = check_transaction_threw(self.client, transaction_hash)
        if receipt_or_none:
            log.critical("transfer failed", **log_details)
            raise TransactionThrew("Transfer", receipt_or_none)

        # TODO: check Transfer event (issue: #2598)
        log.info("transfer successful", **log_details)
Exemplo n.º 20
0
    def register_endpoint(self, node_address, endpoint):
        if node_address != self.client.sender:
            raise ValueError("node_address doesnt match this node's address")

        log_details = {
            'node': pex(self.node_address),
            'node_address': pex(node_address),
            'endpoint': endpoint,
        }
        log.debug('registerEndpoint called', **log_details)

        transaction_hash = self.proxy.transact(
            'registerEndpoint',
            endpoint,
        )

        self.client.poll(transaction_hash)

        receipt_or_none = check_transaction_threw(self.client, transaction_hash)
        if receipt_or_none:
            log.critical('registerEndpoint failed', **log_details)
            raise TransactionThrew('Register Endpoint', receipt_or_none)

        log.debug('registerEndpoint successful', **log_details)
Exemplo n.º 21
0
    def transfer(self, to_address, amount):
        log_details = {
            'node': pex(self.node_address),
            'contract': pex(self.address),
            'to_address': pex(to_address),
            'amount': amount,
        }
        log.debug('transfer called', **log_details)

        transaction_hash = self.proxy.transact(
            'transfer',
            to_checksum_address(to_address),
            amount,
        )

        self.client.poll(transaction_hash)
        receipt_or_none = check_transaction_threw(self.client,
                                                  transaction_hash)
        if receipt_or_none:
            log.critical('transfer failed', **log_details)
            raise TransactionThrew('Transfer', receipt_or_none)

        # TODO: check Transfer event (issue: #2598)
        log.info('transfer successful', **log_details)
Exemplo n.º 22
0
    def register_endpoint(self, node_address, endpoint):
        if node_address != self.client.address:
            raise ValueError("node_address doesnt match this node's address")

        log_details = {
            "node": pex(self.node_address),
            "node_address": pex(node_address),
            "endpoint": endpoint,
        }
        log.debug("registerEndpoint called", **log_details)

        transaction_hash = self.proxy.transact(
            "registerEndpoint",
            safe_gas_limit(GAS_REQUIRED_FOR_ENDPOINT_REGISTER), endpoint)

        self.client.poll(transaction_hash)

        receipt_or_none = check_transaction_threw(self.client,
                                                  transaction_hash)
        if receipt_or_none:
            log.critical("registerEndpoint failed", **log_details)
            raise TransactionThrew("Register Endpoint", receipt_or_none)

        log.debug("registerEndpoint successful", **log_details)
Exemplo n.º 23
0
    def update_transfer(
        self,
        nonce,
        transferred_amount,
        locked_amount,
        locksroot,
        extra_hash,
        signature,
    ):
        if signature:
            log.info(
                'updateTransfer called',
                node=pex(self.node_address),
                contract=pex(self.address),
                nonce=nonce,
                transferred_amount=transferred_amount,
                locked_amount=locked_amount,
                locksroot=encode_hex(locksroot),
                extra_hash=encode_hex(extra_hash),
                signature=encode_hex(signature),
            )

            transaction_hash = self.proxy.transact(
                'updateTransfer',
                nonce,
                transferred_amount,
                locked_amount,
                locksroot,
                extra_hash,
                signature,
            )

            self.client.poll(
                unhexlify(transaction_hash),
                timeout=self.poll_timeout,
            )

            receipt_or_none = check_transaction_threw(self.client,
                                                      transaction_hash)
            if receipt_or_none:
                log.critical(
                    'updateTransfer failed',
                    node=pex(self.node_address),
                    contract=pex(self.address),
                    nonce=nonce,
                    transferred_amount=transferred_amount,
                    locked_amount=locked_amount,
                    locksroot=encode_hex(locksroot),
                    extra_hash=encode_hex(extra_hash),
                    signature=encode_hex(signature),
                )
                self._check_exists()
                raise TransactionThrew('Update Transfer', receipt_or_none)

            log.info(
                'updateTransfer successful',
                node=pex(self.node_address),
                contract=pex(self.address),
                nonce=nonce,
                transferred_amount=transferred_amount,
                locked_amount=locked_amount,
                locksroot=encode_hex(locksroot),
                extra_hash=encode_hex(extra_hash),
                signature=encode_hex(signature),
            )
Exemplo n.º 24
0
    def close(self, nonce, transferred_amount, locked_amount, locksroot,
              extra_hash, signature):
        """ Close the channel using the provided balance proof.

        Raises:
            AddressWithoutCode: If the channel was settled prior to the call.
            ChannelBusyError: If the channel is busy with another operation.
        """

        log.info(
            'close called',
            node=pex(self.node_address),
            contract=pex(self.address),
            nonce=nonce,
            transferred_amount=transferred_amount,
            locked_amount=locked_amount,
            locksroot=encode_hex(locksroot),
            extra_hash=encode_hex(extra_hash),
            signature=encode_hex(signature),
        )

        if not self.channel_operations_lock.acquire(blocking=False):
            raise ChannelBusyError(
                f'Channel with address {self.address} is '
                f'busy with another ongoing operation.', )

        with releasing(self.channel_operations_lock):
            transaction_hash = self.proxy.transact(
                'close',
                nonce,
                transferred_amount,
                locked_amount,
                locksroot,
                extra_hash,
                signature,
            )
            self.client.poll(unhexlify(transaction_hash),
                             timeout=self.poll_timeout)

            receipt_or_none = check_transaction_threw(self.client,
                                                      transaction_hash)
            if receipt_or_none:
                log.critical(
                    'close failed',
                    node=pex(self.node_address),
                    contract=pex(self.address),
                    nonce=nonce,
                    transferred_amount=transferred_amount,
                    locked_amount=locked_amount,
                    locksroot=encode_hex(locksroot),
                    extra_hash=encode_hex(extra_hash),
                    signature=encode_hex(signature),
                )
                self._check_exists()
                raise TransactionThrew('Close', receipt_or_none)

            log.info(
                'close successful',
                node=pex(self.node_address),
                contract=pex(self.address),
                nonce=nonce,
                transferred_amount=transferred_amount,
                locked_amount=locked_amount,
                locksroot=encode_hex(locksroot),
                extra_hash=encode_hex(extra_hash),
                signature=encode_hex(signature),
            )
Exemplo n.º 25
0
    def settle(
        self,
        channel_identifier: typing.ChannelID,
        transferred_amount: int,
        locked_amount: int,
        locksroot: typing.Locksroot,
        partner: typing.Address,
        partner_transferred_amount: int,
        partner_locked_amount: int,
        partner_locksroot: typing.Locksroot,
    ):
        """ Settle the channel.

        Raises:
            ChannelBusyError: If the channel is busy with another operation
        """
        log_details = {
            'token_network': pex(self.address),
            'node': pex(self.node_address),
            'partner': pex(partner),
            'transferred_amount': transferred_amount,
            'locked_amount': locked_amount,
            'locksroot': encode_hex(locksroot),
            'partner_transferred_amount': partner_transferred_amount,
            'partner_locked_amount': partner_locked_amount,
            'partner_locksroot': encode_hex(partner_locksroot),
        }
        log.debug('settle called', **log_details)

        self._check_for_outdated_channel(
            self.node_address,
            partner,
            channel_identifier,
        )

        with self.channel_operations_lock[partner]:
            our_maximum = transferred_amount + locked_amount
            partner_maximum = partner_transferred_amount + partner_locked_amount

            # The second participant transferred + locked amount must be higher
            our_bp_is_larger = our_maximum > partner_maximum

            if our_bp_is_larger:
                transaction_hash = self.proxy.transact(
                    'settleChannel',
                    channel_identifier,
                    partner,
                    partner_transferred_amount,
                    partner_locked_amount,
                    partner_locksroot,
                    self.node_address,
                    transferred_amount,
                    locked_amount,
                    locksroot,
                )
            else:
                transaction_hash = self.proxy.transact(
                    'settleChannel',
                    channel_identifier,
                    self.node_address,
                    transferred_amount,
                    locked_amount,
                    locksroot,
                    partner,
                    partner_transferred_amount,
                    partner_locked_amount,
                    partner_locksroot,
                )

            self.client.poll(transaction_hash)
            receipt_or_none = check_transaction_threw(self.client,
                                                      transaction_hash)
            if receipt_or_none:
                log.critical('settle failed', **log_details)
                self._check_channel_state_for_settle(
                    self.node_address,
                    partner,
                    channel_identifier,
                )
                raise TransactionThrew('Settle', receipt_or_none)

            log.info('settle successful', **log_details)
Exemplo n.º 26
0
    def withdraw(
        self,
        channel_identifier: typing.ChannelID,
        partner: typing.Address,
        total_withdraw: int,
        partner_signature: typing.Address,
        signature: typing.Signature,
    ):
        log_details = {
            'token_network': pex(self.address),
            'node': pex(self.node_address),
            'partner': pex(partner),
            'total_withdraw': total_withdraw,
            'partner_signature': encode_hex(partner_signature),
            'signature': encode_hex(signature),
        }
        log.debug('setTotalWithdraw called', **log_details)

        self._check_for_outdated_channel(
            self.node_address,
            partner,
            channel_identifier,
        )

        current_withdraw = self.detail_participant(
            channel_identifier,
            self.node_address,
            partner,
        ).withdrawn
        amount_to_withdraw = total_withdraw - current_withdraw

        if total_withdraw < current_withdraw:
            msg = (
                f'Current withdraw ({current_withdraw}) is already larger '
                f'than the requested total withdraw amount ({total_withdraw})',
            )
            log.critical(f'setTotalWithdraw failed, {msg}', **log_details)
            raise WithdrawMismatch(msg)

        if amount_to_withdraw <= 0:
            msg = f'withdraw {amount_to_withdraw} must be greater than 0.'
            log.critical(f'setTotalWithdraw failed, {msg}', **log_details)
            raise ValueError(msg)

        with self.channel_operations_lock[partner]:
            transaction_hash = self.proxy.transact(
                'setTotalWithdraw',
                channel_identifier,
                self.node_address,
                total_withdraw,
                partner_signature,
                signature,
            )
            self.client.poll(transaction_hash)

            receipt_or_none = check_transaction_threw(self.client,
                                                      transaction_hash)
            if receipt_or_none:
                log.critical('setTotalWithdraw failed', **log_details)

                self._check_channel_state_for_withdraw(
                    self.node_address,
                    partner,
                    channel_identifier,
                    total_withdraw,
                )

                raise TransactionThrew('Withdraw', receipt_or_none)

            log.info('setTotalWithdraw successful', **log_details)
Exemplo n.º 27
0
    def update_transfer(
        self,
        channel_identifier: typing.ChannelID,
        partner: typing.Address,
        balance_hash: typing.BalanceHash,
        nonce: typing.Nonce,
        additional_hash: typing.AdditionalHash,
        closing_signature: typing.Signature,
        non_closing_signature: typing.Signature,
    ):
        log_details = {
            'token_network': pex(self.address),
            'node': pex(self.node_address),
            'partner': pex(partner),
            'nonce': nonce,
            'balance_hash': encode_hex(balance_hash),
            'additional_hash': encode_hex(additional_hash),
            'closing_signature': encode_hex(closing_signature),
            'non_closing_signature': encode_hex(non_closing_signature),
        }
        log.debug('updateNonClosingBalanceProof called', **log_details)

        self._check_for_outdated_channel(
            self.node_address,
            partner,
            channel_identifier,
        )

        transaction_hash = self.proxy.transact(
            'updateNonClosingBalanceProof',
            channel_identifier,
            partner,
            self.node_address,
            balance_hash,
            nonce,
            additional_hash,
            closing_signature,
            non_closing_signature,
        )

        self.client.poll(transaction_hash)

        receipt_or_none = check_transaction_threw(self.client,
                                                  transaction_hash)
        if receipt_or_none:
            channel_closed = self.channel_is_closed(
                participant1=self.node_address,
                participant2=partner,
                channel_identifier=channel_identifier,
            )
            if channel_closed is False:
                msg = 'Channel is not in a closed state'
                log.critical(f'updateNonClosingBalanceProof failed, {msg}',
                             **log_details)
                raise RaidenUnrecoverableError(msg)

            msg = 'Update NonClosing balance proof'
            log.critical(f'updateNonClosingBalanceProof failed, {msg}',
                         **log_details)
            raise TransactionThrew(msg, receipt_or_none)

        log.info('updateNonClosingBalanceProof successful', **log_details)
Exemplo n.º 28
0
    def close(
        self,
        channel_identifier: typing.ChannelID,
        partner: typing.Address,
        balance_hash: typing.BalanceHash,
        nonce: typing.Nonce,
        additional_hash: typing.AdditionalHash,
        signature: typing.Signature,
    ):
        """ Close the channel using the provided balance proof.

        Raises:
            ChannelBusyError: If the channel is busy with another operation.
            RaidenRecoverableError: If the channel is already closed.
            RaidenUnrecoverableError: If the channel does not exist or is settled.
        """

        log_details = {
            'token_network': pex(self.address),
            'node': pex(self.node_address),
            'partner': pex(partner),
            'nonce': nonce,
            'balance_hash': encode_hex(balance_hash),
            'additional_hash': encode_hex(additional_hash),
            'signature': encode_hex(signature),
        }
        log.debug('closeChannel called', **log_details)

        self._check_for_outdated_channel(
            self.node_address,
            partner,
            channel_identifier,
        )

        self._check_channel_state_for_close(
            self.node_address,
            partner,
            channel_identifier,
        )

        with self.channel_operations_lock[partner]:
            transaction_hash = self.proxy.transact(
                'closeChannel',
                channel_identifier,
                partner,
                balance_hash,
                nonce,
                additional_hash,
                signature,
            )
            self.client.poll(transaction_hash)

            receipt_or_none = check_transaction_threw(self.client,
                                                      transaction_hash)
            if receipt_or_none:
                log.critical('closeChannel failed', **log_details)

                self._check_channel_state_for_close(
                    self.node_address,
                    partner,
                    channel_identifier,
                )

                raise TransactionThrew('Close', receipt_or_none)

            log.info('closeChannel successful', **log_details)
Exemplo n.º 29
0
    def set_total_deposit(
        self,
        channel_identifier: typing.ChannelID,
        total_deposit: typing.TokenAmount,
        partner: typing.Address,
    ):
        """ Set total token deposit in the channel to total_deposit.

        Raises:
            ChannelBusyError: If the channel is busy with another operation
            RuntimeError: If the token address is empty.
        """
        if not isinstance(total_deposit, int):
            raise ValueError('total_deposit needs to be an integral number.')

        self._check_for_outdated_channel(
            self.node_address,
            partner,
            channel_identifier,
        )

        token_address = self.token_address()
        token = Token(self.client, token_address)

        with self.channel_operations_lock[partner], self.deposit_lock:
            # setTotalDeposit requires a monotonically increasing value. This
            # is used to handle concurrent actions:
            #
            #  - The deposits will be done in order, i.e. the monotonic
            #  property is preserved by the caller
            #  - The race of two deposits will be resolved with the larger
            #  deposit winning
            #  - Retries wont have effect
            #
            # This check is serialized with the channel_operations_lock to avoid
            # sending invalid transactions on-chain (decreasing total deposit).
            #
            current_deposit = self.detail_participant(
                channel_identifier,
                self.node_address,
                partner,
            ).deposit
            amount_to_deposit = total_deposit - current_deposit

            log_details = {
                'token_network': pex(self.address),
                'node': pex(self.node_address),
                'partner': pex(partner),
                'total_deposit': total_deposit,
                'amount_to_deposit': amount_to_deposit,
                'id': id(self),
            }
            log.debug('setTotalDeposit called', **log_details)

            # These two scenarions can happen if two calls to deposit happen
            # and then we get here on the second call
            if total_deposit < current_deposit:
                msg = (
                    f'Current deposit ({current_deposit}) is already larger '
                    f'than the requested total deposit amount ({total_deposit})'
                )
                log.info(f'setTotalDeposit failed, {msg}', **log_details)
                raise DepositMismatch(msg)

            if amount_to_deposit <= 0:
                msg = (f'total_deposit - current_deposit =  '
                       f'{amount_to_deposit} must be greater than 0.', )
                log.info(f'setTotalDeposit failed, {msg}', **log_details)
                raise DepositMismatch(msg)

            # A node may be setting up multiple channels for the same token
            # concurrently. Because each deposit changes the user balance this
            # check must be serialized with the operation locks.
            #
            # This check is merely informational, used to avoid sending
            # transactions which are known to fail.
            #
            # It is serialized with the deposit_lock to avoid sending invalid
            # transactions on-chain (account without balance). The lock
            # channel_operations_lock is not sufficient, as it allows two
            # concurrent deposits for different channels.
            #
            current_balance = token.balance_of(self.node_address)
            if current_balance < amount_to_deposit:
                msg = (
                    f'total_deposit - current_deposit =  {amount_to_deposit} can not '
                    f'be larger than the available balance {current_balance}, '
                    f'for token at address {pex(token_address)}')
                log.info(f'setTotalDeposit failed, {msg}', **log_details)
                raise DepositMismatch(msg)

            # If there are channels being set up concurrenlty either the
            # allowance must be accumulated *or* the calls to `approve` and
            # `setTotalDeposit` must be serialized. This is necessary otherwise
            # the deposit will fail.
            #
            # Calls to approve and setTotalDeposit are serialized with the
            # deposit_lock to avoid transaction failure, because with two
            # concurrent deposits, we may have the transactions executed in the
            # following order
            #
            # - approve
            # - approve
            # - setTotalDeposit
            # - setTotalDeposit
            #
            # in which case  the second `approve` will overwrite the first,
            # and the first `setTotalDeposit` will consume the allowance,
            #  making the second deposit fail.
            token.approve(self.address, amount_to_deposit)

            transaction_hash = self.proxy.transact(
                'setTotalDeposit',
                channel_identifier,
                self.node_address,
                total_deposit,
                partner,
            )
            self.client.poll(transaction_hash)

            receipt_or_none = check_transaction_threw(self.client,
                                                      transaction_hash)

            if receipt_or_none:
                if token.allowance(self.node_address,
                                   self.address) < amount_to_deposit:
                    log_msg = (
                        'setTotalDeposit failed. The allowance is insufficient, '
                        'check concurrent deposits for the same token network '
                        'but different proxies.')
                elif token.balance_of(self.node_address) < amount_to_deposit:
                    log_msg = 'setTotalDeposit failed. The address doesnt have funds'
                else:
                    log_msg = 'setTotalDeposit failed'

                log.critical(log_msg, **log_details)

                self._check_channel_state_for_deposit(
                    self.node_address,
                    partner,
                    channel_identifier,
                    total_deposit,
                )

                raise TransactionThrew('Deposit', receipt_or_none)

            log.info('setTotalDeposit successful', **log_details)
Exemplo n.º 30
0
    def settle(
            self,
            transferred_amount: int,
            locked_amount: int,
            locksroot: typing.Locksroot,
            partner: typing.Address,
            partner_transferred_amount: int,
            partner_locked_amount: int,
            partner_locksroot: typing.Locksroot,
    ):
        """ Settle the channel.

        Raises:
            ChannelBusyError: If the channel is busy with another operation
        """
        log.info(
            'settle called',
            token_network=pex(self.address),
            node=pex(self.node_address),
            partner=pex(partner),
            transferred_amount=transferred_amount,
            locked_amount=locked_amount,
            locksroot=encode_hex(locksroot),
            partner_transferred_amount=partner_transferred_amount,
            partner_locked_amount=partner_locked_amount,
            partner_locksroot=encode_hex(partner_locksroot),
        )

        self._check_channel_lock(partner)

        with releasing(self.channel_operations_lock[partner]):
            transaction_hash = self.proxy.transact(
                'settleChannel',
                self.node_address,
                transferred_amount,
                locked_amount,
                locksroot,
                partner,
                partner_transferred_amount,
                partner_locked_amount,
                partner_locksroot,
            )

            self.client.poll(unhexlify(transaction_hash), timeout=self.poll_timeout)
            receipt_or_none = check_transaction_threw(self.client, transaction_hash)
            if receipt_or_none:
                log.info(
                    'settle failed',
                    token_network=pex(self.address),
                    node=pex(self.node_address),
                    partner=pex(partner),
                    transferred_amount=transferred_amount,
                    locked_amount=locked_amount,
                    locksroot=encode_hex(locksroot),
                    partner_transferred_amount=partner_transferred_amount,
                    partner_locked_amount=partner_locked_amount,
                    partner_locksroot=encode_hex(partner_locksroot),
                )
                channel_closed = self.channel_is_closed(partner)
                if channel_closed is False:
                    raise ChannelIncorrectStateError(
                        'Channel is not in a closed state. It cannot be settled',
                    )
                raise TransactionThrew('Settle', receipt_or_none)

            log.info(
                'settle successful',
                token_network=pex(self.address),
                node=pex(self.node_address),
                partner=pex(partner),
                transferred_amount=transferred_amount,
                locked_amount=locked_amount,
                locksroot=encode_hex(locksroot),
                partner_transferred_amount=partner_transferred_amount,
                partner_locked_amount=partner_locked_amount,
                partner_locksroot=encode_hex(partner_locksroot),
            )