Exemplo n.º 1
0
    def set_url(self, url: str) -> TransactionHash:
        """Sets the url needed to access the service via HTTP for the caller"""
        if not url.strip():
            msg = "Invalid empty URL"
            raise BrokenPreconditionError(msg)

        parsed_url = urlparse(url)
        if parsed_url.scheme not in ("http", "https"):
            msg = "URL provided to service registry must be a valid HTTP(S) endpoint."
            raise BrokenPreconditionError(msg)

        extra_log_details: Dict[str, Any] = {}
        estimated_transaction = self.client.estimate_gas(
            self.proxy, "setURL", extra_log_details, url)
        if estimated_transaction is None:
            msg = f"URL {url} is invalid"
            raise RaidenUnrecoverableError(msg)

        transaction_sent = self.client.transact(estimated_transaction)
        transaction_mined = self.client.poll_transaction(transaction_sent)

        if not was_transaction_successfully_mined(transaction_mined):
            msg = f"URL {url} is invalid"
            raise RaidenUnrecoverableError(msg)
        else:
            return transaction_mined.transaction_hash
Exemplo n.º 2
0
    def set_url(self, url: str) -> None:
        """Sets the url needed to access the service via HTTP for the caller"""
        log_details: Dict[str, Any] = {
            "node": to_checksum_address(self.node_address),
            "contract": to_checksum_address(self.address),
            "url": url,
        }

        if not url.strip():
            msg = "Invalid empty URL"
            raise BrokenPreconditionError(msg)

        parsed_url = urlparse(url)
        if parsed_url.scheme not in ("http", "https"):
            msg = "URL provided to service registry must be a valid HTTP(S) endpoint."
            raise BrokenPreconditionError(msg)

        with log_transaction(log, "set_url", log_details):
            gas_limit = self.proxy.estimate_gas("latest", "setURL", url)
            if not gas_limit:
                msg = f"URL {url} is invalid"
                raise RaidenUnrecoverableError(msg)

            log_details["gas_limit"] = gas_limit
            transaction_hash = self.proxy.transact("setURL", gas_limit, url)
            receipt = self.client.poll(transaction_hash)
            failed_receipt = check_transaction_threw(receipt=receipt)
            if failed_receipt:
                msg = f"URL {url} is invalid"
                raise RaidenUnrecoverableError(msg)
Exemplo n.º 3
0
    def _check_channel_state_for_deposit(
        self,
        participant1,
        participant2,
        channel_identifier,
        deposit_amount,
    ):
        participant_details = self.detail_participants(
            participant1,
            participant2,
            channel_identifier,
        )

        channel_state = self._get_channel_state(
            participant1=self.node_address,
            participant2=participant2,
            channel_identifier=channel_identifier,
        )
        # Check if deposit is being made on a nonexistent channel
        if channel_state in (ChannelState.NONEXISTENT, ChannelState.REMOVED):
            raise RaidenUnrecoverableError(
                f'Channel between participant {participant1} '
                f'and {participant2} does not exist', )
        # Deposit was prohibited because the channel is settled
        elif channel_state == ChannelState.SETTLED:
            raise RaidenUnrecoverableError(
                'Deposit is not possible due to channel being settled', )
        # Deposit was prohibited because the channel is closed
        elif channel_state == ChannelState.CLOSED:
            raise RaidenRecoverableError('Channel is already closed', )
        elif participant_details.our_details.deposit < deposit_amount:
            raise RaidenUnrecoverableError('Deposit amount decreased')
Exemplo n.º 4
0
    def _check_channel_state_for_withdraw(
        self,
        participant1,
        participant2,
        channel_identifier,
        withdraw_amount,
    ):
        participant_details = self.detail_participants(
            participant1,
            participant2,
            channel_identifier,
        )

        if participant_details.our_details.withdrawn > withdraw_amount:
            raise WithdrawMismatch('Withdraw amount decreased')

        channel_state = self._get_channel_state(
            participant1=participant1,
            participant2=participant2,
            channel_identifier=channel_identifier,
        )

        if channel_state in (ChannelState.NONEXISTENT, ChannelState.REMOVED):
            raise RaidenUnrecoverableError(
                f'Channel between participant {participant1} '
                f'and {participant2} does not exist', )
        elif channel_state == ChannelState.SETTLED:
            raise RaidenUnrecoverableError(
                'A settled channel cannot be closed', )
        elif channel_state == ChannelState.CLOSED:
            raise RaidenRecoverableError('Channel is already closed', )
