Exemplo n.º 1
0
    def _check_why_deposit_failed(
        self,
        token: Token,
        amount_to_deposit: TokenAmount,
        total_deposit: TokenAmount,
        block_identifier: BlockSpecification,
    ) -> Tuple[Union[RaidenRecoverableError, RaidenUnrecoverableError], str, ]:
        error_type = RaidenUnrecoverableError
        msg = ''
        latest_deposit = self.get_total_deposit(
            address=self.node_address,
            block_identifier=block_identifier,
        )

        allowance = token.allowance(
            owner=self.node_address,
            spender=Address(self.address),
            block_identifier=block_identifier,
        )
        if allowance < amount_to_deposit:
            msg = ('The allowance is insufficient. Check concurrent deposits '
                   'for the same token network but different proxies.')
        elif token.balance_of(self.node_address,
                              block_identifier) < amount_to_deposit:
            msg = 'The address doesnt have enough tokens'
        elif latest_deposit < total_deposit:
            msg = 'Deposit amount did not increase after deposit transaction'
        else:
            msg = 'Deposit failed of unknown reason'

        return error_type, msg
Exemplo n.º 2
0
def test_token(
        deploy_client,
        token_proxy,
        private_keys,
        web3,
        contract_manager,
):
    privkey = private_keys[1]
    address = privatekey_to_address(privkey)
    address = to_canonical_address(address)
    other_client = JSONRPCClient(web3, privkey)
    other_token_proxy = Token(
        jsonrpc_client=other_client,
        token_address=to_canonical_address(token_proxy.proxy.contract.address),
        contract_manager=contract_manager,
    )

    # send some funds from deployer to generated address
    transfer_funds = 100
    token_proxy.transfer(address, transfer_funds)
    assert transfer_funds == token_proxy.balance_of(address)
    allow_funds = 100
    token_proxy.approve(address, allow_funds)
    assert allow_funds == token_proxy.proxy.contract.functions.allowance(
        to_checksum_address(deploy_client.address),
        to_checksum_address(address),
    ).call(block_identifier='latest')
    other_token_proxy.transfer(deploy_client.address, transfer_funds)
    assert token_proxy.balance_of(address) == 0
Exemplo n.º 3
0
    def _check_why_deposit_failed(
        self,
        token: Token,
        amount_to_deposit: TokenAmount,
        total_deposit: TokenAmount,
        block_identifier: BlockSpecification,
    ) -> str:
        msg = ""
        latest_deposit = self.get_total_deposit(
            address=self.node_address, block_identifier=block_identifier)

        allowance = token.allowance(
            owner=self.node_address,
            spender=Address(self.address),
            block_identifier=block_identifier,
        )
        if allowance < amount_to_deposit:
            msg = ("The allowance is insufficient. Check concurrent deposits "
                   "for the same token network but different proxies.")
        elif token.balance_of(self.node_address,
                              block_identifier) < amount_to_deposit:
            msg = "The address doesnt have enough tokens"
        elif latest_deposit < total_deposit:
            msg = "Deposit amount did not increase after deposit transaction"
        else:
            msg = "Deposit failed of unknown reason"

        return msg
Exemplo n.º 4
0
def test_token(deploy_client, token_proxy, private_keys, web3,
               contract_manager):
    privkey = private_keys[1]
    address = privatekey_to_address(privkey)
    address = to_canonical_address(address)
    other_client = JSONRPCClient(web3, privkey)
    other_token_proxy = Token(
        jsonrpc_client=other_client,
        token_address=to_canonical_address(token_proxy.proxy.address),
        contract_manager=contract_manager,
        block_identifier=BLOCK_ID_LATEST,
    )

    # send some funds from deployer to generated address
    transfer_funds = 100
    transaction_hash = token_proxy.transfer(address, transfer_funds)
    assert is_tx_hash_bytes(transaction_hash)
    assert transfer_funds == token_proxy.balance_of(address)
    allow_funds = 100

    transaction_hash = token_proxy.approve(address, allow_funds)
    assert is_tx_hash_bytes(transaction_hash)
    assert allow_funds == token_proxy.proxy.functions.allowance(
        deploy_client.address, address).call(block_identifier=BLOCK_ID_LATEST)
    other_token_proxy.transfer(deploy_client.address, transfer_funds)
    assert token_proxy.balance_of(address) == 0
Exemplo n.º 5
0
    def deposit(self, amount):
        """ Deposit amount token in the channel.

        Raises:
            AddressWithoutCode: If the channel was settled prior to the call.
            RuntimeError: If the netting channel token address is empty.
        """
        if not isinstance(amount, (int, long)):
            raise ValueError('amount needs to be an integral number.')

        token_address = self.token_address()

        token = Token(
            self.client,
            token_address,
            self.startgas,
            self.gasprice,
            self.poll_timeout,
        )
        current_balance = token.balance_of(self.node_address)

        if current_balance < amount:
            raise ValueError(
                'deposit [{}] cant be larger than the available balance [{}].'.
                format(
                    amount,
                    current_balance,
                ))

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

        transaction_hash = estimate_and_transact(
            self.proxy,
            'deposit',
            self.startgas,
            self.gasprice,
            amount,
        )

        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('deposit failed', contract=pex(self.address))
            self._check_exists()
            raise TransactionThrew('Deposit', receipt_or_none)

        if log.isEnabledFor(logging.INFO):
            log.info('deposit sucessfull',
                     contract=pex(self.address),
                     amount=amount)
