Exemple #1
0
 def secret_request_with_wrong_secrethash(self, previous_action, secret):
     assume(sha256_secrethash(secret) != sha256_secrethash(previous_action.transfer.secret))
     self._assume_channel_opened(previous_action)
     transfer = deepcopy(previous_action.transfer)
     transfer.secret = secret
     action = self._receive_secret_request(transfer)
     client = self._get_initiator_client(transfer)
     return self._unauthentic_secret_request(action, client)
Exemple #2
0
def test_automatic_secret_registration(raiden_chain, token_addresses):
    app0, app1 = raiden_chain
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), app0.raiden.default_registry.address,
        token_address)
    hold_event_handler = app1.raiden.raiden_event_handler

    amount = 100
    identifier = 1

    message_handler = WaitForMessage()

    app1.raiden.message_handler = message_handler

    target = app1.raiden.address
    secret = Secret(sha3(target))
    secrethash = sha256_secrethash(secret)

    hold_event_handler.hold_secretrequest_for(secrethash=secrethash)
    locked_transfer_received = message_handler.wait_for_message(
        LockedTransfer, {})

    app0.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=target,
        identifier=identifier,
        secret=secret,
    )

    # Wait for app1 to receive the locked transfer.
    locked_transfer_received.wait()

    # Stop app0 to avoid sending the unlock, this must be done after the locked
    # transfer is sent.
    app0.raiden.transport.stop()

    reveal_secret = RevealSecret(
        message_identifier=MessageID(random.randint(0, UINT64_MAX)),
        secret=secret,
        signature=EMPTY_SIGNATURE,
    )
    app0.raiden.sign(reveal_secret)
    message_handler.on_message(app1.raiden, reveal_secret)

    chain_state = views.state_from_app(app1)

    secrethash = sha256_secrethash(secret)
    target_task = chain_state.payment_mapping.secrethashes_to_task[secrethash]
    lock_expiration = target_task.target_state.transfer.lock.expiration  # type: ignore
    app1.raiden.proxy_manager.wait_until_block(
        target_block_number=lock_expiration)

    assert app1.raiden.default_secret_registry.is_secret_registered(
        secrethash=secrethash, block_identifier="latest")
Exemple #3
0
def test_sha256_secrethash():
    assert sha256_secrethash(b"") == (
        b"\xe3\xb0\xc4B\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99o\xb9$"
        b"'\xaeA\xe4d\x9b\x93L\xa4\x95\x99\x1bxR\xb8U")

    assert sha256_secrethash(b"a") == (
        b"\xca\x97\x81\x12\xca\x1b\xbd\xca\xfa\xc21\xb3\x9a#\xdcM"
        b"\xa7\x86\xef\xf8\x14|Nr\xb9\x80w\x85\xaf\xeeH\xbb")
    secret = b"secretsecretsecretsecretsecretse"
    assert sha256_secrethash(secret) == (
        b'\xd4h:"\xc1\xce9\x82M\x93\x1e\xed\xc6\x8e\xa8\xfa'
        b"RY\xce\xb05(\xb1\xa2/pu\x86>\xf8\xba\xf0")
    def register_secret_batch(self, secrets: List[Secret]) -> None:
        """Register a batch of secrets. Check if they are already registered at
        the given block identifier."""
        secrets_to_register = list()
        secrethashes_to_register = list()
        secrethashes_not_sent = list()
        transaction_result = AsyncResult()
        wait_for = set()

        # secret registration has no preconditions:
        #
        # - The action does not depend on any state, it's always valid to call
        #   it.
        # - This action is always susceptible to race conditions.
        #
        # Therefore this proxy only needs to detect if the secret is already
        # registered, to avoid sending obviously unecessary transactions, and
        # it has to handle race conditions.

        with self._open_secret_transactions_lock:
            verification_block_hash = self.client.get_confirmed_blockhash()

            for secret in secrets:
                secrethash = sha256_secrethash(secret)
                secrethash_hex = encode_hex(secrethash)

                # Do the local test on `open_secret_transactions` first, then
                # if necessary do an RPC call.
                #
                # The call to `is_secret_registered` has two conflicting
                # requirements:
                #
                # - Avoid sending duplicated transactions for the same lock
                # - Operating on a consistent/confirmed view of the blockchain
                #   (if a secret has been registered in a block that is not
                #   confirmed it doesn't count yet, an optimization would be to
                #   *not* send the transaction and wait for the confirmation)
                #
                # The code below respects the consistent blockchain view,
                # meaning that if this proxy method is called with an old
                # blockhash an unecessary transaction will be sent, and the
                # error will be treated as a race-condition.
                other_result = self.open_secret_transactions.get(secret)

                if other_result is not None:
                    wait_for.add(other_result)
                    secrethashes_not_sent.append(secrethash_hex)
                elif not self.is_secret_registered(secrethash, verification_block_hash):
                    secrets_to_register.append(secret)
                    secrethashes_to_register.append(secrethash_hex)
                    self.open_secret_transactions[secret] = transaction_result

        # From here on the lock is not required. Context-switches will happen
        # for the gas estimation and the transaction, however the
        # synchronization data is limited to the open_secret_transactions
        if secrets_to_register:
            log_details = {"secrethashes_not_sent": secrethashes_not_sent}
            self._register_secret_batch(secrets_to_register, transaction_result, log_details)

        gevent.joinall(wait_for, raise_error=True)
Exemple #5
0
    def _new_mediator_transfer(
        self, initiator_address, target_address, payment_id, amount, secret, our_address
    ) -> LockedTransferSignedState:
        initiator_pkey = self.address_to_privkey[initiator_address]
        balance_proof_data = self._update_balance_proof_data(
            initiator_address, amount, self.block_number + 10, secret, our_address
        )
        self.secrethash_to_secret[sha256_secrethash(secret)] = secret

        return factories.create(
            factories.LockedTransferSignedStateProperties(
                **balance_proof_data.properties.__dict__,
                amount=amount,
                expiration=self.block_number + 10,
                payment_identifier=payment_id,
                secret=secret,
                initiator=initiator_address,
                target=target_address,
                token=self.token_id,
                sender=initiator_address,
                recipient=our_address,
                pkey=initiator_pkey,
                message_identifier=1,
            )
        )
def secret_registry_batch_happy_path(
        proxy_manager: ProxyManager,
        secret_registry_proxy: SecretRegistry) -> None:
    secrets = [make_secret() for i in range(4)]
    secrethashes = [sha256_secrethash(secret) for secret in secrets]

    secret_registry_proxy.register_secret_batch(secrets=secrets)

    logs = get_secret_registry_events(
        proxy_manager=proxy_manager,
        secret_registry_address=secret_registry_proxy.address,
        contract_manager=secret_registry_proxy.contract_manager,
    )

    for secrethash in secrethashes:
        secret_registered = must_have_event(logs, {
            "event": "SecretRevealed",
            "args": {
                "secrethash": secrethash
            }
        })
        assert secret_registered, "All secrets from the batch must be registered"

        block = secret_registry_proxy.get_secret_registration_block_by_secrethash(
            secrethash=secrethash, block_identifier="latest")
        msg = "Block number reported by the proxy and the event must match"
        assert block == secret_registered["block_number"], msg