Exemplo n.º 5
0
    def _check_channel_state_for_settle(
        self,
        participant1: typing.Address,
        participant2: typing.Address,
        channel_identifier: typing.ChannelID,
    ) -> None:
        channel_data = self.detail_channel(participant1, participant2,
                                           channel_identifier)
        if channel_data.state == ChannelState.SETTLED:
            raise RaidenRecoverableError('Channel is already settled', )
        elif channel_data.state == ChannelState.REMOVED:
            raise RaidenRecoverableError(
                'Channel is already unlocked. It cannot be settled', )
        elif channel_data.state == ChannelState.OPENED:
            raise RaidenUnrecoverableError(
                'Channel is still open. It cannot be settled', )
        elif channel_data.state == ChannelState.CLOSED:
            if self.client.block_number() < channel_data.settle_block_number:
                raise RaidenUnrecoverableError(
                    'Channel cannot be settled before settlement window is over',
                )

            raise RaidenUnrecoverableError(
                "Settling this channel failed although the channel's current state "
                "is closed.", )
Exemplo n.º 6
0
    def handle_contract_send_channelwithdraw(
        raiden: "RaidenService", channel_withdraw_event: ContractSendChannelWithdraw
    ) -> None:
        withdraw_confirmation_data = pack_withdraw(
            canonical_identifier=channel_withdraw_event.canonical_identifier,
            participant=raiden.address,
            total_withdraw=channel_withdraw_event.total_withdraw,
            expiration_block=channel_withdraw_event.expiration,
        )
        our_signature = raiden.signer.sign(data=withdraw_confirmation_data)

        chain_state = state_from_raiden(raiden)
        confirmed_block_identifier = chain_state.block_hash
        channel_state = get_channelstate_by_canonical_identifier(
            chain_state=chain_state,
            canonical_identifier=channel_withdraw_event.canonical_identifier,
        )

        if channel_state is None:
            raise RaidenUnrecoverableError("ContractSendChannelWithdraw for non-existing channel.")

        channel_proxy = raiden.proxy_manager.payment_channel(
            channel_state=channel_state, block_identifier=confirmed_block_identifier
        )

        try:
            channel_proxy.set_total_withdraw(
                total_withdraw=channel_withdraw_event.total_withdraw,
                expiration_block=channel_withdraw_event.expiration,
                participant_signature=our_signature,
                partner_signature=channel_withdraw_event.partner_signature,
                block_identifier=channel_withdraw_event.triggered_by_block_hash,
            )
        except InsufficientEth as e:
            raise RaidenUnrecoverableError(str(e)) from e
Exemplo n.º 7
0
    def handle_contract_send_channelupdate(
            raiden: "RaidenService",
            channel_update_event: ContractSendChannelUpdateTransfer) -> None:
        balance_proof = channel_update_event.balance_proof

        if balance_proof:
            canonical_identifier = balance_proof.canonical_identifier
            chain_state = state_from_raiden(raiden)
            confirmed_block_identifier = chain_state.block_hash

            channel_state = get_channelstate_by_canonical_identifier(
                chain_state=chain_state,
                canonical_identifier=canonical_identifier)

            if channel_state is None:
                raise RaidenUnrecoverableError(
                    "ContractSendChannelUpdateTransfer for inexesting channel."
                )

            channel = raiden.proxy_manager.payment_channel(
                channel_state=channel_state,
                block_identifier=confirmed_block_identifier)

            non_closing_data = pack_signed_balance_proof(
                msg_type=MessageTypeId.BALANCE_PROOF_UPDATE,
                nonce=balance_proof.nonce,
                balance_hash=balance_proof.balance_hash,
                additional_hash=balance_proof.message_hash,
                canonical_identifier=canonical_identifier,
                partner_signature=balance_proof.signature,
            )
            our_signature = raiden.signer.sign(data=non_closing_data)

            try:
                channel.update_transfer(
                    nonce=balance_proof.nonce,
                    balance_hash=balance_proof.balance_hash,
                    additional_hash=balance_proof.message_hash,
                    partner_signature=balance_proof.signature,
                    signature=our_signature,
                    block_identifier=channel_update_event.
                    triggered_by_block_hash,
                )
            except InsufficientEth as e:
                raise RaidenUnrecoverableError(
                    f"{str(e)}\n"
                    "CAUTION: This happened when updating our side of the channel "
                    "during a channel settlement. You are in immediate danger of "
                    "losing funds in this channel.") from e