Exemplo n.º 6
0
    def _deposit_preconditions(
        self,
        total_deposit: TokenAmount,
        beneficiary: Address,
        token: Token,
        block_identifier: BlockSpecification,
    ) -> Tuple[TokenAmount, Dict]:
        if not isinstance(total_deposit, int):
            raise ValueError('total_deposit needs to be an integer number.')

        previous_total_deposit = self.get_total_deposit(
            address=beneficiary,
            block_identifier=block_identifier,
        )
        amount_to_deposit = total_deposit - previous_total_deposit

        log_details = {
            'user_deposit_address': pex(self.address),
            'node': pex(self.node_address),
            'beneficiary': pex(beneficiary),
            'new_total_deposit': total_deposit,
            'previous_total_deposit': previous_total_deposit,
        }

        if total_deposit <= previous_total_deposit:
            msg = (
                f'Current total deposit {previous_total_deposit} is already larger '
                f'than the requested total deposit amount {total_deposit}')
            log.info('deposit failed', reason=msg, **log_details)
            raise DepositMismatch(msg)

        current_balance = token.balance_of(
            address=self.node_address,
            block_identifier=block_identifier,
        )
        if current_balance < amount_to_deposit:
            msg = (
                f'new_total_deposit - previous_total_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('deposit failed', reason=msg, **log_details)
            raise DepositMismatch(msg)

        token.approve(
            allowed_address=Address(self.address),
            allowance=amount_to_deposit,
        )

        return amount_to_deposit, log_details
Exemplo n.º 7
0
    def _deposit_preconditions(
        self,
        beneficiary: Address,
        total_deposit: TokenAmount,
        given_block_identifier: BlockIdentifier,
        token: Token,
    ) -> Tuple[TokenAmount, TokenAmount]:
        try:
            previous_total_deposit = self.get_total_deposit(
                address=beneficiary, block_identifier=given_block_identifier
            )
            current_balance = token.balance_of(
                address=self.node_address, block_identifier=given_block_identifier
            )
            whole_balance = self.whole_balance(block_identifier=given_block_identifier)
            whole_balance_limit = self.whole_balance_limit(block_identifier=given_block_identifier)
        except ValueError:
            # If 'given_block_identifier' has been pruned, we cannot perform the
            # precondition checks but must still set the amount_to_deposit to a
            # reasonable value.
            previous_total_deposit = self.get_total_deposit(
                address=beneficiary, block_identifier=self.client.get_checking_block()
            )
            amount_to_deposit = TokenAmount(total_deposit - previous_total_deposit)
        except BadFunctionCallOutput:
            raise_on_call_returned_empty(given_block_identifier)
        else:
            amount_to_deposit = TokenAmount(total_deposit - previous_total_deposit)

            if whole_balance + amount_to_deposit > UINT256_MAX:
                msg = (
                    f"Current whole balance is {whole_balance}. "
                    f"The new deposit of {amount_to_deposit} would lead to an overflow."
                )
                raise BrokenPreconditionError(msg)

            if whole_balance + amount_to_deposit > whole_balance_limit:
                msg = (
                    f"Current whole balance is {whole_balance}. "
                    f"With the new deposit of {amount_to_deposit}, the deposit "
                    f"limit of {whole_balance_limit} would be exceeded."
                )
                raise BrokenPreconditionError(msg)

            if total_deposit <= previous_total_deposit:
                msg = (
                    f"Current total deposit {previous_total_deposit} is already larger "
                    f"than the requested total deposit amount {total_deposit}"
                )
                raise BrokenPreconditionError(msg)

            if current_balance < amount_to_deposit:
                msg = (
                    f"new_total_deposit - previous_total_deposit = {amount_to_deposit} "
                    f"can not be larger than the available balance {current_balance}, "
                    f"for token at address {to_checksum_address(token.address)}"
                )
                raise BrokenPreconditionError(msg)

        return previous_total_deposit, amount_to_deposit
Exemplo n.º 8
0
    def _withdraw_check_result(
        self,
        transaction_sent: Optional[TransactionSent],
        amount_to_withdraw: TokenAmount,
        token: Token,
        previous_token_balance: TokenAmount,
    ) -> None:
        if transaction_sent is None:
            failed_at = self.client.get_block(BLOCK_ID_LATEST)
            failed_at_blocknumber = failed_at["number"]

            self.client.check_for_insufficient_eth(
                transaction_name="withdraw",
                transaction_executed=False,
                required_gas=self.gas_measurements["UserDeposit.withdraw"],
                block_identifier=failed_at_blocknumber,
            )
            raise RaidenRecoverableError(
                "Withdraw transaction failed to be sent for an unknown reason."
            )

        transaction_mined = self.client.poll_transaction(transaction_sent)

        if not was_transaction_successfully_mined(transaction_mined):
            failed_at_blocknumber = BlockNumber(transaction_mined.receipt["blockNumber"])

            withdraw_plan = self.get_withdraw_plan(
                withdrawer_address=self.node_address, block_identifier=failed_at_blocknumber
            )
            whole_balance = self.whole_balance(block_identifier=failed_at_blocknumber)

            if amount_to_withdraw > withdraw_plan.withdraw_amount:
                raise RaidenRecoverableError(
                    f"Couldn't withdraw {amount_to_withdraw}, "
                    f"current withdraw plan only allows for {withdraw_plan.withdraw_amount}."
                )

            if withdraw_plan.withdraw_block > failed_at_blocknumber:
                raise RaidenRecoverableError(
                    f"Couldn't withdraw at block {failed_at_blocknumber}. "
                    f"The current withdraw plan requires block number "
                    f"{withdraw_plan.withdraw_block}."
                )

            if whole_balance - amount_to_withdraw < 0:
                raise RaidenRecoverableError(
                    f"The current whole balance is {whole_balance}. "
                    f"The withdraw of {amount_to_withdraw} would have lead to an underflow."
                )

            current_token_balance = TokenAmount(
                token.balance_of(self.node_address, block_identifier=failed_at_blocknumber)
            )
            # FIXME: This seems fishy. The token balance could have an unexpected value for
            #        unrelated reasons (e.g. concurrent token transfers via transferFrom).
            if current_token_balance != previous_token_balance + amount_to_withdraw:
                raise RaidenRecoverableError("Token transfer during withdraw failed.")

            raise RaidenRecoverableError("Withdraw failed for an unknown reason.")
Exemplo n.º 9
0
    def _deposit_preconditions(
        self,
        total_deposit: TokenAmount,
        beneficiary: Address,
        token: Token,
        block_identifier: BlockSpecification,
    ) -> Tuple[TokenAmount, Dict]:
        if not isinstance(total_deposit, int):
            raise ValueError("total_deposit needs to be an integer number.")

        previous_total_deposit = self.get_total_deposit(
            address=beneficiary, block_identifier=block_identifier
        )
        amount_to_deposit = TokenAmount(total_deposit - previous_total_deposit)

        log_details = {
            "user_deposit_address": pex(self.address),
            "node": pex(self.node_address),
            "beneficiary": pex(beneficiary),
            "new_total_deposit": total_deposit,
            "previous_total_deposit": previous_total_deposit,
        }

        if total_deposit <= previous_total_deposit:
            msg = (
                f"Current total deposit {previous_total_deposit} is already larger "
                f"than the requested total deposit amount {total_deposit}"
            )
            log.info("deposit failed", reason=msg, **log_details)
            raise DepositMismatch(msg)

        current_balance = token.balance_of(
            address=self.node_address, block_identifier=block_identifier
        )
        if current_balance < amount_to_deposit:
            msg = (
                f"new_total_deposit - previous_total_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("deposit failed", reason=msg, **log_details)
            raise DepositMismatch(msg)

        token.approve(allowed_address=Address(self.address), allowance=amount_to_deposit)

        return amount_to_deposit, log_details
Exemplo n.º 10
0
    def token(self, token_address: TokenAddress) -> Token:
        """ Return a proxy to interact with a token. """
        if not is_binary_address(token_address):
            raise ValueError("token_address must be a valid address")

        with self._token_creation_lock:
            if token_address not in self.address_to_token:
                self.address_to_token[token_address] = Token(
                    jsonrpc_client=self.client,
                    token_address=token_address,
                    contract_manager=self.contract_manager,
                )

        return self.address_to_token[token_address]
Exemplo n.º 11
0
def deploy_token_and_return_proxy(deploy_client, contract_manager):
    token_contract = deploy_token(
        deploy_client=deploy_client,
        contract_manager=contract_manager,
        initial_amount=10000,
        decimals=0,
        token_name="TKN",
        token_symbol="TKN",
    )

    return Token(
        jsonrpc_client=deploy_client,
        token_address=to_canonical_address(token_contract.contract.address),
        contract_manager=contract_manager,
    )
Exemplo n.º 12
0
def deploy_token_and_return_proxy(deploy_client: JSONRPCClient,
                                  contract_manager: ContractManager,
                                  token_contract_name: str) -> Token:
    token_contract = deploy_token(
        deploy_client=deploy_client,
        contract_manager=contract_manager,
        initial_amount=TokenAmount(1000 * 10**18),
        decimals=0,
        token_name="TKN",
        token_symbol="TKN",
        token_contract_name=token_contract_name,
    )

    return Token(
        jsonrpc_client=deploy_client,
        token_address=TokenAddress(token_contract.contract_address),
        contract_manager=contract_manager,
    )
Exemplo n.º 13
0
def deploy_smart_contract_bundle_concurrently(
    deploy_client: JSONRPCClient,
    contract_manager: ContractManager,
    proxy_manager: ProxyManager,
    chain_id: ChainID,
    environment_type: Environment,
    max_token_networks: int,
    number_of_tokens: int,
    private_keys: List[PrivateKey],
    register_tokens: bool,
    settle_timeout_max: int,
    settle_timeout_min: int,
    token_amount: TokenAmount,
    token_contract_name: str,
) -> FixtureSmartContracts:

    greenlets: Set[Greenlet] = set()
    participants = [privatekey_to_address(key) for key in private_keys]

    secret_registry_deploy_greenlet = gevent.spawn(
        deploy_secret_registry,
        deploy_client=deploy_client,
        contract_manager=contract_manager,
        proxy_manager=proxy_manager,
    )
    greenlets.add(secret_registry_deploy_greenlet)

    token_network_registry_deploy_greenlet = gevent.spawn(
        deploy_token_network_registry,
        secret_registry_deploy_result=secret_registry_deploy_greenlet.get,
        deploy_client=deploy_client,
        contract_manager=contract_manager,
        proxy_manager=proxy_manager,
        chain_id=chain_id,
        settle_timeout_min=settle_timeout_min,
        settle_timeout_max=settle_timeout_max,
        max_token_networks=max_token_networks,
    )
    greenlets.add(token_network_registry_deploy_greenlet)

    # ERC20 tokens used for token networks
    token_contracts_greenlets = list()
    for _ in range(number_of_tokens):
        token_deploy_greenlet = gevent.spawn(
            deploy_token,
            deploy_client=deploy_client,
            contract_manager=contract_manager,
            initial_amount=token_amount,
            decimals=2,
            token_name="raiden",
            token_symbol="Rd",
            token_contract_name=token_contract_name,
        )
        greenlets.add(token_deploy_greenlet)
        token_contracts_greenlets.append(token_deploy_greenlet)

        # Fund the nodes
        for transfer_to in participants:
            fund_node_greenlet = gevent.spawn(
                fund_node,
                token_result=token_deploy_greenlet.get,
                proxy_manager=proxy_manager,
                to_address=transfer_to,
                amount=TokenAmount(token_amount // len(participants)),
            )
            greenlets.add(fund_node_greenlet)

        if register_tokens:
            register_grenlet = gevent.spawn(
                register_token,
                token_deploy_result=token_deploy_greenlet.get,
                token_network_registry_deploy_result=
                token_network_registry_deploy_greenlet.get,
            )
            greenlets.add(register_grenlet)

        del token_deploy_greenlet

    if environment_type == Environment.DEVELOPMENT:
        utility_token_deploy_greenlet = gevent.spawn(
            deploy_token,
            deploy_client=deploy_client,
            contract_manager=contract_manager,
            initial_amount=TokenAmount(1000 * 10**18),
            decimals=0,
            token_name="TKN",
            token_symbol="TKN",
            token_contract_name=token_contract_name,
        )
        greenlets.add(utility_token_deploy_greenlet)

        if register_tokens:
            register_utility_token_grenlet = gevent.spawn(
                register_token,
                token_deploy_result=utility_token_deploy_greenlet.get,
                token_network_registry_deploy_result=
                token_network_registry_deploy_greenlet.get,
            )
            greenlets.add(register_utility_token_grenlet)

        service_registry_deploy_greenlet = gevent.spawn(
            deploy_service_registry,
            token_deploy_result=utility_token_deploy_greenlet.get,
            deploy_client=deploy_client,
            contract_manager=contract_manager,
            proxy_manager=proxy_manager,
        )
        greenlets.add(service_registry_deploy_greenlet)

        user_deposit_deploy_greenlet = gevent.spawn(
            deploy_user_deposit,
            token_deploy_result=utility_token_deploy_greenlet.get,
            deploy_client=deploy_client,
            contract_manager=contract_manager,
            proxy_manager=proxy_manager,
        )
        greenlets.add(user_deposit_deploy_greenlet)

        one_to_n_deploy_greenlet = gevent.spawn(
            deploy_one_to_n,
            user_deposit_deploy_result=user_deposit_deploy_greenlet.get,
            service_registry_deploy_result=service_registry_deploy_greenlet.
            get,
            deploy_client=deploy_client,
            contract_manager=contract_manager,
            proxy_manager=proxy_manager,
            chain_id=chain_id,
        )
        greenlets.add(one_to_n_deploy_greenlet)

        monitoring_service_deploy_greenlet = gevent.spawn(
            deploy_monitoring_service,
            token_deploy_result=utility_token_deploy_greenlet.get,
            user_deposit_deploy_result=user_deposit_deploy_greenlet.get,
            service_registry_deploy_result=service_registry_deploy_greenlet.
            get,
            token_network_registry_deploy_result=
            token_network_registry_deploy_greenlet.get,
            deploy_client=deploy_client,
            contract_manager=contract_manager,
            proxy_manager=proxy_manager,
        )
        greenlets.add(monitoring_service_deploy_greenlet)

        for transfer_to in participants:
            transfer_grenlet = gevent.spawn(
                transfer_user_deposit_tokens,
                user_deposit_deploy_result=user_deposit_deploy_greenlet.get,
                transfer_to=transfer_to,
            )
            greenlets.add(transfer_grenlet)

    gevent.joinall(greenlets, raise_error=True)

    secret_registry_proxy = secret_registry_deploy_greenlet.get()
    token_network_registry_proxy = token_network_registry_deploy_greenlet.get()
    token_contracts = [
        token_deploy_greenlet.get()
        for token_deploy_greenlet in token_contracts_greenlets
    ]

    services_smart_contracts: Optional[ServicesSmartContracts] = None
    if environment_type == Environment.DEVELOPMENT:
        one_to_n_proxy = one_to_n_deploy_greenlet.get()
        user_deposit_proxy = user_deposit_deploy_greenlet.get()
        service_registry_proxy = service_registry_deploy_greenlet.get()
        utility_token_contract = utility_token_deploy_greenlet.get()
        monitoring_service_proxy = monitoring_service_deploy_greenlet.get()

        utility_token_proxy = Token(deploy_client,
                                    utility_token_contract.address,
                                    contract_manager, BLOCK_ID_LATEST)

        utility_token_network_proxy: Optional[TokenNetwork] = None
        if register_tokens:
            utility_token_network_address = register_utility_token_grenlet.get(
            )
            utility_token_network_proxy = proxy_manager.token_network(
                utility_token_network_address, BLOCK_ID_LATEST)

        services_smart_contracts = ServicesSmartContracts(
            utility_token_proxy=utility_token_proxy,
            utility_token_network_proxy=utility_token_network_proxy,
            one_to_n_proxy=one_to_n_proxy,
            user_deposit_proxy=user_deposit_proxy,
            service_registry_proxy=service_registry_proxy,
            monitoring_service=monitoring_service_proxy,
        )

    return FixtureSmartContracts(
        secret_registry_proxy=secret_registry_proxy,
        token_network_registry_proxy=token_network_registry_proxy,
        token_contracts=token_contracts,
        services_smart_contracts=services_smart_contracts,
    )
Exemplo n.º 14
0
def test_payment_channel_proxy_basics(
    token_network_registry_address: TokenNetworkRegistryAddress,
    token_network_proxy: TokenNetwork,
    token_proxy: Token,
    chain_id: ChainID,
    private_keys: List[PrivateKey],
    web3: Web3,
    contract_manager: ContractManager,
    reveal_timeout: BlockTimeout,
) -> None:
    token_network_address = token_network_proxy.address
    partner = privatekey_to_address(private_keys[0])

    rpc_client = JSONRPCClient(web3, private_keys[1])
    proxy_manager = ProxyManager(
        rpc_client=rpc_client,
        contract_manager=contract_manager,
        metadata=ProxyManagerMetadata(
            token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER,
            filters_start_at=GENESIS_BLOCK_NUMBER,
        ),
    )
    token_network_proxy = proxy_manager.token_network(
        address=token_network_address, block_identifier=BLOCK_ID_LATEST
    )
    start_block = web3.eth.blockNumber

    channel_details = token_network_proxy.new_netting_channel(
        partner=partner,
        settle_timeout=TEST_SETTLE_TIMEOUT_MIN,
        given_block_identifier=BLOCK_ID_LATEST,
    )
    channel_identifier = channel_details.channel_identifier
    assert channel_identifier is not None

    channel_state = NettingChannelState(
        canonical_identifier=CanonicalIdentifier(
            chain_identifier=chain_id,
            token_network_address=token_network_address,
            channel_identifier=channel_identifier,
        ),
        token_address=token_network_proxy.token_address(),
        token_network_registry_address=token_network_registry_address,
        reveal_timeout=reveal_timeout,
        settle_timeout=BlockTimeout(TEST_SETTLE_TIMEOUT_MIN),
        fee_schedule=FeeScheduleState(),
        our_state=NettingChannelEndState(
            address=token_network_proxy.client.address, contract_balance=Balance(0)
        ),
        partner_state=NettingChannelEndState(address=partner, contract_balance=Balance(0)),
        open_transaction=SuccessfulTransactionState(finished_block_number=BlockNumber(0)),
    )
    channel_proxy_1 = proxy_manager.payment_channel(
        channel_state=channel_state, block_identifier=BLOCK_ID_LATEST
    )

    assert channel_proxy_1.channel_identifier == channel_identifier
    assert channel_proxy_1.opened(BLOCK_ID_LATEST) is True

    # Test deposit
    initial_token_balance = 100
    token_proxy.transfer(rpc_client.address, TokenAmount(initial_token_balance))
    assert token_proxy.balance_of(rpc_client.address) == initial_token_balance
    assert token_proxy.balance_of(partner) == 0
    channel_proxy_1.approve_and_set_total_deposit(
        total_deposit=TokenAmount(10), block_identifier=BLOCK_ID_LATEST
    )

    # ChannelOpened, ChannelNewDeposit
    channel_events = get_all_netting_channel_events(
        proxy_manager=proxy_manager,
        token_network_address=token_network_address,
        netting_channel_identifier=channel_proxy_1.channel_identifier,
        contract_manager=contract_manager,
        from_block=start_block,
        to_block=web3.eth.blockNumber,
    )

    assert len(channel_events) == 2

    block_before_close = web3.eth.blockNumber
    empty_balance_proof = BalanceProof(
        channel_identifier=channel_proxy_1.channel_identifier,
        token_network_address=token_network_address,
        balance_hash=EMPTY_BALANCE_HASH,
        nonce=0,
        chain_id=chain_id,
        transferred_amount=TokenAmount(0),
    )
    closing_data = (
        empty_balance_proof.serialize_bin(msg_type=MessageTypeId.BALANCE_PROOF) + EMPTY_SIGNATURE
    )
    channel_proxy_1.close(
        nonce=Nonce(0),
        balance_hash=EMPTY_BALANCE_HASH,
        additional_hash=EMPTY_MESSAGE_HASH,
        non_closing_signature=EMPTY_SIGNATURE,
        closing_signature=LocalSigner(private_keys[1]).sign(data=closing_data),
        block_identifier=BLOCK_ID_LATEST,
    )
    assert channel_proxy_1.closed(BLOCK_ID_LATEST) is True
    # ChannelOpened, ChannelNewDeposit, ChannelClosed
    channel_events = get_all_netting_channel_events(
        proxy_manager=proxy_manager,
        token_network_address=token_network_address,
        netting_channel_identifier=channel_proxy_1.channel_identifier,
        contract_manager=contract_manager,
        from_block=start_block,
        to_block=web3.eth.blockNumber,
    )
    assert len(channel_events) == 3

    # check the settlement timeouts again
    assert channel_proxy_1.settle_timeout() == TEST_SETTLE_TIMEOUT_MIN

    # update transfer -- we need to wait on +1 since we use the latest block on parity for
    # estimate gas and at the time the latest block is the settle timeout block.
    # More info: https://github.com/raiden-network/raiden/pull/3699#discussion_r270477227
    rpc_client.wait_until_block(
        target_block_number=BlockNumber(rpc_client.block_number() + TEST_SETTLE_TIMEOUT_MIN + 1)
    )

    transaction_hash = channel_proxy_1.settle(
        transferred_amount=TokenAmount(0),
        locked_amount=LockedAmount(0),
        locksroot=LOCKSROOT_OF_NO_LOCKS,
        partner_transferred_amount=TokenAmount(0),
        partner_locked_amount=LockedAmount(0),
        partner_locksroot=LOCKSROOT_OF_NO_LOCKS,
        block_identifier=BLOCK_ID_LATEST,
    )
    assert is_tx_hash_bytes(transaction_hash)
    assert channel_proxy_1.settled(BLOCK_ID_LATEST) is True
    # ChannelOpened, ChannelNewDeposit, ChannelClosed, ChannelSettled
    channel_events = get_all_netting_channel_events(
        proxy_manager=proxy_manager,
        token_network_address=token_network_address,
        netting_channel_identifier=channel_proxy_1.channel_identifier,
        contract_manager=contract_manager,
        from_block=start_block,
        to_block=web3.eth.blockNumber,
    )
    assert len(channel_events) == 4

    channel_details = token_network_proxy.new_netting_channel(
        partner=partner,
        settle_timeout=TEST_SETTLE_TIMEOUT_MIN,
        given_block_identifier=BLOCK_ID_LATEST,
    )
    new_channel_identifier = channel_details.channel_identifier
    assert new_channel_identifier is not None

    channel_state = NettingChannelState(
        canonical_identifier=CanonicalIdentifier(
            chain_identifier=chain_id,
            token_network_address=token_network_address,
            channel_identifier=new_channel_identifier,
        ),
        token_address=token_network_proxy.token_address(),
        token_network_registry_address=token_network_registry_address,
        reveal_timeout=reveal_timeout,
        settle_timeout=BlockTimeout(TEST_SETTLE_TIMEOUT_MIN),
        fee_schedule=FeeScheduleState(),
        our_state=NettingChannelEndState(
            address=token_network_proxy.client.address, contract_balance=Balance(0)
        ),
        partner_state=NettingChannelEndState(address=partner, contract_balance=Balance(0)),
        open_transaction=SuccessfulTransactionState(finished_block_number=BlockNumber(0)),
    )
    channel_proxy_2 = proxy_manager.payment_channel(
        channel_state=channel_state, block_identifier=BLOCK_ID_LATEST
    )

    assert channel_proxy_2.channel_identifier == new_channel_identifier
    assert channel_proxy_2.opened(BLOCK_ID_LATEST) is True

    msg = "The channel was already closed, the second call must fail"
    with pytest.raises(RaidenRecoverableError):
        channel_proxy_1.close(
            nonce=Nonce(0),
            balance_hash=EMPTY_BALANCE_HASH,
            additional_hash=EMPTY_MESSAGE_HASH,
            non_closing_signature=EMPTY_SIGNATURE,
            closing_signature=LocalSigner(private_keys[1]).sign(data=closing_data),
            block_identifier=block_before_close,
        )
        pytest.fail(msg)

    msg = "The channel is not open at latest, this must raise"
    with pytest.raises(RaidenUnrecoverableError):
        channel_proxy_1.close(
            nonce=Nonce(0),
            balance_hash=EMPTY_BALANCE_HASH,
            additional_hash=EMPTY_MESSAGE_HASH,
            non_closing_signature=EMPTY_SIGNATURE,
            closing_signature=LocalSigner(private_keys[1]).sign(data=closing_data),
            block_identifier=BLOCK_ID_LATEST,
        )
        pytest.fail(msg)

    msg = (
        "The channel was not opened at the provided block (latest). "
        "This call should never have been attempted."
    )
    with pytest.raises(BrokenPreconditionError):
        channel_proxy_1.approve_and_set_total_deposit(
            total_deposit=TokenAmount(20), block_identifier=BLOCK_ID_LATEST
        )
        pytest.fail(msg)
Exemplo n.º 15
0
    def deposit(self, 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.')

        token_address = self.token_address()

        token = Token(
            self.client,
            token_address,
            self.poll_timeout,
        )
        current_balance = token.balance_of(self.node_address)
        current_deposit = self.detail_participant(self.node_address, partner)['deposit']
        amount_to_deposit = total_deposit - current_deposit

        if amount_to_deposit <= 0:
            raise ValueError('deposit [{}] must be greater than 0.'.format(
                amount_to_deposit,
            ))

        if current_balance < amount_to_deposit:
            raise ValueError(
                f'deposit {amount_to_deposit} cant be larger than the '
                f'available balance {current_balance}, '
                f'for token at address {pex(token_address)}',
            )

        log.info(
            'deposit called',
            token_network=pex(self.address),
            node=pex(self.node_address),
            partner=pex(partner),
            total_deposit=total_deposit,
            amount_to_deposit=amount_to_deposit,
        )

        self._check_channel_lock(partner)

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

            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(
                    'deposit failed',
                    token_network=pex(self.address),
                    node=pex(self.node_address),
                    partner=pex(partner),
                    total_deposit=total_deposit,
                )

                channel_opened = self.channel_is_opened(partner)
                if channel_opened is False:
                    raise ChannelIncorrectStateError(
                        'Channel is not in an opened state. A deposit cannot be made',
                    )
                raise TransactionThrew('Deposit', receipt_or_none)

            log.info(
                'deposit successful',
                token_network=pex(self.address),
                node=pex(self.node_address),
                partner=pex(partner),
                total_deposit=total_deposit,
            )
Exemplo n.º 16
0
    def _add_token(self, token_address: TokenAddress,
                   additional_arguments: Dict) -> Address:
        if not is_binary_address(token_address):
            raise InvalidAddress("Expected binary address format for token")

        token_proxy = Token(
            jsonrpc_client=self.client,
            token_address=token_address,
            contract_manager=self.contract_manager,
        )

        if token_proxy.total_supply() == "":
            raise InvalidToken(
                "Given token address does not follow the ERC20 standard (missing totalSupply()"
            )

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

        checking_block = self.client.get_checking_block()
        error_prefix = "Call to createERC20TokenNetwork will fail"

        kwarguments = {"_token_address": token_address}
        kwarguments.update(additional_arguments)
        gas_limit = self.proxy.estimate_gas(checking_block,
                                            "createERC20TokenNetwork",
                                            **kwarguments)

        if gas_limit:
            error_prefix = "Call to createERC20TokenNetwork failed"
            transaction_hash = self.proxy.transact(
                "createERC20TokenNetwork",
                safe_gas_limit(gas_limit,
                               GAS_REQUIRED_FOR_CREATE_ERC20_TOKEN_NETWORK),
                **kwarguments,
            )

            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

            required_gas = gas_limit if gas_limit else GAS_REQUIRED_FOR_CREATE_ERC20_TOKEN_NETWORK
            self.proxy.jsonrpc_client.check_for_insufficient_eth(
                transaction_name="createERC20TokenNetwork",
                transaction_executed=transaction_executed,
                required_gas=required_gas,
                block_identifier=block,
            )

            if self.get_token_network(token_address, block):
                error_msg = f"{error_prefix}. Token already registered"
                log.warning(error_msg, **log_details)
                raise RaidenRecoverableError(error_msg)

            error_msg = f"{error_prefix}"
            log.critical(error_msg, **log_details)
            raise RaidenUnrecoverableError(error_msg)

        token_network_address = self.get_token_network(token_address, "latest")
        if token_network_address is None:
            msg = "createERC20TokenNetwork succeeded but token network address is Null"
            log.critical(msg, **log_details)
            raise RuntimeError(msg)

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

        return token_network_address
Exemplo n.º 17
0
    def _deposit_check_result(
        self,
        transaction_sent: Optional[TransactionSent],
        token: Token,
        beneficiary: Address,
        total_deposit: TokenAmount,
        amount_to_deposit: TokenAmount,
    ) -> None:
        if transaction_sent is None:
            failed_at = self.client.get_block(BLOCK_ID_LATEST)
            failed_at_blocknumber = failed_at["number"]

            self.client.check_for_insufficient_eth(
                transaction_name="deposit",
                transaction_executed=False,
                required_gas=self.gas_measurements["UserDeposit.deposit"],
                block_identifier=failed_at_blocknumber,
            )

            latest_deposit = self.get_total_deposit(
                address=beneficiary, block_identifier=failed_at_blocknumber
            )
            amount_to_deposit = TokenAmount(total_deposit - latest_deposit)

            allowance = token.allowance(
                owner=self.node_address,
                spender=Address(self.address),
                block_identifier=failed_at_blocknumber,
            )
            whole_balance = self.whole_balance(block_identifier=failed_at_blocknumber)
            whole_balance_limit = self.whole_balance_limit(block_identifier=failed_at_blocknumber)

            if allowance < amount_to_deposit:
                msg = (
                    "The allowance is insufficient. Check concurrent deposits "
                    "for the same user deposit but different proxies."
                )
                raise RaidenRecoverableError(msg)

            if token.balance_of(self.node_address, failed_at_blocknumber) < amount_to_deposit:
                msg = "The address doesnt have enough tokens"
                raise RaidenRecoverableError(msg)

            if latest_deposit < total_deposit:
                msg = "Deposit amount did not increase after deposit transaction"
                raise RaidenRecoverableError(msg)

            if whole_balance + amount_to_deposit > UINT256_MAX:
                msg = (
                    f"Current whole balance is {whole_balance}. "
                    f"The new deposit of {amount_to_deposit} would lead to an overflow."
                )
                raise RaidenRecoverableError(msg)

            if whole_balance + amount_to_deposit > whole_balance_limit:
                msg = (
                    f"Current whole balance is {whole_balance}. "
                    f"With the new deposit of {amount_to_deposit}, the deposit "
                    f"limit of {whole_balance_limit} would be exceeded."
                )
                raise RaidenRecoverableError(msg)

            raise RaidenRecoverableError("Deposit failed of unknown reason")

        else:
            transaction_mined = self.client.poll_transaction(transaction_sent)

            if not was_transaction_successfully_mined(transaction_mined):
                failed_at_blocknumber = BlockNumber(transaction_mined.receipt["blockNumber"])

                latest_deposit = self.get_total_deposit(
                    address=beneficiary, block_identifier=failed_at_blocknumber
                )
                amount_to_deposit = TokenAmount(total_deposit - latest_deposit)

                allowance = token.allowance(
                    owner=self.node_address,
                    spender=Address(self.address),
                    block_identifier=failed_at_blocknumber,
                )

                whole_balance = self.whole_balance(block_identifier=failed_at_blocknumber)
                whole_balance_limit = self.whole_balance_limit(
                    block_identifier=failed_at_blocknumber
                )

                if latest_deposit >= total_deposit:
                    msg = "Deposit amount already increased after another transaction"
                    raise RaidenRecoverableError(msg)

                if allowance < amount_to_deposit:
                    msg = (
                        "The allowance is insufficient. Check concurrent deposits "
                        "for the same token network but different proxies."
                    )
                    raise RaidenRecoverableError(msg)

                # Because we acquired the lock for the token, and the gas estimation succeeded,
                # We know that the account had enough balance for the deposit transaction.
                if token.balance_of(self.node_address, failed_at_blocknumber) < amount_to_deposit:
                    msg = (
                        "Transaction failed and balance decreased unexpectedly. "
                        "This could be a bug in Raiden or a mallicious "
                        "ERC20 Token."
                    )
                    raise RaidenRecoverableError(msg)

                if whole_balance + amount_to_deposit > UINT256_MAX:
                    msg = (
                        f"Current whole balance is {whole_balance}. "
                        f"The new deposit of {amount_to_deposit} caused an overflow."
                    )
                    raise RaidenRecoverableError(msg)

                if whole_balance + amount_to_deposit > whole_balance_limit:
                    msg = (
                        f"Current whole balance is {whole_balance}. "
                        f"With the new deposit of {amount_to_deposit}, the deposit "
                        f"limit of {whole_balance_limit} was exceeded."
                    )
                    raise RaidenRecoverableError(msg)

                if latest_deposit < total_deposit:
                    msg = "Deposit amount did not increase after deposit transaction"
                    raise RaidenRecoverableError(msg)

                raise RaidenRecoverableError("Deposit failed of unknown reason")
Exemplo n.º 18
0
    def deposit(
        self,
        beneficiary: Address,
        total_deposit: TokenAmount,
        block_identifier: BlockSpecification,
    ) -> None:
        """ Deposit provided amount into the user-deposit contract
        to the beneficiary's account. """

        token_address = self.token_address(block_identifier)
        token = Token(
            jsonrpc_client=self.client,
            token_address=token_address,
            contract_manager=self.contract_manager,
        )

        log_details = {
            "beneficiary": pex(beneficiary),
            "contract": pex(self.address),
            "total_deposit": total_deposit,
        }

        checking_block = self.client.get_checking_block()
        error_prefix = "Call to deposit will fail"

        with self.deposit_lock:
            amount_to_deposit, log_details = self._deposit_preconditions(
                total_deposit=total_deposit,
                beneficiary=beneficiary,
                token=token,
                block_identifier=block_identifier,
            )
            gas_limit = self.proxy.estimate_gas(
                checking_block, "deposit", to_checksum_address(beneficiary),
                total_deposit)

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

                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="deposit",
                    transaction_executed=transaction_executed,
                    required_gas=GAS_REQUIRED_FOR_UDC_DEPOSIT,
                    block_identifier=block,
                )

                msg = self._check_why_deposit_failed(
                    token=token,
                    amount_to_deposit=amount_to_deposit,
                    total_deposit=total_deposit,
                    block_identifier=block,
                )
                error_msg = f"{error_prefix}. {msg}"
                log.critical(error_msg, **log_details)
                raise RaidenUnrecoverableError(error_msg)

        log.info("deposit successful", **log_details)
Exemplo n.º 19
0
    def deposit(self, amount):
        """ Deposit amount 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(amount, int):
            raise ValueError('amount needs to be an integral number.')

        token_address = self.token_address()

        token = Token(
            self.client,
            token_address,
            self.poll_timeout,
        )
        current_balance = token.balance_of(self.node_address)

        if current_balance < amount:
            raise ValueError('deposit [{}] cant be larger than the available balance [{}].'.format(
                amount,
                current_balance,
            ))

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

        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 = estimate_and_transact(
                self.proxy,
                'deposit',
                amount,
            )

            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(
                    'deposit failed',
                    node=pex(self.node_address),
                    contract=pex(self.address),
                )

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

            log.info(
                'deposit successful',
                node=pex(self.node_address),
                contract=pex(self.address),
                amount=amount,
            )
Exemplo n.º 20
0
    def _add_token(
        self,
        token_address: TokenAddress,
        channel_participant_deposit_limit: TokenAmount,
        token_network_deposit_limit: TokenAmount,
        log_details: Dict[Any, Any],
    ) -> Tuple[TransactionHash, TokenNetworkAddress]:
        token_network_address = None

        kwargs = {
            "_token_address": token_address,
            "_channel_participant_deposit_limit":
            channel_participant_deposit_limit,
            "_token_network_deposit_limit": token_network_deposit_limit,
        }
        estimated_transaction = self.rpc_client.estimate_gas(
            self.proxy, "createERC20TokenNetwork", log_details, **kwargs)

        if estimated_transaction is not None:
            estimated_transaction.estimated_gas = safe_gas_limit(
                estimated_transaction.estimated_gas,
                self.gas_measurements[
                    "TokenNetworkRegistry createERC20TokenNetwork"],
            )

            transaction_sent = self.rpc_client.transact(estimated_transaction)
            transaction_mined = self.rpc_client.poll_transaction(
                transaction_sent)
            receipt = transaction_mined.receipt

            if not was_transaction_successfully_mined(transaction_mined):
                failed_at_blocknumber = BlockNumber(receipt["blockNumber"])

                max_token_networks = self.get_max_token_networks(
                    block_identifier=failed_at_blocknumber)
                token_networks_created = self.get_token_network_created(
                    block_identifier=failed_at_blocknumber)
                already_registered = self.get_token_network(
                    token_address=token_address,
                    block_identifier=failed_at_blocknumber)
                deprecation_executor = self.get_deprecation_executor(
                    block_identifier=failed_at_blocknumber)
                settlement_timeout_min = self.settlement_timeout_min(
                    block_identifier=failed_at_blocknumber)
                settlement_timeout_max = self.settlement_timeout_max(
                    block_identifier=failed_at_blocknumber)
                chain_id = self.get_chain_id(
                    block_identifier=failed_at_blocknumber)
                secret_registry_address = self.get_secret_registry_address(
                    block_identifier=failed_at_blocknumber)

                try:
                    # Creating a new instance to run the constructor checks.
                    token_proxy = Token(
                        jsonrpc_client=self.rpc_client,
                        token_address=token_address,
                        contract_manager=self.proxy_manager.contract_manager,
                        block_identifier=failed_at_blocknumber,
                    )
                except AddressWithoutCode:
                    # This cannot be an unrecoverable error, since the ERC20
                    # code is external.
                    raise RaidenRecoverableError(
                        "Token disappeared! The address "
                        f"{to_checksum_address(token_address)} did have code at "
                        f"block {log_details['given_block_identifier']}, however "
                        f"at block {failed_at_blocknumber} when the registration "
                        "transaction was mined the address didn't have code "
                        "anymore.")

                check_transaction_failure(transaction_mined, self.rpc_client)

                check_address_has_code_handle_pruned_block(
                    client=self.rpc_client,
                    address=Address(secret_registry_address),
                    contract_name=CONTRACT_SECRET_REGISTRY,
                    expected_code=decode_hex(
                        self.proxy_manager.contract_manager.
                        get_runtime_hexcode(CONTRACT_SECRET_REGISTRY)),
                    given_block_identifier=failed_at_blocknumber,
                )

                if token_networks_created >= max_token_networks:
                    raise RaidenRecoverableError(
                        "The number of existing token networks reached the maximum allowed"
                    )

                if already_registered:
                    # Race condition lost, the token network was created in a different
                    # transaction which got mined first.
                    raise RaidenRecoverableError(
                        "The token was already registered in the TokenNetworkRegistry."
                    )

                if deprecation_executor == NULL_ADDRESS_BYTES:
                    raise RaidenUnrecoverableError(
                        "The deprecation executor property for the "
                        "TokenNetworkRegistry is invalid.")

                if chain_id == 0:
                    raise RaidenUnrecoverableError(
                        "The chain ID property for the TokenNetworkRegistry is invalid."
                    )

                if chain_id != self.rpc_client.chain_id:
                    raise RaidenUnrecoverableError(
                        f"The provided chain ID {chain_id} does not match the "
                        f"network Raiden is running on: {self.rpc_client.chain_id}."
                    )

                if secret_registry_address == NULL_ADDRESS_BYTES:
                    raise RaidenUnrecoverableError(
                        "The secret registry address for the token network is invalid."
                    )

                if settlement_timeout_min == 0:
                    raise RaidenUnrecoverableError(
                        "The minimum settlement timeout for the token network "
                        "should be larger than zero.")

                if settlement_timeout_max <= settlement_timeout_min:
                    raise RaidenUnrecoverableError(
                        "The maximum settlement timeout for the token network "
                        "should be larger than the minimum settlement timeout."
                    )

                total_supply = token_proxy.total_supply(
                    block_identifier=failed_at_blocknumber)
                if not total_supply or total_supply <= 0:
                    raise RaidenRecoverableError(
                        f"The given token address is not a valid ERC20 token, "
                        f"total_supply() returned an invalid value {total_supply}."
                    )

                # At this point, the TokenNetworkRegistry fails to instantiate
                # a new TokenNetwork.
                raise RaidenUnrecoverableError(
                    "createERC20TokenNetwork failed for an unknown reason, even "
                    "though the gas estimation succeeded.")

            succeeded_at_blockhash = receipt["blockHash"]
            token_network_address = self.get_token_network(
                token_address, succeeded_at_blockhash)
            if token_network_address is None:
                msg = "createERC20TokenNetwork succeeded but token network address is Null"
                raise RaidenUnrecoverableError(msg)
        else:  # `estimated_transaction` is None
            # The latest block can not be used reliably because of reorgs,
            # therefore every call using this block has to handle pruned data.
            failed_at_block = self.rpc_client.get_block(BLOCK_ID_LATEST)
            failed_at_blockhash = failed_at_block["hash"].hex()
            failed_at_blocknumber = failed_at_block["number"]

            max_token_networks = self.get_max_token_networks(
                block_identifier=failed_at_blocknumber)
            token_networks_created = self.get_token_network_created(
                block_identifier=failed_at_blocknumber)

            already_registered = self.get_token_network(
                token_address=token_address,
                block_identifier=failed_at_blocknumber)
            deprecation_executor = self.get_deprecation_executor(
                block_identifier=failed_at_blocknumber)
            settlement_timeout_min = self.settlement_timeout_min(
                block_identifier=failed_at_blocknumber)
            settlement_timeout_max = self.settlement_timeout_max(
                block_identifier=failed_at_blocknumber)
            chain_id = self.get_chain_id(
                block_identifier=failed_at_blocknumber)
            secret_registry_address = self.get_secret_registry_address(
                block_identifier=failed_at_blocknumber)

            try:
                # Creating a new instance to run the constructor checks.
                token_proxy = Token(
                    jsonrpc_client=self.rpc_client,
                    token_address=token_address,
                    contract_manager=self.proxy_manager.contract_manager,
                    block_identifier=failed_at_blocknumber,
                )
            except AddressWithoutCode:
                # This cannot be an unrecoverable error, since the ERC20
                # code is external.
                raise RaidenRecoverableError(
                    "Token disappeared! The address "
                    "{to_checksum_address(token_address)} did have code at "
                    "block {log_details['given_block_identifier']}, however "
                    "at block {failed_at_blocknumber} when the registration "
                    "transaction was mined the address didn't have code "
                    "anymore.")

            check_address_has_code_handle_pruned_block(
                client=self.rpc_client,
                address=Address(secret_registry_address),
                contract_name=CONTRACT_SECRET_REGISTRY,
                expected_code=decode_hex(
                    self.proxy_manager.contract_manager.get_runtime_hexcode(
                        CONTRACT_SECRET_REGISTRY)),
                given_block_identifier=failed_at_blocknumber,
            )

            required_gas = self.gas_measurements[
                "TokenNetworkRegistry createERC20TokenNetwork"]

            self.rpc_client.check_for_insufficient_eth(
                transaction_name="createERC20TokenNetwork",
                transaction_executed=False,
                required_gas=required_gas,
                block_identifier=failed_at_blocknumber,
            )

            if token_networks_created >= max_token_networks:
                raise RaidenRecoverableError(
                    "The number of existing token networks reached the maximum allowed"
                )

            if already_registered:
                # Race condition lost, the token network was created in a different
                # transaction which got mined first.
                raise RaidenRecoverableError(
                    "The token was already registered in the TokenNetworkRegistry."
                )

            if deprecation_executor == NULL_ADDRESS_BYTES:
                raise RaidenUnrecoverableError(
                    "The deprecation executor property for the TokenNetworkRegistry is invalid."
                )

            if chain_id == 0:
                raise RaidenUnrecoverableError(
                    "The chain ID property for the TokenNetworkRegistry is invalid."
                )

            if chain_id != self.rpc_client.chain_id:
                raise RaidenUnrecoverableError(
                    f"The provided chain ID {chain_id} does not match the "
                    f"network Raiden is running on: {self.rpc_client.chain_id}."
                )

            if secret_registry_address == NULL_ADDRESS_BYTES:
                raise RaidenUnrecoverableError(
                    "The secret registry address for the token network is invalid."
                )

            if settlement_timeout_min <= 0:
                raise RaidenUnrecoverableError(
                    "The minimum settlement timeout for the token network "
                    "should be larger than zero.")

            if settlement_timeout_max <= settlement_timeout_min:
                raise RaidenUnrecoverableError(
                    "The maximum settlement timeout for the token network "
                    "should be larger than the minimum settlement timeout.")

            total_supply = token_proxy.total_supply(
                block_identifier=failed_at_blocknumber)
            if not total_supply or total_supply <= 0:
                raise RaidenRecoverableError(
                    f"The given token address is not a valid ERC20 token, "
                    f"total_supply() returned an invalid value {total_supply}."
                )

            # At this point, the TokenNetworkRegistry fails to instantiate
            # a new TokenNetwork.
            raise RaidenUnrecoverableError(
                f"createERC20TokenNetwork gas estimation failed for an unknown "
                f"reason. Reference block {failed_at_blockhash} "
                f"{failed_at_blocknumber}.")
        return (
            TransactionHash(transaction_mined.transaction_hash),
            TokenNetworkAddress(token_network_address),
        )
Exemplo n.º 21
0
    def _add_token(
        self,
        token_address: TokenAddress,
        additional_arguments: Dict,
    ) -> Address:
        if not is_binary_address(token_address):
            raise InvalidAddress('Expected binary address format for token')

        token_proxy = Token(
            jsonrpc_client=self.client,
            token_address=token_address,
            contract_manager=self.contract_manager,
        )

        if token_proxy.total_supply() == '':
            raise InvalidToken(
                'Given token address does not follow the ERC20 standard (missing totalSupply()',
            )

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

        checking_block = self.client.get_checking_block()
        error_prefix = 'Call to createERC20TokenNetwork will fail'

        kwarguments = {'_token_address': token_address}
        kwarguments.update(additional_arguments)
        gas_limit = self.proxy.estimate_gas(
            checking_block,
            'createERC20TokenNetwork',
            **kwarguments,
        )

        if gas_limit:
            error_prefix = 'Call to createERC20TokenNetwork failed'
            transaction_hash = self.proxy.transact(
                'createERC20TokenNetwork',
                safe_gas_limit(gas_limit,
                               GAS_REQUIRED_FOR_CREATE_ERC20_TOKEN_NETWORK),
                **kwarguments,
            )

            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:
            error_type = RaidenUnrecoverableError
            if transaction_executed:
                block = receipt_or_none['blockNumber']
            else:
                block = checking_block

            required_gas = gas_limit if gas_limit else GAS_REQUIRED_FOR_CREATE_ERC20_TOKEN_NETWORK
            self.proxy.jsonrpc_client.check_for_insufficient_eth(
                transaction_name='createERC20TokenNetwork',
                transaction_executed=transaction_executed,
                required_gas=required_gas,
                block_identifier=block,
            )

            msg = ''
            if self.get_token_network(token_address, block):
                msg = 'Token already registered'
                error_type = RaidenRecoverableError

            error_msg = f'{error_prefix}. {msg}'
            if error_type == RaidenRecoverableError:
                log.warning(error_msg, **log_details)
            else:
                log.critical(error_msg, **log_details)
            raise error_type(error_msg)

        token_network_address = self.get_token_network(token_address, 'latest')
        if token_network_address is None:
            msg = 'createERC20TokenNetwork succeeded but token network address is Null'
            log.critical(msg, **log_details)
            raise RuntimeError(msg)

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

        return token_network_address
Exemplo n.º 22
0
    def _deposit(
        self,
        beneficiary: Address,
        token: Token,
        total_deposit: TokenAmount,
        amount_to_deposit: TokenAmount,
        log_details: Dict[str, Any],
    ) -> None:
        token.approve(allowed_address=Address(self.address),
                      allowance=amount_to_deposit)

        checking_block = self.client.get_checking_block()
        gas_limit = self.proxy.estimate_gas(checking_block, "deposit",
                                            to_checksum_address(beneficiary),
                                            total_deposit)

        if not gas_limit:
            failed_at = self.proxy.rpc_client.get_block("latest")
            failed_at_blocknumber = failed_at["number"]

            self.proxy.rpc_client.check_for_insufficient_eth(
                transaction_name="deposit",
                transaction_executed=False,
                required_gas=self.gas_measurements["UserDeposit.deposit"],
                block_identifier=failed_at_blocknumber,
            )

            latest_deposit = self.get_total_deposit(
                address=self.node_address,
                block_identifier=failed_at_blocknumber)
            amount_to_deposit = TokenAmount(total_deposit - latest_deposit)

            allowance = token.allowance(
                owner=self.node_address,
                spender=Address(self.address),
                block_identifier=failed_at_blocknumber,
            )
            whole_balance = self.whole_balance(
                block_identifier=failed_at_blocknumber)
            whole_balance_limit = self.whole_balance_limit(
                block_identifier=failed_at_blocknumber)

            if allowance < amount_to_deposit:
                msg = (
                    "The allowance is insufficient. Check concurrent deposits "
                    "for the same user deposit but different proxies.")
                raise RaidenRecoverableError(msg)

            if token.balance_of(self.node_address,
                                failed_at_blocknumber) < amount_to_deposit:
                msg = "The address doesnt have enough tokens"
                raise RaidenRecoverableError(msg)

            if latest_deposit < total_deposit:
                msg = "Deposit amount did not increase after deposit transaction"
                raise RaidenRecoverableError(msg)

            if whole_balance + amount_to_deposit > UINT256_MAX:
                msg = (
                    f"Current whole balance is {whole_balance}. "
                    f"The new deposit of {amount_to_deposit} would lead to an overflow."
                )
                raise RaidenRecoverableError(msg)

            if whole_balance + amount_to_deposit > whole_balance_limit:
                msg = (
                    f"Current whole balance is {whole_balance}. "
                    f"With the new deposit of {amount_to_deposit}, the deposit "
                    f"limit of {whole_balance_limit} would be exceeded.")
                raise RaidenRecoverableError(msg)

            raise RaidenRecoverableError("Deposit failed of unknown reason")

        else:
            gas_limit = safe_gas_limit(gas_limit)
            log_details["gas_limit"] = gas_limit

            transaction_hash = self.proxy.transact(
                "deposit", gas_limit, to_checksum_address(beneficiary),
                total_deposit)

            receipt = self.client.poll(transaction_hash)
            failed_receipt = check_transaction_threw(receipt=receipt)

            if failed_receipt:
                failed_at_blocknumber = failed_receipt["blockNumber"]

                latest_deposit = self.get_total_deposit(
                    address=self.node_address,
                    block_identifier=failed_at_blocknumber)
                amount_to_deposit = TokenAmount(total_deposit - latest_deposit)

                allowance = token.allowance(
                    owner=self.node_address,
                    spender=Address(self.address),
                    block_identifier=failed_at_blocknumber,
                )

                whole_balance = self.whole_balance(
                    block_identifier=failed_at_blocknumber)
                whole_balance_limit = self.whole_balance_limit(
                    block_identifier=failed_at_blocknumber)

                if latest_deposit >= total_deposit:
                    msg = "Deposit amount already increased after another transaction"
                    raise RaidenRecoverableError(msg)

                if allowance < amount_to_deposit:
                    msg = (
                        "The allowance is insufficient. Check concurrent deposits "
                        "for the same token network but different proxies.")
                    raise RaidenRecoverableError(msg)

                # Because we acquired the lock for the token, and the gas estimation succeeded,
                # We know that the account had enough balance for the deposit transaction.
                if token.balance_of(self.node_address,
                                    failed_at_blocknumber) < amount_to_deposit:
                    msg = (
                        f"Transaction failed and balance decreased unexpectedly. "
                        f"This could be a bug in Raiden or a mallicious "
                        f"ERC20 Token.")
                    raise RaidenRecoverableError(msg)

                if whole_balance + amount_to_deposit > UINT256_MAX:
                    msg = (
                        f"Current whole balance is {whole_balance}. "
                        f"The new deposit of {amount_to_deposit} caused an overflow."
                    )
                    raise RaidenRecoverableError(msg)

                if whole_balance + amount_to_deposit > whole_balance_limit:
                    msg = (
                        f"Current whole balance is {whole_balance}. "
                        f"With the new deposit of {amount_to_deposit}, the deposit "
                        f"limit of {whole_balance_limit} was exceeded.")
                    raise RaidenRecoverableError(msg)

                if latest_deposit < total_deposit:
                    msg = "Deposit amount did not increase after deposit transaction"
                    raise RaidenRecoverableError(msg)

                raise RaidenRecoverableError(
                    "Deposit failed of unknown reason")
Exemplo n.º 23
0
def deploy_service_registry_and_set_urls(
        private_keys, web3, contract_manager,
        service_registry_address) -> Tuple[ServiceRegistry, List[str]]:
    urls = ["http://foo", "http://boo", "http://coo"]
    c1_client = JSONRPCClient(web3, private_keys[0])
    c1_service_proxy = ServiceRegistry(
        jsonrpc_client=c1_client,
        service_registry_address=service_registry_address,
        contract_manager=contract_manager,
    )
    token_address = c1_service_proxy.token_address(block_identifier="latest")
    c1_token_proxy = Token(jsonrpc_client=c1_client,
                           token_address=token_address,
                           contract_manager=contract_manager)
    c2_client = JSONRPCClient(web3, private_keys[1])
    c2_service_proxy = ServiceRegistry(
        jsonrpc_client=c2_client,
        service_registry_address=service_registry_address,
        contract_manager=contract_manager,
    )
    c2_token_proxy = Token(jsonrpc_client=c2_client,
                           token_address=token_address,
                           contract_manager=contract_manager)
    c3_client = JSONRPCClient(web3, private_keys[2])
    c3_service_proxy = ServiceRegistry(
        jsonrpc_client=c3_client,
        service_registry_address=service_registry_address,
        contract_manager=contract_manager,
    )
    c3_token_proxy = Token(jsonrpc_client=c3_client,
                           token_address=token_address,
                           contract_manager=contract_manager)

    # Test that getting a random service for an empty registry returns None
    pfs_address = get_random_pfs(c1_service_proxy,
                                 "latest",
                                 pathfinding_max_fee=TokenAmount(1))
    assert pfs_address is None

    # Test that setting the urls works
    c1_price = c1_service_proxy.current_price(block_identifier="latest")
    tx = c1_token_proxy.proxy.transact("mint", 1000000, c1_price)
    receipt = c1_client.poll(tx)
    assert not check_transaction_threw(receipt=receipt)
    assert c1_token_proxy.balance_of(c1_client.address) > 0
    c1_token_proxy.approve(allowed_address=service_registry_address,
                           allowance=c1_price)
    c1_service_proxy.deposit(block_identifier="latest", limit_amount=c1_price)
    c1_service_proxy.set_url(urls[0])

    c2_price = c2_service_proxy.current_price(block_identifier="latest")
    tx = c2_token_proxy.proxy.transact("mint", 1000000, c2_price)
    receipt = c2_client.poll(tx)
    assert not check_transaction_threw(receipt=receipt)
    assert c2_token_proxy.balance_of(c2_client.address) > 0
    c2_token_proxy.approve(allowed_address=service_registry_address,
                           allowance=c2_price)
    c2_service_proxy.deposit(block_identifier="latest", limit_amount=c2_price)
    c2_service_proxy.set_url(urls[1])

    c3_price = c3_service_proxy.current_price(block_identifier="latest")
    tx = c3_token_proxy.proxy.transact("mint", 1000000, c3_price)
    receipt = c3_client.poll(tx)
    assert not check_transaction_threw(receipt=receipt)
    assert c3_token_proxy.balance_of(c3_client.address) > 0
    c3_token_proxy.approve(allowed_address=service_registry_address,
                           allowance=c3_price)
    c3_service_proxy.deposit(block_identifier="latest", limit_amount=c3_price)
    c3_token_proxy.proxy.transact("mint", 1000000, c3_price)
    c3_token_proxy.approve(allowed_address=service_registry_address,
                           allowance=c3_price)
    c3_service_proxy.set_url(urls[2])

    return c1_service_proxy, urls