Exemple #7
0
def secret_registry_batch_happy_path(
        web3: Web3, secret_registry_proxy: SecretRegistry) -> None:
    secrets = [make_secret() for i in range(4)]
    secrethashes = [sha256_secrethash(secret) for secret in secrets]

    secret_registered_filter = secret_registry_proxy.secret_registered_filter(
        GENESIS_BLOCK_NUMBER)
    secret_registry_proxy.register_secret_batch(secrets=secrets)

    logs = [
        secret_registry_proxy.proxy.decode_event(log) for log in
        secret_registered_filter.get_new_entries(web3.eth.blockNumber)
    ]

    for secrethash in secrethashes:
        secret_registered = must_have_event(logs, {
            "event": "SecretRevealed",
            "args": {
                "secrethash": secrethash
            }
        })
        assert secret_registered, "All secrets from the batch must be registered"

        block = secret_registry_proxy.get_secret_registration_block_by_secrethash(
            secrethash=secrethash, block_identifier="latest")
        msg = "Block number reported by the proxy and the event must match"
        assert block == secret_registered["blockNumber"], msg
Exemple #8
0
def secret_registry_batch_happy_path(
    proxy_manager: ProxyManager, secret_registry_proxy: SecretRegistry
) -> None:
    secrets = [make_secret() for i in range(4)]
    secrethashes = [sha256_secrethash(secret) for secret in secrets]

    transaction_hashes = secret_registry_proxy.register_secret_batch(secrets=secrets)
    for tx_hash in transaction_hashes:
        assert is_tx_hash_bytes(tx_hash)

    logs = get_contract_events(
        proxy_manager=proxy_manager,
        abi=proxy_manager.contract_manager.get_contract_abi(CONTRACT_SECRET_REGISTRY),
        contract_address=Address(secret_registry_proxy.address),
    )

    for secrethash in secrethashes:
        secret_registered = must_have_event(
            logs, {"event": "SecretRevealed", "args": {"secrethash": secrethash}}
        )
        assert secret_registered, "All secrets from the batch must be registered"

        block = secret_registry_proxy.get_secret_registration_block_by_secrethash(
            secrethash=secrethash, block_identifier=BLOCK_ID_LATEST
        )
        msg = "Block number reported by the proxy and the event must match"
        assert block == secret_registered["block_number"], msg
 def _update_balance_proof_data(self, partner, amount, expiration, secret):
     expected = self._get_balance_proof_data(partner)
     lock = HashTimeLockState(amount=amount,
                              expiration=expiration,
                              secrethash=sha256_secrethash(secret))
     expected.update(amount, lock)
     return expected
Exemple #10
0
def test_automatic_secret_registration(
    raiden_chain: List[App], token_addresses: List[TokenAddress]
) -> None:
    app0, app1 = raiden_chain
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), app0.raiden.default_registry.address, token_address
    )
    assert token_network_address

    hold_event_handler = app1.raiden.raiden_event_handler
    message_handler = app1.raiden.message_handler

    msg = "hold event handler necessary to control messages"
    assert isinstance(hold_event_handler, HoldRaidenEventHandler), msg
    assert isinstance(message_handler, WaitForMessage), msg

    amount = PaymentAmount(100)
    identifier = factories.make_payment_id()

    target = TargetAddress(app1.raiden.address)
    (secret, secrethash) = factories.make_secret_with_hash()

    hold_event_handler.hold_secretrequest_for(secrethash=secrethash)
    locked_transfer_received = message_handler.wait_for_message(LockedTransfer, {})

    app0.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=target,
        identifier=identifier,
        secret=secret,
    )

    # Wait for app1 to receive the locked transfer.
    locked_transfer_received.wait()

    # Stop app0 to avoid sending the unlock, this must be done after the locked
    # transfer is sent.
    app0.raiden.transport.stop()

    reveal_secret = RevealSecret(
        message_identifier=MessageID(random.randint(0, UINT64_MAX)),
        secret=secret,
        signature=EMPTY_SIGNATURE,
    )
    app0.raiden.sign(reveal_secret)
    message_handler.on_messages(app1.raiden, [reveal_secret])

    chain_state = views.state_from_app(app1)

    secrethash = sha256_secrethash(secret)
    target_task = chain_state.payment_mapping.secrethashes_to_task[secrethash]
    lock_expiration = target_task.target_state.transfer.lock.expiration  # type: ignore
    app1.raiden.proxy_manager.client.wait_until_block(target_block_number=lock_expiration)

    assert app1.raiden.default_secret_registry.is_secret_registered(
        secrethash=secrethash, block_identifier=BLOCK_ID_LATEST
    )
Exemple #11
0
 def _receive_secret_request(self,
                             transfer: TransferDescriptionWithSecretState):
     client = self._get_initiator_client(transfer)
     secrethash = sha256_secrethash(transfer.secret)
     return ReceiveSecretRequest(
         payment_identifier=transfer.payment_identifier,
         amount=transfer.amount,
         expiration=client.expected_expiry[transfer.secrethash],
         secrethash=secrethash,
         sender=Address(transfer.target),
     )
Exemple #12
0
def assert_payment_secret_and_hash(response, payment):
    # make sure that payment key/values are part of the response.
    assert len(response) == 7
    assert "secret" in response
    assert "secret_hash" in response

    secret = Secret(to_bytes(hexstr=response["secret"]))
    assert len(secret) == SECRET_LENGTH
    assert payment["amount"] == response["amount"]

    assert to_bytes(
        hexstr=response["secret_hash"]) == sha256_secrethash(secret)
Exemple #13
0
def test_initiator_task_view():
    """Test transfer_tasks_view(), which is used to generate the output of the
    pending transfers API, with an initiator task.
    """
    channel_id = factories.UNIT_CHANNEL_ID
    secret = factories.make_secret()
    transfer = factories.create(
        factories.LockedTransferUnsignedStateProperties(secret=secret))
    secrethash = transfer.lock.secrethash
    transfer_description = TransferDescriptionWithSecretState(
        token_network_registry_address=factories.
        UNIT_TOKEN_NETWORK_REGISTRY_ADDRESS,
        payment_identifier=transfer.payment_identifier,
        amount=transfer.balance_proof.locked_amount,
        token_network_address=factories.UNIT_TOKEN_NETWORK_ADDRESS,
        initiator=transfer.initiator,
        target=transfer.target,
        secret=secret,
        secrethash=sha256_secrethash(secret),
    )
    transfer_state = InitiatorTransferState(
        route=RouteState(route=[transfer.initiator, transfer.target],
                         forward_channel_id=channel_id),
        transfer_description=transfer_description,
        channel_identifier=channel_id,
        transfer=transfer,
    )
    payment_state = InitiatorPaymentState(
        routes=[], initiator_transfers={secrethash: transfer_state})
    task = InitiatorTask(
        token_network_address=factories.UNIT_TOKEN_NETWORK_ADDRESS,
        manager_state=payment_state)
    payment_mapping = {secrethash: cast(TransferTask, task)}

    view = transfer_tasks_view(payment_mapping)

    assert len(view) == 1
    pending_transfer = view[0]
    assert pending_transfer.get("role") == "initiator"
    balance_proof = transfer.balance_proof
    assert pending_transfer.get("channel_identifier") == str(
        balance_proof.channel_identifier)
    assert pending_transfer.get("locked_amount") == str(
        balance_proof.locked_amount)
    assert pending_transfer.get("transferred_amount") == str(
        balance_proof.transferred_amount)