Exemplo n.º 8
0
 def deposit(self, block_identifier: BlockSpecification,
             limit_amount: TokenAmount) -> None:
     """Makes a deposit to create or extend a registration"""
     gas_limit = self.proxy.estimate_gas(block_identifier, "deposit",
                                         limit_amount)
     if not gas_limit:
         msg = "ServiceRegistry.deposit transaction fails"
         raise RaidenUnrecoverableError(msg)
     transaction_hash = self.proxy.transact("deposit", gas_limit,
                                            limit_amount)
     receipt = self.client.poll(transaction_hash)
     failed_receipt = check_transaction_threw(receipt=receipt)
     if failed_receipt:
         msg = "ServiceRegistry.deposit transaction failed"
         raise RaidenUnrecoverableError(msg)
Exemplo n.º 9
0
def channel_state_until_state_change(
    raiden: "RaidenService",
    canonical_identifier: CanonicalIdentifier,
    state_change_identifier: StateChangeID,
) -> Optional[NettingChannelState]:  # pragma: no unittest
    """ Go through WAL state changes until a certain balance hash is found. """
    assert raiden.wal, "Raiden has not been started yet"

    wal = restore_to_state_change(
        transition_function=node.state_transition,
        storage=raiden.wal.storage,
        state_change_identifier=state_change_identifier,
        node_address=raiden.address,
    )

    msg = "There is a state change, therefore the state must not be None"
    assert wal.state_manager.current_state is not None, msg

    chain_state = wal.state_manager.current_state

    channel_state = views.get_channelstate_by_canonical_identifier(
        chain_state=chain_state, canonical_identifier=canonical_identifier)

    if not channel_state:
        raise RaidenUnrecoverableError(
            f"Channel was not found before state_change {state_change_identifier}"
        )

    return channel_state
Exemplo n.º 10
0
def _get_onchain_locksroots(
    raiden: RaidenService,
    storage: SQLiteStorage,
    token_network: Dict[str, Any],
    channel: Dict[str, Any],
) -> Tuple[Locksroot, Locksroot]:
    channel_new_state_change = _find_channel_new_state_change(
        storage=storage,
        token_network_address=token_network['address'],
        channel_identifier=channel['identifier'],
    )

    if not channel_new_state_change:
        raise RaidenUnrecoverableError(
            f'Could not find the state change for channel {channel["identifier"]}, '
            f'token network address: {token_network["address"]} being created. ',
        )

    canonical_identifier = CanonicalIdentifier(
        chain_identifier=CHAIN_ID_UNSPECIFIED,
        token_network_address=to_canonical_address(token_network['address']),
        channel_identifier=int(channel['identifier']),
    )

    our_locksroot, partner_locksroot = get_onchain_locksroots(
        chain=raiden.chain,
        canonical_identifier=canonical_identifier,
        participant1=to_canonical_address(channel['our_state']['address']),
        participant2=to_canonical_address(channel['partner_state']['address']),
        block_identifier='latest',
    )
    return our_locksroot, partner_locksroot
Exemplo n.º 11
0
def _get_onchain_locksroots(
    raiden: "RaidenService",
    storage: SQLiteStorage,
    token_network: Dict[str, Any],
    channel: Dict[str, Any],
) -> Tuple[Locksroot, Locksroot]:
    channel_new_state_change = _find_channel_new_state_change(
        storage=storage,
        token_network_address=token_network["address"],
        channel_identifier=channel["identifier"],
    )

    if not channel_new_state_change:
        raise RaidenUnrecoverableError(
            f'Could not find the state change for channel {channel["identifier"]}, '
            f'token network address: {token_network["address"]} being created. '
        )

    canonical_identifier = CanonicalIdentifier(
        chain_identifier=ChainID(-1),
        token_network_address=TokenNetworkAddress(
            to_canonical_address(token_network["address"])),
        channel_identifier=ChannelID(int(channel["identifier"])),
    )

    our_locksroot, partner_locksroot = get_onchain_locksroots(
        chain=raiden.chain,
        canonical_identifier=canonical_identifier,
        participant1=to_canonical_address(channel["our_state"]["address"]),
        participant2=to_canonical_address(channel["partner_state"]["address"]),
        block_identifier="latest",
    )
    return our_locksroot, partner_locksroot