Exemple #14
0
def test_start_end_attack(token_addresses, raiden_chain, deposit):
    """ An attacker can try to steal tokens from a hub or the last node in a
    path.

    The attacker needs to use two addresses (A1 and A2) and connect both to the
    hub H. Once connected a mediated transfer is initialized from A1 to A2
    through H. Once the node A2 receives the mediated transfer the attacker
    uses the known secret and reveal to close and settle the channel H-A2,
    without revealing the secret to H's raiden node.

    The intention is to make the hub transfer the token but for him to be
    unable to require the token A1."""
    amount = 30

    token = token_addresses[0]
    app0, app1, app2 = raiden_chain  # pylint: disable=unbalanced-tuple-unpacking
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), app0.raiden.default_registry.address, token
    )
    assert token_network_address
    hold_event_handler = app2.raiden.raiden_event_handler

    # the attacker owns app0 and app2 and creates a transfer through app1
    identifier = 1
    target = app2.raiden.address
    secret = Secret(sha3(target))
    secrethash = sha256_secrethash(secret)

    hold_event_handler.hold_secretrequest_for(secrethash=secrethash)

    app0.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=target,
        identifier=identifier,
        secret=secret,
    )

    attack_channel = get_channelstate(app2, app1, token_network_address)
    attack_transfer = None  # TODO
    attack_contract = attack_channel.external_state.netting_channel.address  # type: ignore
    hub_contract = get_channelstate(  # type: ignore
        app1, app0, token_network_address
    ).external_state.netting_channel.address

    # start the settle counter
    attack_balance_proof = attack_transfer.to_balanceproof()  # type: ignore
    attack_channel.netting_channel.channel_close(attack_balance_proof)  # type: ignore

    # wait until the last block to reveal the secret, hopefully we are not
    # missing a block during the test
    assert attack_transfer
    app2.raiden.proxy_manager.wait_until_block(
        target_block_number=attack_transfer.lock.expiration - 1
    )

    # since the attacker knows the secret he can net the lock
    # <the commented code below is left for documentation purposes>
    # attack_channel.netting_channel.unlock(
    #     UnlockProofState(unlock_proof, attack_transfer.lock, secret)
    # )
    # XXX: verify that the secret was publicized

    # at this point the hub might not know the secret yet, and won't be able to
    # claim the token from the channel A1 - H

    # the attacker settles the contract
    app2proxymanager = app2.raiden.proxy_manager
    app2proxymanager.wait_until_block(
        target_block_number=app2proxymanager.client.block_number() + 1
    )

    attack_channel.netting_channel.settle(token, attack_contract)

    # at this point the attacker has the "stolen" funds
    attack_contract = app2.raiden.proxy_manager.token_hashchannel[token][attack_contract]
    assert attack_contract.participants[app2.raiden.address]["netted"] == deposit + amount
    assert attack_contract.participants[app1.raiden.address]["netted"] == deposit - amount

    # and the hub's channel A1-H doesn't
    hub_contract = app1.raiden.proxy_manager.token_hashchannel[token][hub_contract]
    assert hub_contract.participants[app0.raiden.address]["netted"] == deposit
    assert hub_contract.participants[app1.raiden.address]["netted"] == deposit

    # to mitigate the attack the Hub _needs_ to use a lower expiration for the
    # locked transfer between H-A2 than A1-H. For A2 to acquire the token
    # it needs to make the secret public in the blockchain so it publishes the
    # secret through an event and the Hub is able to require its funds
    app1proxymanager = app1.raiden.proxy_manager
    app1proxymanager.wait_until_block(
        target_block_number=app1proxymanager.client.block_number() + 1
    )

    # XXX: verify that the Hub has found the secret, close and settle the channel

    # the hub has acquired its token
    hub_contract = app1.raiden.proxy_manager.token_hashchannel[token][hub_contract]
    assert hub_contract.participants[app0.raiden.address]["netted"] == deposit + amount
    assert hub_contract.participants[app1.raiden.address]["netted"] == deposit - amount
Exemple #15
0
    def __post_init__(self) -> None:
        super().__post_init__()
        typecheck(self.transfer, LockedTransferSignedState)

        object.__setattr__(self, "secrethash", sha256_secrethash(self.secret))
Exemple #16
0
 def __post_init__(self) -> None:
     object.__setattr__(self, "secrethash", sha256_secrethash(self.secret))
Exemple #17
0
 def __repr__(self) -> str:
     secrethash = sha256_secrethash(self.secret)
     return "ContractSendSecretReveal(secrethash={} triggered_by_block_hash={})".format(
         to_hex(secrethash), to_hex(self.triggered_by_block_hash)
     )
Exemple #18
0
 def __post_init__(self) -> None:
     if self.secrethash == EMPTY_SECRETHASH and self.secret:
         self.secrethash = sha256_secrethash(self.secret)
Exemple #19
0
def test_register_secret_happy_path(web3: Web3,
                                    secret_registry_proxy: SecretRegistry,
                                    contract_manager: ContractManager) -> None:
    """Test happy path of SecretRegistry with a single secret.

    Test that `register_secret` changes the smart contract state by registering
    the secret, this can be verified by the block height and the existence of
    the SecretRegistered event.
    """
    secret = make_secret()
    secrethash = sha256_secrethash(secret)
    secret_unregistered = make_secret()
    secrethash_unregistered = sha256_secrethash(secret_unregistered)

    secret_registered_filter = secret_registry_proxy.secret_registered_filter(
        GENESIS_BLOCK_NUMBER)

    assert not secret_registry_proxy.is_secret_registered(
        secrethash=secrethash, block_identifier="latest"
    ), "Test setup is invalid, secret must be unknown"
    assert not secret_registry_proxy.is_secret_registered(
        secrethash=secrethash_unregistered, block_identifier="latest"
    ), "Test setup is invalid, secret must be unknown"

    proxy_manager = ProxyManager(
        rpc_client=secret_registry_proxy.client,
        contract_manager=contract_manager,
        metadata=ProxyManagerMetadata(
            token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER,
            filters_start_at=GENESIS_BLOCK_NUMBER,
        ),
    )
    proxy_manager.wait_until_block(BlockNumber(STATE_PRUNING_AFTER_BLOCKS + 1))

    with pytest.raises(NoStateForBlockIdentifier):
        secret_registry_proxy.is_secret_registered(
            secrethash=secrethash_unregistered, block_identifier=0)

    secret_registry_proxy.register_secret(secret=secret)

    logs = [
        secret_registry_proxy.proxy.decode_event(encoded_log) for encoded_log
        in secret_registered_filter.get_new_entries(web3.eth.blockNumber)
    ]
    secret_registered = must_have_event(logs, {
        "event": "SecretRevealed",
        "args": {
            "secrethash": secrethash
        }
    })

    msg = "SecretRegistry.register_secret returned but the SecretRevealed event was not emitted."
    assert secret_registered, msg

    registered_block = secret_registry_proxy.get_secret_registration_block_by_secrethash(
        secrethash=secrethash, block_identifier="latest")
    msg = (
        "Block height returned by the SecretRegistry.get_secret_registration_block_by_secrethash "
        "does not match the block from the SecretRevealed event.")
    assert secret_registered["blockNumber"] == registered_block, msg

    block = secret_registry_proxy.get_secret_registration_block_by_secrethash(
        secrethash=secrethash_unregistered, block_identifier="latest")
    assert block is None, "The secret that was not registered must not change block height!"
Exemple #20
0
# TODO: Make this configurable. Since in parity this is also a configurable value
STATE_PRUNING_AFTER_BLOCKS = 64
STATE_PRUNING_SAFETY_MARGIN = 8
NO_STATE_QUERY_AFTER_BLOCKS = STATE_PRUNING_AFTER_BLOCKS - STATE_PRUNING_SAFETY_MARGIN

NULL_ADDRESS_BYTES = bytes(20)
NULL_ADDRESS_HEX = to_hex_address(Address(NULL_ADDRESS_BYTES))
NULL_ADDRESS_CHECKSUM = to_checksum_address(Address(NULL_ADDRESS_BYTES))

EMPTY_HASH = BlockHash(bytes(32))
EMPTY_BALANCE_HASH = BalanceHash(bytes(32))
EMPTY_MESSAGE_HASH = AdditionalHash(bytes(32))
EMPTY_SIGNATURE = Signature(bytes(65))
EMPTY_SECRET = Secret(bytes(32))
EMPTY_SECRETHASH = SecretHash(bytes(32))
EMPTY_SECRET_SHA256 = sha256_secrethash(EMPTY_SECRET)
LOCKSROOT_OF_NO_LOCKS = Locksroot(keccak(b""))
EMPTY_LOCKSROOT = Locksroot(bytes(32))
ZERO_TOKENS = TokenAmount(0)

ABSENT_SECRET = Secret(b"")

SECRET_LENGTH = 32
SECRETHASH_LENGTH = 32

RECEIPT_FAILURE_CODE = 0


class EthClient(Enum):
    GETH = "geth"
    PARITY = "parity"
Exemple #21
0
def test_clear_closed_queue(raiden_network: List[App], token_addresses,
                            network_wait):
    """ Closing a channel clears the respective message queue. """
    app0, app1 = raiden_network

    hold_event_handler = app1.raiden.raiden_event_handler
    assert isinstance(hold_event_handler, HoldRaidenEventHandler)

    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    chain_state0 = views.state_from_app(app0)
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state0, app0.raiden.default_registry.address, token_address)
    assert token_network_address
    token_network = views.get_token_network_by_address(chain_state0,
                                                       token_network_address)
    assert token_network

    channel_identifier = get_channelstate(app0, app1,
                                          token_network_address).identifier

    assert (channel_identifier
            in token_network.partneraddresses_to_channelidentifiers[
                app1.raiden.address])

    target = app1.raiden.address
    secret = Secret(keccak(target))
    secrethash = sha256_secrethash(secret)
    hold_event_handler.hold_secretrequest_for(secrethash=secrethash)

    # make an unconfirmed transfer to ensure the nodes have communicated
    amount = PaymentAmount(10)
    payment_identifier = PaymentID(1337)
    app0.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=TargetAddress(target),
        identifier=payment_identifier,
        secret=secret,
    )

    app1.raiden.transport.stop()
    app1.raiden.transport.greenlet.get()

    # make sure to wait until the queue is created
    def has_initiator_events():
        assert app0.raiden.wal, "raiden server must have been started"
        initiator_events = app0.raiden.wal.storage.get_events()
        return search_for_item(initiator_events, SendLockedTransfer, {})

    assert wait_until(has_initiator_events, network_wait)

    # assert the specific queue is present
    chain_state0 = views.state_from_app(app0)
    queues0 = views.get_all_messagequeues(chain_state=chain_state0)
    assert [
        (queue_id, queue) for queue_id, queue in queues0.items()
        if queue_id.recipient == app1.raiden.address and queue_id.
        canonical_identifier.channel_identifier == channel_identifier and queue
    ]

    # A ChannelClose event will be generated, this will be polled by both apps
    RaidenAPI(app0.raiden).channel_close(registry_address, token_address,
                                         app1.raiden.address)

    with block_offset_timeout(app0.raiden, "Could not get close event"):
        waiting.wait_for_close(
            app0.raiden,
            registry_address,
            token_address,
            [channel_identifier],
            app0.raiden.alarm.sleep_time,
        )

    # assert all queues with this partner are gone or empty
    chain_state0 = views.state_from_app(app0)
    queues0 = views.get_all_messagequeues(chain_state=chain_state0)
    assert not [(queue_id, queue) for queue_id, queue in queues0.items()
                if queue_id.recipient == app1.raiden.address and queue]

    chain_state1 = views.state_from_app(app1)
    queues1 = views.get_all_messagequeues(chain_state=chain_state1)
    assert not [(queue_id, queue) for queue_id, queue in queues1.items()
                if queue_id.recipient == app0.raiden.address and queue]
def test_mediated_transfer_with_node_consuming_more_than_allocated_fee(
        raiden_network, number_of_nodes, deposit, token_addresses,
        network_wait):
    """
    Tests a mediator node consuming more fees than allocated.
    Which means that the initiator will not reveal the secret
    to the target.
    """
    app0, app1, app2 = raiden_network
    token_address = token_addresses[0]
    chain_state = views.state_from_app(app0)
    token_network_registry_address = app0.raiden.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state, token_network_registry_address, token_address)
    assert token_network_address
    amount = PaymentAmount(100)
    fee = FeeAmount(5)
    fee_margin = calculate_fee_margin(amount, fee)

    app1_app2_channel_state = views.get_channelstate_by_token_network_and_partner(
        chain_state=views.state_from_raiden(app1.raiden),
        token_network_address=token_network_address,
        partner_address=app2.raiden.address,
    )
    assert app1_app2_channel_state

    # Let app1 consume all of the allocated mediation fee
    app1_app2_channel_state.fee_schedule = FeeScheduleState(
        flat=FeeAmount(fee * 2))

    secret = factories.make_secret(0)
    secrethash = sha256_secrethash(secret)

    wait_message_handler = WaitForMessage()
    app0.raiden.message_handler = wait_message_handler
    secret_request_received = wait_message_handler.wait_for_message(
        SecretRequest, {"secrethash": secrethash})

    def get_best_routes_with_fees(*args, **kwargs):
        routes = get_best_routes_internal(*args, **kwargs)
        for r in routes:
            r.estimated_fee = fee
        return routes

    with patch("raiden.routing.get_best_routes_internal",
               get_best_routes_with_fees):
        app0.raiden.start_mediated_transfer_with_secret(
            token_network_address=token_network_address,
            amount=amount,
            target=app2.raiden.address,
            identifier=1,
            secret=secret,
        )

    app0_app1_channel_state = views.get_channelstate_by_token_network_and_partner(
        chain_state=views.state_from_raiden(app0.raiden),
        token_network_address=token_network_address,
        partner_address=app1.raiden.address,
    )
    assert app0_app1_channel_state

    msg = "App0 should have the transfer in secrethashes_to_lockedlocks"
    assert secrethash in app0_app1_channel_state.our_state.secrethashes_to_lockedlocks, msg

    msg = "App0 should have locked the amount + fee"
    lock_amount = app0_app1_channel_state.our_state.secrethashes_to_lockedlocks[
        secrethash].amount
    assert lock_amount == amount + fee + fee_margin, msg

    secret_request_received.wait()

    app0_chain_state = views.state_from_app(app0)
    initiator_task = cast(
        InitiatorTask,
        app0_chain_state.payment_mapping.secrethashes_to_task[secrethash])

    msg = "App0 should have never revealed the secret"
    transfer_state = initiator_task.manager_state.initiator_transfers[
        secrethash].transfer_state
    assert transfer_state != "transfer_secret_revealed", msg