Exemplo n.º 12
0
def channel_state_until_state_change(
        raiden,
        payment_network_identifier: typing.PaymentNetworkID,
        token_address: typing.TokenAddress,
        channel_identifier: typing.ChannelID,
        state_change_identifier: int,
) -> typing.Optional[NettingChannelState]:
    """ Go through WAL state changes until a certain balance hash is found. """
    wal = restore_to_state_change(
        transition_function=node.state_transition,
        storage=raiden.wal.storage,
        state_change_identifier=state_change_identifier,
    )

    msg = 'There is a state change, therefore the state must not be None'
    assert wal.state_manager.current_state is not None, msg

    channel_state = views.get_channelstate_by_id(
        chain_state=wal.state_manager.current_state,
        payment_network_id=payment_network_identifier,
        token_address=token_address,
        channel_id=channel_identifier,
    )

    if not channel_state:
        raise RaidenUnrecoverableError(
            f"Channel was not found before state_change {pex(state_change_identifier)}",
        )

    return channel_state
Exemplo n.º 13
0
def channel_state_until_state_change(
    raiden: 'RaidenService',
    payment_network_identifier: typing.PaymentNetworkID,
    token_address: typing.TokenAddress,
    channel_identifier: typing.ChannelID,
    state_change_identifier: int,
) -> typing.Optional[NettingChannelState]:
    """ Go through WAL state changes until a certain balance hash is found. """
    # Restore state from the latest snapshot
    wal = restore_to_state_change(
        node.state_transition,
        raiden.wal.storage,
        state_change_identifier,
    )

    channel_state = views.get_channelstate_by_id(
        chain_state=wal.state_manager.current_state,
        payment_network_id=payment_network_identifier,
        token_address=token_address,
        channel_id=channel_identifier,
    )

    if not channel_state:
        raise RaidenUnrecoverableError(
            f"Channel was not found before state_change {pex(state_change_identifier)}",
        )

    return channel_state
Exemplo n.º 14
0
    def send_transaction(self,
                         to: Address,
                         startgas: int,
                         value: int = 0,
                         data: bytes = b"") -> TransactionHash:
        """ Locally sign the transaction and send it to the network. """

        with self._sent_lock:
            if self._sent:
                raise RaidenUnrecoverableError(
                    f"A transaction for this slot has been sent already! "
                    f"Reusing the nonce is a synchronization problem.")

            if to == to_canonical_address(NULL_ADDRESS_HEX):
                warnings.warn(
                    "For contract creation the empty string must be used.")

            gas_price = self._client.gas_price()

            transaction = {
                "data": data,
                "gas": startgas,
                "nonce": self.nonce,
                "value": value,
                "gasPrice": gas_price,
            }
            node_gas_price = self._client.web3.eth.gasPrice
            log.debug(
                "Calculated gas price for transaction",
                node=to_checksum_address(self._client.address),
                calculated_gas_price=gas_price,
                node_gas_price=node_gas_price,
            )

            # add the to address if not deploying a contract
            if to != b"":
                transaction["to"] = to_checksum_address(to)

            signed_txn = self._client.web3.eth.account.signTransaction(
                transaction, self._client.privkey)

            log_details = {
                "node": to_checksum_address(self._client.address),
                "nonce": transaction["nonce"],
                "gasLimit": transaction["gas"],
                "gasPrice": transaction["gasPrice"],
            }
            log.debug("send_raw_transaction called", **log_details)

            tx_hash = self._client.web3.eth.sendRawTransaction(
                signed_txn.rawTransaction)

            log.debug("send_raw_transaction returned",
                      tx_hash=encode_hex(tx_hash),
                      **log_details)

            self._sent = True

            return TransactionHash(tx_hash)