Exemple #23
0
def test_pending_transfers_endpoint(raiden_network: List[RaidenService],
                                    token_addresses):
    initiator, mediator, target = raiden_network
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_raiden(mediator), mediator.default_registry.address,
        token_address)
    assert token_network_address

    amount_to_send = PaymentAmount(150)
    # Remove when https://github.com/raiden-network/raiden/issues/4982 is tackled
    expected_fee = FeeAmount(
        int(amount_to_send * INTERNAL_ROUTING_DEFAULT_FEE_PERC))
    fee_margin = calculate_fee_margin(amount_to_send, expected_fee)
    # This is 0,4% of ~150, so ~1.2 which gets rounded to 1
    actual_fee = 1
    identifier = PaymentID(42)

    initiator_server = prepare_api_server(initiator)
    mediator_server = prepare_api_server(mediator)
    target_server = prepare_api_server(target)

    target.message_handler = target_wait = WaitForMessage()
    mediator.message_handler = mediator_wait = WaitForMessage()

    secret = factories.make_secret()
    secrethash = sha256_secrethash(secret)

    request = grequests.get(
        api_url_for(mediator_server,
                    "pending_transfers_resource_by_token",
                    token_address=token_address))
    response = request.send().response
    assert response.status_code == 200 and response.content == b"[]"

    target_hold = target.raiden_event_handler
    assert isinstance(
        target_hold,
        HoldRaidenEventHandler), "test app must use HoldRaidenEventHandler"

    target_hold.hold_secretrequest_for(secrethash=secrethash)

    initiator.mediated_transfer_async(
        token_network_address=token_network_address,
        amount=PaymentAmount(amount_to_send - expected_fee - fee_margin),
        target=TargetAddress(target.address),
        identifier=identifier,
        secret=secret,
        route_states=[
            create_route_state_for_route(
                apps=raiden_network,
                token_address=token_address,
                fee_estimate=expected_fee,
            )
        ],
    )

    transfer_arrived = target_wait.wait_for_message(LockedTransfer,
                                                    {"payment_identifier": 42})
    transfer_arrived.wait(timeout=30.0)

    for server in (initiator_server, mediator_server, target_server):
        request = grequests.get(
            api_url_for(server, "pending_transfers_resource"))
        response = request.send().response
        assert response.status_code == 200
        content = json.loads(response.content)
        assert len(content) == 1
        assert content[0]["payment_identifier"] == str(identifier)
        if server == target_server:
            assert content[0]["locked_amount"] == str(amount_to_send -
                                                      actual_fee)
        else:
            assert content[0]["locked_amount"] == str(amount_to_send)
        assert content[0]["token_address"] == to_checksum_address(
            token_address)
        assert content[0]["token_network_address"] == to_checksum_address(
            token_network_address)

    mediator_unlock = mediator_wait.wait_for_message(Unlock, {})
    target_unlock = target_wait.wait_for_message(Unlock, {})
    target_hold.release_secretrequest_for(target, secrethash)
    gevent.joinall({mediator_unlock, target_unlock}, raise_error=True)

    for server in (initiator_server, mediator_server, target_server):
        request = grequests.get(
            api_url_for(server, "pending_transfers_resource"))
        response = request.send().response
        assert response.status_code == 200 and response.content == b"[]"

    request = grequests.get(
        api_url_for(
            initiator_server,
            "pending_transfers_resource_by_token",
            token_address=to_hex(b"notaregisteredtokenn"),
        ))
    response = request.send().response
    assert response.status_code == 404 and b"Token" in response.content

    request = grequests.get(
        api_url_for(
            target_server,
            "pending_transfers_resource_by_token_and_partner",
            token_address=token_address,
            partner_address=to_hex(b"~nonexistingchannel~"),
        ))
    response = request.send().response
    assert response.status_code == 404 and b"Channel" in response.content
Exemple #24
0
def test_settled_lock(token_addresses, raiden_network, deposit):
    """ Any transfer following a secret reveal must update the locksroot, so
    that an attacker cannot reuse a secret to double claim a lock.
    """
    app0, app1 = raiden_network
    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    amount = PaymentAmount(30)
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), app0.raiden.default_registry.address, token_address
    )
    assert token_network_address
    hold_event_handler = app1.raiden.raiden_event_handler

    address0 = app0.raiden.address
    address1 = app1.raiden.address

    deposit0 = deposit
    deposit1 = deposit

    token_proxy = app0.raiden.proxy_manager.token(token_address)
    initial_balance0 = token_proxy.balance_of(address0)
    initial_balance1 = token_proxy.balance_of(address1)
    identifier = 1
    target = app1.raiden.address
    secret = Secret(sha3(target))
    secrethash = sha256_secrethash(secret)

    secret_available = hold_event_handler.hold_secretrequest_for(secrethash=secrethash)

    app0.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=target,
        identifier=identifier,
        secret=secret,
    )

    secret_available.wait()  # wait for the messages to be exchanged

    # Save the pending locks from the pending transfer, used to test the unlock
    channelstate_0_1 = get_channelstate(app0, app1, token_network_address)
    batch_unlock = channel.get_batch_unlock(channelstate_0_1.our_state)
    assert batch_unlock

    hold_event_handler.release_secretrequest_for(app1.raiden, secrethash)

    transfer(
        initiator_app=app0,
        target_app=app1,
        token_address=token_address,
        amount=amount,
        identifier=PaymentID(2),
    )

    RaidenAPI(app1.raiden).channel_close(registry_address, token_address, app0.raiden.address)

    waiting.wait_for_settle(
        app1.raiden,
        app1.raiden.default_registry.address,
        token_address,
        [channelstate_0_1.identifier],
        app1.raiden.alarm.sleep_time,
    )
    current_block = app0.raiden.rpc_client.block_number()

    netting_channel = app1.raiden.proxy_manager.payment_channel(
        canonical_identifier=channelstate_0_1.canonical_identifier
    )

    # The transfer locksroot must not contain the unlocked lock, the
    # unlock must fail.
    with pytest.raises(RaidenUnrecoverableError):
        netting_channel.unlock(
            sender=channelstate_0_1.our_state.address,
            receiver=channelstate_0_1.partner_state.address,
            pending_locks=batch_unlock,
            given_block_identifier=current_block,
        )

    expected_balance0 = initial_balance0 + deposit0 - amount * 2
    expected_balance1 = initial_balance1 + deposit1 + amount * 2

    assert token_proxy.balance_of(address0) == expected_balance0
    assert token_proxy.balance_of(address1) == expected_balance1
Exemple #25
0
def test_batch_unlock(raiden_network, token_addresses, secret_registry_address, deposit):
    """Tests that batch unlock is properly called.

    This test will start a single incomplete transfer, the secret will be
    revealed *on-chain*. The node that receives the tokens has to call unlock,
    the node that doesn't gain anything does nothing.
    """
    alice_app, bob_app = raiden_network
    alice_address = alice_app.raiden.address
    bob_address = bob_app.raiden.address

    token_network_registry_address = alice_app.raiden.default_registry.address
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(alice_app), token_network_registry_address, token_address
    )
    assert token_network_address

    hold_event_handler = bob_app.raiden.raiden_event_handler

    # Take a snapshot early on
    alice_app.raiden.wal.snapshot()

    canonical_identifier = get_channelstate(
        alice_app, bob_app, token_network_address
    ).canonical_identifier

    assert is_channel_registered(alice_app, bob_app, canonical_identifier)
    assert is_channel_registered(bob_app, alice_app, canonical_identifier)

    token_proxy = alice_app.raiden.proxy_manager.token(token_address)
    alice_initial_balance = token_proxy.balance_of(alice_app.raiden.address)
    bob_initial_balance = token_proxy.balance_of(bob_app.raiden.address)

    # Take snapshot before transfer
    alice_app.raiden.wal.snapshot()

    alice_to_bob_amount = 10
    identifier = 1
    secret = Secret(sha3(bob_address))
    secrethash = sha256_secrethash(secret)

    secret_request_event = hold_event_handler.hold_secretrequest_for(secrethash=secrethash)

    alice_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=bob_address,
        identifier=identifier,
        secret=secret,
    )

    secret_request_event.get()  # wait for the messages to be exchanged

    alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    lock = channel.get_lock(alice_bob_channel_state.our_state, secrethash)
    assert lock

    # This is the current state of the protocol:
    #
    #    A -> B LockedTransfer
    #    B -> A SecretRequest
    #    - protocol didn't continue
    assert_synced_channel_state(
        token_network_address, alice_app, deposit, [lock], bob_app, deposit, []
    )

    # Test WAL restore to return the latest channel state
    alice_app.raiden.wal.snapshot()
    our_balance_proof = alice_bob_channel_state.our_state.balance_proof
    restored_channel_state = channel_state_until_state_change(
        raiden=alice_app.raiden,
        canonical_identifier=alice_bob_channel_state.canonical_identifier,
        state_change_identifier=HIGH_STATECHANGE_ULID,
    )
    assert restored_channel_state
    our_restored_balance_proof = restored_channel_state.our_state.balance_proof
    assert our_balance_proof == our_restored_balance_proof

    # Close the channel before revealing the secret off-chain. This will leave
    # a pending lock in the channel which has to be unlocked on-chain.
    #
    # The token network will emit a ChannelClose event, this will be polled by
    # both apps and each must start a task for calling settle.
    RaidenAPI(bob_app.raiden).channel_close(
        token_network_registry_address, token_address, alice_app.raiden.address
    )

    # The secret has to be registered manually because Bob never learned the
    # secret. The test is holding the SecretRequest to ensure the off-chain
    # unlock will not happen and the channel is closed with a pending lock.
    #
    # Alternatives would be to hold the unlock messages, or to stop and restart
    # the apps after the channel is closed.
    secret_registry_proxy = alice_app.raiden.proxy_manager.secret_registry(secret_registry_address)
    secret_registry_proxy.register_secret(secret=secret)

    msg = (
        "The lock must still be part of the node state for the test to proceed, "
        "otherwise there is not unlock to be done."
    )
    assert lock, msg

    msg = (
        "The secret must be registered before the lock expires, in order for "
        "the unlock to happen on-chain. Otherwise the test will fail on the "
        "expected balances."
    )
    assert lock.expiration > alice_app.raiden.get_block_number(), msg
    assert lock.secrethash == sha256_secrethash(secret)

    waiting.wait_for_settle(
        alice_app.raiden,
        token_network_registry_address,
        token_address,
        [alice_bob_channel_state.identifier],
        alice_app.raiden.alarm.sleep_time,
    )

    msg = "The channel_state must not have been cleared, one of the ends has pending locks to do."
    assert is_channel_registered(alice_app, bob_app, canonical_identifier), msg
    assert is_channel_registered(bob_app, alice_app, canonical_identifier), msg

    msg = (
        "Timeout while waiting for the unlock to be mined. This may happen if "
        "transaction is rejected, not mined, or the node's alarm task is "
        "not running."
    )
    with gevent.Timeout(seconds=30, exception=AssertionError(msg)):
        # Wait for both nodes (Bob and Alice) to see the on-chain unlock
        wait_for_batch_unlock(
            app=alice_app,
            token_network_address=token_network_address,
            receiver=bob_address,
            sender=alice_address,
        )
        wait_for_batch_unlock(
            app=bob_app,
            token_network_address=token_network_address,
            receiver=bob_address,
            sender=alice_address,
        )

    msg = (
        "The nodes have done the unlock, and both ends have seen it, now the "
        "channel must be cleared"
    )
    assert not is_channel_registered(alice_app, bob_app, canonical_identifier), msg
    assert not is_channel_registered(bob_app, alice_app, canonical_identifier), msg

    alice_new_balance = alice_initial_balance + deposit - alice_to_bob_amount
    bob_new_balance = bob_initial_balance + deposit + alice_to_bob_amount

    msg = "Unexpected end balance after channel settlement with batch unlock."
    assert token_proxy.balance_of(alice_app.raiden.address) == alice_new_balance, msg
    assert token_proxy.balance_of(bob_app.raiden.address) == bob_new_balance, msg
Exemple #26
0
def test_lock_expiry(raiden_network, token_addresses, deposit):
    """Test lock expiry and removal."""
    alice_app, bob_app = raiden_network
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(alice_app), alice_app.raiden.default_registry.address, token_address
    )
    assert token_network_address

    hold_event_handler = bob_app.raiden.raiden_event_handler
    wait_message_handler = bob_app.raiden.message_handler

    token_network = views.get_token_network_by_address(
        views.state_from_app(alice_app), token_network_address
    )
    assert token_network

    channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    channel_identifier = channel_state.identifier

    assert (
        channel_identifier
        in token_network.partneraddresses_to_channelidentifiers[bob_app.raiden.address]
    )

    alice_to_bob_amount = 10
    identifier = 1
    target = bob_app.raiden.address
    transfer_1_secret = factories.make_secret(0)
    transfer_1_secrethash = sha256_secrethash(transfer_1_secret)
    transfer_2_secret = factories.make_secret(1)
    transfer_2_secrethash = sha256_secrethash(transfer_2_secret)

    hold_event_handler.hold_secretrequest_for(secrethash=transfer_1_secrethash)
    transfer1_received = wait_message_handler.wait_for_message(
        LockedTransfer, {"lock": {"secrethash": transfer_1_secrethash}}
    )
    transfer2_received = wait_message_handler.wait_for_message(
        LockedTransfer, {"lock": {"secrethash": transfer_2_secrethash}}
    )
    remove_expired_lock_received = wait_message_handler.wait_for_message(
        LockExpired, {"secrethash": transfer_1_secrethash}
    )

    alice_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=target,
        identifier=identifier,
        secret=transfer_1_secret,
    )
    transfer1_received.wait()

    alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    lock = channel.get_lock(alice_bob_channel_state.our_state, transfer_1_secrethash)
    assert lock

    # This is the current state of the protocol:
    #
    #    A -> B LockedTransfer
    #    B -> A SecretRequest
    #    - protocol didn't continue
    assert_synced_channel_state(
        token_network_address, alice_app, deposit, [lock], bob_app, deposit, []
    )

    # Verify lock is registered in both channel states
    alice_channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    assert transfer_1_secrethash in alice_channel_state.our_state.secrethashes_to_lockedlocks

    bob_channel_state = get_channelstate(bob_app, alice_app, token_network_address)
    assert transfer_1_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks

    alice_chain_state = views.state_from_raiden(alice_app.raiden)
    assert transfer_1_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task

    remove_expired_lock_received.wait()

    alice_channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    assert transfer_1_secrethash not in alice_channel_state.our_state.secrethashes_to_lockedlocks

    # Verify Bob received the message and processed the LockExpired message
    bob_channel_state = get_channelstate(bob_app, alice_app, token_network_address)
    assert transfer_1_secrethash not in bob_channel_state.partner_state.secrethashes_to_lockedlocks

    alice_chain_state = views.state_from_raiden(alice_app.raiden)
    assert transfer_1_secrethash not in alice_chain_state.payment_mapping.secrethashes_to_task

    # Make another transfer
    alice_to_bob_amount = 10
    identifier = 2

    hold_event_handler.hold_secretrequest_for(secrethash=transfer_2_secrethash)

    alice_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=target,
        identifier=identifier,
        secret=transfer_2_secret,
    )
    transfer2_received.wait()

    # Make sure the other transfer still exists
    alice_chain_state = views.state_from_raiden(alice_app.raiden)
    assert transfer_2_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task

    bob_channel_state = get_channelstate(bob_app, alice_app, token_network_address)
    assert transfer_2_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks
def test_mediated_transfer_messages_out_of_order(  # pylint: disable=unused-argument
        raiden_network, deposit, token_addresses, network_wait):
    """Raiden must properly handle repeated locked transfer messages."""
    app0, app1, app2 = raiden_network

    app1_wait_for_message = WaitForMessage()
    app2_wait_for_message = WaitForMessage()

    app1.raiden.message_handler = app1_wait_for_message
    app2.raiden.message_handler = app2_wait_for_message

    secret = factories.make_secret(0)
    secrethash = sha256_secrethash(secret)

    # Save the messages, these will be processed again
    app1_mediatedtransfer = app1_wait_for_message.wait_for_message(
        LockedTransfer, {"lock": {
            "secrethash": secrethash
        }})
    app2_mediatedtransfer = app2_wait_for_message.wait_for_message(
        LockedTransfer, {"lock": {
            "secrethash": secrethash
        }})
    # Wait until the node receives a reveal secret to redispatch the locked
    # transfer message
    app1_revealsecret = app1_wait_for_message.wait_for_message(
        RevealSecret, {"secret": secret})
    app2_revealsecret = app2_wait_for_message.wait_for_message(
        RevealSecret, {"secret": secret})

    token_address = token_addresses[0]
    chain_state = views.state_from_app(app0)
    token_network_registry_address = app0.raiden.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state, token_network_registry_address, token_address)

    amount = 10
    identifier = 1
    transfer_received = app0.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=amount,
        target=app2.raiden.address,
        identifier=identifier,
        secret=secret,
    )

    # - Wait until reveal secret is received to replay the message
    # - The secret is revealed backwards, app2 should be first
    # - The locked transfer is sent before the secret reveal, so the mediated
    #   transfers async results must be set and `get_nowait` can be used
    app2_revealsecret.get(timeout=network_wait)
    mediated_transfer_msg = app2_mediatedtransfer.get_nowait()
    app2.raiden.message_handler.handle_message_lockedtransfer(
        app2.raiden, mediated_transfer_msg)

    app1_revealsecret.get(timeout=network_wait)
    app1.raiden.message_handler.handle_message_lockedtransfer(
        app1.raiden, app1_mediatedtransfer.get_nowait())

    transfer_received.payment_done.wait()
    with block_timeout_for_transfer_by_secrethash(app1.raiden, secrethash):
        wait_assert(
            assert_succeeding_transfer_invariants,
            token_network_address,
            app0,
            deposit - amount,
            [],
            app1,
            deposit + amount,
            [],
        )

    with block_timeout_for_transfer_by_secrethash(app2.raiden, secrethash):
        wait_assert(
            assert_succeeding_transfer_invariants,
            token_network_address,
            app1,
            deposit - amount,
            [],
            app2,
            deposit + amount,
            [],
        )
Exemple #28
0
def test_batch_unlock_after_restart(raiden_network, token_addresses, deposit):
    """Simulate the case where:
    - A sends B a transfer
    - B sends A a transfer
    - Secrets were never revealed
    - B closes channel
    - A crashes
    - Wait for settle
    - Wait for unlock from B
    - Restart A
    At this point, the current unlock logic will try to unlock
    iff the node gains from unlocking. Which means that the node will try to unlock
    either side. In the above scenario, each node will unlock its side.
    This test makes sure that we do NOT invalidate A's unlock transaction based
    on the ContractReceiveChannelBatchUnlock caused by B's unlock.
    """
    alice_app, bob_app = raiden_network
    registry_address = alice_app.raiden.default_registry.address
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state=views.state_from_app(alice_app),
        token_network_registry_address=alice_app.raiden.default_registry.address,
        token_address=token_address,
    )
    assert token_network_address
    timeout = 10

    token_network = views.get_token_network_by_address(
        chain_state=views.state_from_app(alice_app), token_network_address=token_network_address
    )
    assert token_network

    channel_identifier = get_channelstate(alice_app, bob_app, token_network_address).identifier

    assert (
        channel_identifier
        in token_network.partneraddresses_to_channelidentifiers[bob_app.raiden.address]
    )

    alice_to_bob_amount = 10
    identifier = 1

    alice_transfer_secret = Secret(sha3(alice_app.raiden.address))
    alice_transfer_secrethash = sha256_secrethash(alice_transfer_secret)

    bob_transfer_secret = Secret(sha3(bob_app.raiden.address))
    bob_transfer_secrethash = sha256_secrethash(bob_transfer_secret)

    alice_transfer_hold = bob_app.raiden.raiden_event_handler.hold_secretrequest_for(
        secrethash=alice_transfer_secrethash
    )
    bob_transfer_hold = alice_app.raiden.raiden_event_handler.hold_secretrequest_for(
        secrethash=bob_transfer_secrethash
    )

    alice_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=bob_app.raiden.address,
        identifier=identifier,
        secret=alice_transfer_secret,
    )

    bob_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=alice_app.raiden.address,
        identifier=identifier + 1,
        secret=bob_transfer_secret,
    )

    alice_transfer_hold.wait(timeout=timeout)
    bob_transfer_hold.wait(timeout=timeout)

    alice_bob_channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    alice_lock = channel.get_lock(alice_bob_channel_state.our_state, alice_transfer_secrethash)
    bob_lock = channel.get_lock(alice_bob_channel_state.partner_state, bob_transfer_secrethash)
    assert alice_lock
    assert bob_lock

    # This is the current state of protocol:
    #
    #    A -> B LockedTransfer
    #    - protocol didn't continue
    assert_synced_channel_state(
        token_network_address=token_network_address,
        app0=alice_app,
        balance0=deposit,
        pending_locks0=[alice_lock],
        app1=bob_app,
        balance1=deposit,
        pending_locks1=[bob_lock],
    )

    # A ChannelClose event will be generated, this will be polled by both apps
    # and each must start a task for calling settle
    RaidenAPI(bob_app.raiden).channel_close(
        registry_address=registry_address,
        token_address=token_address,
        partner_address=alice_app.raiden.address,
    )

    # wait for the close transaction to be mined, this is necessary to compute
    # the timeout for the settle
    with gevent.Timeout(timeout):
        waiting.wait_for_close(
            raiden=alice_app.raiden,
            token_network_registry_address=registry_address,
            token_address=token_address,
            channel_ids=[alice_bob_channel_state.identifier],
            retry_timeout=alice_app.raiden.alarm.sleep_time,
        )

    channel_closed = raiden_state_changes_search_for_item(
        bob_app.raiden,
        ContractReceiveChannelClosed,
        {
            "canonical_identifier": {
                "token_network_address": token_network_address,
                "channel_identifier": alice_bob_channel_state.identifier,
            }
        },
    )
    assert isinstance(channel_closed, ContractReceiveChannelClosed)
    settle_max_wait_block = BlockNumber(
        channel_closed.block_number + alice_bob_channel_state.settle_timeout * 2
    )

    settle_timeout = BlockTimeout(
        RuntimeError("settle did not happen"),
        bob_app.raiden,
        settle_max_wait_block,
        alice_app.raiden.alarm.sleep_time,
    )
    with settle_timeout:
        waiting.wait_for_settle(
            raiden=alice_app.raiden,
            token_network_registry_address=registry_address,
            token_address=token_address,
            channel_ids=[alice_bob_channel_state.identifier],
            retry_timeout=alice_app.raiden.alarm.sleep_time,
        )

    with gevent.Timeout(timeout):
        wait_for_batch_unlock(
            app=bob_app,
            token_network_address=token_network_address,
            receiver=alice_bob_channel_state.partner_state.address,
            sender=alice_bob_channel_state.our_state.address,
        )

    alice_app.start()

    with gevent.Timeout(timeout):
        wait_for_batch_unlock(
            app=alice_app,
            token_network_address=token_network_address,
            receiver=alice_bob_channel_state.partner_state.address,
            sender=alice_bob_channel_state.our_state.address,
        )