Exemplo n.º 15
0
    def start_mediated_transfer_with_secret(
        self,
        token_network_identifier: TokenNetworkID,
        amount: TokenAmount,
        target: TargetAddress,
        identifier: PaymentID,
        secret: Secret,
    ) -> AsyncResult:

        secret_hash = sha3(secret)
        if self.default_secret_registry.check_registered(secret_hash):
            raise RaidenUnrecoverableError(
                f'Attempted to initiate a locked transfer with secrethash {pex(secret_hash)}.'
                f' That secret is already registered onchain.', )

        self.start_health_check_for(Address(target))

        if identifier is None:
            identifier = create_default_identifier()

        with self.payment_identifier_lock:
            payment_status = self.targets_to_identifiers_to_statuses[
                target].get(identifier)
            if payment_status:
                payment_status_matches = payment_status.matches(
                    token_network_identifier,
                    amount,
                )
                if not payment_status_matches:
                    raise PaymentConflict(
                        'Another payment with the same id is in flight', )

                return payment_status.payment_done

            payment_status = PaymentStatus(
                payment_identifier=identifier,
                amount=amount,
                token_network_identifier=token_network_identifier,
                payment_done=AsyncResult(),
                secret=secret,
                secret_hash=secret_hash,
            )
            self.targets_to_identifiers_to_statuses[target][
                identifier] = payment_status

        init_initiator_statechange = initiator_init(
            raiden=self,
            transfer_identifier=identifier,
            transfer_amount=amount,
            transfer_secret=secret,
            token_network_identifier=token_network_identifier,
            target_address=target,
        )

        # Dispatch the state change even if there are no routes to create the
        # wal entry.
        self.handle_state_change(init_initiator_statechange)

        return payment_status.payment_done
Exemplo n.º 16
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.º 17
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)

        gas_limit = self.proxy.estimate_gas(
            'unlock',
            channel_identifier,
            self.node_address,
            partner,
            leaves_packed,
        )
        gas_limit = safe_gas_limit(gas_limit, UNLOCK_TX_GAS_LIMIT)

        transaction_hash = self.proxy.transact(
            'unlock',
            gas_limit,
            channel_identifier,
            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(
                participant1=self.node_address,
                participant2=partner,
                channel_identifier=channel_identifier,
            )

            if channel_settled is False:
                log.critical('unlock failed. Channel is not in a settled state', **log_details)
                raise RaidenUnrecoverableError(
                    '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.º 18
0
    def approve(self, allowed_address: Address, allowance: TokenAmount):
        """ Aprove `allowed_address` to transfer up to `deposit` amount of token.

        Note:

            For channel deposit please use the channel proxy, since it does
            additional validations.
        """

        log_details = {
            'node': pex(self.node_address),
            'contract': pex(self.address),
            'allowed_address': pex(allowed_address),
            'allowance': allowance,
        }

        checking_block = self.client.get_checking_block()
        error_prefix = 'Call to approve will fail'
        gas_limit = self.proxy.estimate_gas(
            checking_block,
            'approve',
            to_checksum_address(allowed_address),
            allowance,
        )

        if gas_limit:
            error_prefix = 'Call to approve failed'
            log.debug('approve called', **log_details)
            transaction_hash = self.proxy.transact(
                'approve',
                safe_gas_limit(gas_limit),
                to_checksum_address(allowed_address),
                allowance,
            )

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

        transaction_executed = gas_limit is not None
        if not transaction_executed or receipt_or_none:
            if transaction_executed:
                block = receipt_or_none['blockNumber']
            else:
                block = checking_block

            self.proxy.jsonrpc_client.check_for_insufficient_eth(
                transaction_name='approve',
                transaction_executed=transaction_executed,
                required_gas=GAS_REQUIRED_FOR_APPROVE,
                block_identifier=block,
            )

            msg = self._check_why_approved_failed(allowance, block)
            error_msg = f'{error_prefix}. {msg}'
            log.critical(error_msg, **log_details)
            raise RaidenUnrecoverableError(error_msg)

        log.info('approve successful', **log_details)
Exemplo n.º 19
0
    def deposit(self, block_identifier: BlockIdentifier,
                limit_amount: TokenAmount) -> None:
        """Makes a deposit to create or extend a registration"""
        extra_log_details = {"given_block_identifier": block_identifier}
        estimated_transaction = self.client.estimate_gas(
            self.proxy, "deposit", extra_log_details, limit_amount)

        if estimated_transaction is None:
            msg = "ServiceRegistry.deposit transaction fails"
            raise RaidenUnrecoverableError(msg)

        transaction_sent = self.client.transact(estimated_transaction)
        transaction_mined = self.client.poll_transaction(transaction_sent)

        if not was_transaction_successfully_mined(transaction_mined):
            msg = "ServiceRegistry.deposit transaction failed"
            raise RaidenUnrecoverableError(msg)
Exemplo n.º 20
0
    def _check_channel_state_for_close(self, participant1, participant2,
                                       channel_identifier):
        channel_state = self._get_channel_state(
            participant1=participant1,
            participant2=participant2,
            channel_identifier=channel_identifier,
        )

        if channel_state in (ChannelState.NONEXISTENT, ChannelState.REMOVED):
            raise RaidenUnrecoverableError(
                f'Channel between participant {participant1} '
                f'and {participant2} does not exist', )
        elif channel_state == ChannelState.SETTLED:
            raise RaidenUnrecoverableError(
                'A settled channel cannot be closed', )
        elif channel_state == ChannelState.CLOSED:
            raise RaidenRecoverableError('Channel is already closed', )
Exemplo n.º 21
0
    def approve(self, allowed_address: Address, allowance: TokenAmount):
        """ Aprove `allowed_address` to transfer up to `deposit` amount of token.

        Note:

            For channel deposit please use the channel proxy, since it does
            additional validations.
        """
        # 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),
            "allowed_address": pex(allowed_address),
            "allowance": allowance,
        }

        checking_block = self.client.get_checking_block()
        error_prefix = "Call to approve will fail"
        gas_limit = self.proxy.estimate_gas(
            checking_block, "approve", to_checksum_address(allowed_address), allowance
        )

        if gas_limit:
            error_prefix = "Call to approve failed"
            log.debug("approve called", **log_details)
            transaction_hash = self.proxy.transact(
                "approve",
                safe_gas_limit(gas_limit),
                to_checksum_address(allowed_address),
                allowance,
            )

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

        transaction_executed = gas_limit is not None
        if not transaction_executed or receipt_or_none:
            if transaction_executed:
                block = receipt_or_none["blockNumber"]
            else:
                block = checking_block

            self.proxy.jsonrpc_client.check_for_insufficient_eth(
                address=self.node_address,
                transaction_name="approve",
                transaction_executed=transaction_executed,
                required_gas=GAS_REQUIRED_FOR_APPROVE,
                block_identifier=block,
            )

            msg = self._check_why_approved_failed(allowance, block)
            error_msg = f"{error_prefix}. {msg}"
            log.critical(error_msg, **log_details)
            raise RaidenUnrecoverableError(error_msg)

        log.info("approve successful", **log_details)
Exemplo n.º 22
0
 def handle_contract_send_secretreveal(
     raiden: "RaidenService", channel_reveal_secret_event: ContractSendSecretReveal
 ) -> None:  # pragma: no unittest
     try:
         raiden.default_secret_registry.register_secret(
             secret=channel_reveal_secret_event.secret
         )
     except InsufficientEth as e:
         raise RaidenUnrecoverableError(str(e)) from e
Exemplo n.º 23
0
def raise_on_call_returned_empty(
        given_block_identifier: BlockIdentifier) -> NoReturn:
    """Format a message and raise RaidenUnrecoverableError."""
    # We know that the given address has code because this is checked
    # in the constructor
    msg = (f"Either the given address is for a different smart contract, "
           f"or the contract was not yet deployed at the block "
           f"{format_block_id(given_block_identifier)}. Either way this call "
           f"should never have happened.")
    raise RaidenUnrecoverableError(msg)
Exemplo n.º 24
0
    def _check_channel_state_for_settle(self, participant1, participant2,
                                        channel_identifier):
        channel_data = self.detail_channel(participant1, participant2,
                                           channel_identifier)
        if channel_data.state == ChannelState.SETTLED:
            raise RaidenRecoverableError('Channel is already settled', )
        elif channel_data.state == ChannelState.REMOVED:
            raise RaidenRecoverableError(
                'Channel is already unlocked. It cannot be settled', )
        elif channel_data.state == ChannelState.OPENED:
            raise RaidenUnrecoverableError(
                'Channel is still open. It cannot be settled', )
        elif channel_data.state == ChannelState.CLOSED:
            if self.client.block_number() < channel_data.settle_block_number:
                raise RaidenUnrecoverableError(
                    'Channel cannot be settled before settlement window is over',
                )

            raise RaidenRecoverableError(
                'Channel cannot be settled before closing', )
Exemplo n.º 25
0
    def handle_contract_send_channelclose(
        raiden: "RaidenService",
        chain_state: ChainState,
        channel_close_event: ContractSendChannelClose,
    ) -> None:
        balance_proof = channel_close_event.balance_proof

        if balance_proof:
            nonce = balance_proof.nonce
            balance_hash = balance_proof.balance_hash
            signature_in_proof = balance_proof.signature
            message_hash = balance_proof.message_hash
            canonical_identifier = balance_proof.canonical_identifier

        else:
            nonce = Nonce(0)
            balance_hash = EMPTY_BALANCE_HASH
            signature_in_proof = EMPTY_SIGNATURE
            message_hash = EMPTY_MESSAGE_HASH
            canonical_identifier = channel_close_event.canonical_identifier

        closing_data = pack_signed_balance_proof(
            msg_type=MessageTypeId.BALANCE_PROOF,
            nonce=nonce,
            balance_hash=balance_hash,
            additional_hash=message_hash,
            canonical_identifier=canonical_identifier,
            partner_signature=signature_in_proof,
        )

        our_signature = raiden.signer.sign(data=closing_data)

        confirmed_block_identifier = state_from_raiden(raiden).block_hash
        channel_state = get_channelstate_by_canonical_identifier(
            chain_state=chain_state,
            canonical_identifier=channel_close_event.canonical_identifier)

        if channel_state is None:
            raise RaidenUnrecoverableError(
                "ContractSendChannelClose for inexesting channel.")

        channel_proxy = raiden.proxy_manager.payment_channel(
            channel_state=channel_state,
            block_identifier=confirmed_block_identifier)

        channel_proxy.close(
            nonce=nonce,
            balance_hash=balance_hash,
            additional_hash=message_hash,
            non_closing_signature=signature_in_proof,
            closing_signature=our_signature,
            block_identifier=channel_close_event.triggered_by_block_hash,
        )
Exemplo n.º 26
0
def raise_on_call_returned_empty(
        given_block_identifier: BlockSpecification) -> NoReturn:
    """Format a message and raise RaidenUnrecoverableError."""
    # We know that the given address has code because this is checked
    # in the constructor
    if isinstance(given_block_identifier, T_BlockHash):
        given_block_identifier = to_hex(given_block_identifier)

    msg = (f"Either the given address is for a different smart contract, "
           f"or the contract was not yet deployed at the block "
           f"{given_block_identifier}. Either way this call should never "
           f"happened.")
    raise RaidenUnrecoverableError(msg)
Exemplo n.º 27
0
    def transact(
        self, function_name: str, startgas: int, *args: Any, **kwargs: Any
    ) -> TransactionHash:
        data = ContractProxy.get_transaction_data(
            abi=self.contract.abi, function_name=function_name, args=args, kwargs=kwargs
        )

        slot = self.rpc_client.get_next_transaction()
        try:
            tx_hash = slot.send_transaction(
                to=self.contract.address,
                startgas=startgas,
                value=kwargs.pop("value", 0),
                data=decode_hex(data),
            )
        except ValueError as e:
            action = inspect_client_error(e, self.rpc_client.eth_node)
            if action == ClientErrorInspectResult.INSUFFICIENT_FUNDS:
                raise InsufficientEth(
                    "Transaction failed due to insufficient ETH balance. "
                    "Please top up your ETH account."
                )
            elif action == ClientErrorInspectResult.TRANSACTION_UNDERPRICED:
                raise ReplacementTransactionUnderpriced(
                    "Transaction was rejected. This is potentially "
                    "caused by the reuse of the previous transaction "
                    "nonce as well as paying an amount of gas less than or "
                    "equal to the previous transaction's gas amount"
                )
            elif action in THE_NONCE_WAS_REUSED:
                # XXX: Add logic to check that it is the same transaction
                # (instead of relying on the error message), and instead of
                # raising an unrecoverable error proceed as normal with the
                # polling.
                #
                # This was previously done, but removed by #4909, and for it to
                # be finished #2088 has to be implemented.
                raise EthereumNonceTooLow(
                    "Transaction rejected because the nonce has been already mined."
                )

            raise RaidenUnrecoverableError(
                f"Unexpected error in underlying Ethereum node: {str(e)}"
            )

        return tx_hash
Exemplo n.º 28
0
def join_broadcast_room(client: GMatrixClient,
                        broadcast_room_alias: str) -> Room:
    """ Join the public broadcast through the alias `broadcast_room_alias`.

    When a new Matrix instance is deployed the broadcast room _must_ be created
    and aliased, Raiden will not use a server that does not have the discovery
    room properly set. Requiring the setup of the broadcast alias as part of
    the server setup fixes a serious race condition where multiple discovery
    rooms are created, which would break the presence checking.
    See: https://github.com/raiden-network/raiden-transport/issues/46
    """
    try:
        return client.join_room(broadcast_room_alias)
    except MatrixRequestError:
        raise RaidenUnrecoverableError(
            f"Could not join broadcast room {broadcast_room_alias}. "
            f"Make sure the Matrix server you're trying to connect to uses the recommended server "
            f"setup, esp. the server-side broadcast room creation. "
            f"See https://github.com/raiden-network/raiden-transport.")
Exemplo n.º 29
0
    def kill_offender(hub: Hub) -> None:
        if greenlet_tracer.did_block_hub(hub):
            active_greenlet = greenlet_tracer.active_greenlet

            msg = ""
            if monitor_thread._tracer.active_greenlet != active_greenlet:
                msg = (
                    f"Mismatch values for the active_greenlet among the "
                    f"monitor_thread and deubgging tracer, this either means "
                    f"there is a bug in the trace chain (the wrong values are "
                    f"forwarded), or that one of the trace functions was wrongly "
                    f"uninstalled. Active greenlets "
                    f"monitor_thread={monitor_thread._tracer.active_greenlet} "
                    f"debug_tracer={active_greenlet}.")

            hub.loop.run_callback(lambda: active_greenlet.throw(
                RaidenUnrecoverableError(
                    f"A greenlet used the CPU for longer than "
                    f"{gevent.config.max_blocking_time} seconds, killing it.{msg}"
                )))
Exemplo n.º 30
0
def test_run_error_reporting(cli_runner, monkeypatch):
    caught_exceptions = {
        APIServerPortInUseError(): ReturnCode.PORT_ALREADY_IN_USE,
        ConfigurationError(): ReturnCode.RAIDEN_CONFIGURATION_ERROR,
        ConnectTimeout(): ReturnCode.GENERIC_COMMUNICATION_ERROR,
        ConnectionError(): ReturnCode.GENERIC_COMMUNICATION_ERROR,
        EthereumNonceTooLow(): ReturnCode.ETH_ACCOUNT_ERROR,
        EthNodeInterfaceError(): ReturnCode.ETH_INTERFACE_ERROR,
        KeystoreAuthenticationError(): ReturnCode.ETH_ACCOUNT_ERROR,
        KeystoreFileNotFound(): ReturnCode.ETH_ACCOUNT_ERROR,
        RaidenUnrecoverableError(): ReturnCode.FATAL,
        ReplacementTransactionUnderpriced(): ReturnCode.ETH_ACCOUNT_ERROR,
        RequestsConnectionError(): ReturnCode.GENERIC_COMMUNICATION_ERROR,
        Exception(): ReturnCode.FATAL,
    }

    for exception, code in caught_exceptions.items():
        monkeypatch.setattr(cli, "run_services", mock_raises(exception))
        result = cli_runner(cli.run, "--accept-disclaimer")
        assert result.exception.code == code