Exemple #29
0
def test_send_queued_messages(  # pylint: disable=unused-argument
        raiden_network, deposit, token_addresses, network_wait):
    """Test re-sending of undelivered messages on node restart"""
    app0, app1 = raiden_network
    token_address = token_addresses[0]
    chain_state = views.state_from_app(app0)
    token_network_registry_address = app0.raiden.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state, token_network_registry_address, token_address)
    assert token_network_address

    number_of_transfers = 7
    amount_per_transfer = 1
    total_transferred_amount = TokenAmount(amount_per_transfer *
                                           number_of_transfers)

    # Make sure none of the transfers will be sent before the restart
    transfers = []
    for secret_seed in range(number_of_transfers):
        secret = make_secret(secret_seed)
        secrethash = sha256_secrethash(secret)
        transfers.append((create_default_identifier(), amount_per_transfer,
                          secret, secrethash))

        app0.raiden.raiden_event_handler.hold(
            SendLockedTransfer,
            {"transfer": {
                "lock": {
                    "secrethash": secrethash
                }
            }})

    for identifier, amount, secret, _ in transfers:
        app0.raiden.mediated_transfer_async(
            token_network_address=token_network_address,
            amount=amount,
            target=app1.raiden.address,
            identifier=identifier,
            secret=secret,
        )

    app0.stop()

    # Restart the app. The pending transfers must be processed.
    new_transport = MatrixTransport(app0.raiden.config["transport"]["matrix"])
    raiden_event_handler = RaidenEventHandler()
    message_handler = MessageHandler()
    app0_restart = App(
        config=app0.config,
        rpc_client=app0.raiden.rpc_client,
        proxy_manager=app0.raiden.proxy_manager,
        query_start_block=BlockNumber(0),
        default_registry=app0.raiden.default_registry,
        default_secret_registry=app0.raiden.default_secret_registry,
        default_service_registry=app0.raiden.default_service_registry,
        default_one_to_n_address=app0.raiden.default_one_to_n_address,
        default_msc_address=app0.raiden.default_msc_address,
        transport=new_transport,
        raiden_event_handler=raiden_event_handler,
        message_handler=message_handler,
        routing_mode=RoutingMode.PRIVATE,
    )

    del app0
    app0_restart.start()

    # XXX: There is no synchronization among the app and the test, so it is
    # possible between `start` and the check bellow that some of the transfers
    # have completed, making it flaky.
    #
    # Make sure the transfers are in the queue and fail otherwise.
    # chain_state = views.state_from_raiden(app0_restart.raiden)
    # for _, _, _, secrethash in transfers:
    #     msg = "The secrethashes of the pending transfers must be in the queue after a restart."
    #     assert secrethash in chain_state.payment_mapping.secrethashes_to_task, msg

    with watch_for_unlock_failures(*raiden_network):
        exception = RuntimeError(
            "Timeout while waiting for balance update for app0")
        with gevent.Timeout(20, exception=exception):
            waiting.wait_for_payment_balance(
                raiden=app0_restart.raiden,
                token_network_registry_address=token_network_registry_address,
                token_address=token_address,
                partner_address=app1.raiden.address,
                target_address=app1.raiden.address,
                target_balance=total_transferred_amount,
                retry_timeout=network_wait,
            )
        exception = RuntimeError(
            "Timeout while waiting for balance update for app1")
        with gevent.Timeout(20, exception=exception):
            waiting.wait_for_payment_balance(
                raiden=app1.raiden,
                token_network_registry_address=token_network_registry_address,
                token_address=token_address,
                partner_address=app0_restart.raiden.address,
                target_address=app1.raiden.address,
                target_balance=total_transferred_amount,
                retry_timeout=network_wait,
            )

    assert_synced_channel_state(
        token_network_address,
        app0_restart,
        deposit - total_transferred_amount,
        [],
        app1,
        deposit + total_transferred_amount,
        [],
    )
    new_transport.stop()
Exemple #30
0
def test_api_payments_with_resolver(
        api_server_test_instance: APIServer,
        raiden_network,
        token_addresses,
        resolvers,  # pylint: disable=unused-argument
):

    _, app1 = raiden_network
    amount = 100
    identifier = 42
    token_address = token_addresses[0]
    target_address = app1.raiden.address
    secret = factories.make_secret()
    secret_hash = sha256_secrethash(secret)

    our_address = api_server_test_instance.rest_api.raiden_api.address

    payment = {
        "initiator_address": to_checksum_address(our_address),
        "target_address": to_checksum_address(target_address),
        "token_address": to_checksum_address(token_address),
        "amount": str(amount),
        "identifier": str(identifier),
    }

    # payment with secret_hash when both resolver and initiator don't have the secret

    request = grequests.post(
        api_url_for(
            api_server_test_instance,
            "token_target_paymentresource",
            token_address=to_checksum_address(token_address),
            target_address=to_checksum_address(target_address),
        ),
        json={
            "amount": str(amount),
            "identifier": str(identifier),
            "secret_hash": encode_hex(secret_hash),
        },
    )
    response = request.send().response
    assert_proper_response(response, status_code=HTTPStatus.CONFLICT)
    assert payment == payment

    # payment with secret where the resolver doesn't have the secret. Should work.

    request = grequests.post(
        api_url_for(
            api_server_test_instance,
            "token_target_paymentresource",
            token_address=to_checksum_address(token_address),
            target_address=to_checksum_address(target_address),
        ),
        json={
            "amount": str(amount),
            "identifier": str(identifier),
            "secret": encode_hex(secret)
        },
    )
    response = request.send().response
    assert_proper_response(response, status_code=HTTPStatus.OK)
    assert payment == payment

    # payment with secret_hash where the resolver has the secret. Should work.

    secret = Secret(
        decode_hex(
            "0x2ff886d47b156de00d4cad5d8c332706692b5b572adfe35e6d2f65e92906806e"
        ))
    secret_hash = sha256_secrethash(secret)

    request = grequests.post(
        api_url_for(
            api_server_test_instance,
            "token_target_paymentresource",
            token_address=to_checksum_address(token_address),
            target_address=to_checksum_address(target_address),
        ),
        json={
            "amount": str(amount),
            "identifier": str(identifier),
            "secret_hash": encode_hex(secret_hash),
        },
    )
    with watch_for_unlock_failures(*raiden_network):
        response = request.send().response
    assert_proper_response(response, status_code=HTTPStatus.OK)
    assert payment == payment