def test_sha256_secrethash():
    assert sha256_secrethash(Secret(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(Secret(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 = 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"
    )
Exemple #2
0
    def from_dict(cls, data: Dict[str, Any]) -> 'ContractSendSecretReveal':
        restored = cls(
            expiration=BlockExpiration(int(data['expiration'])),
            secret=Secret(serialization.deserialize_bytes(data['secret'])),
        )

        return restored
Exemple #3
0
 def from_dict(cls, data: Dict[str, Any]) -> "ReceiveSecretReveal":
     instance = cls(
         secret=Secret(deserialize_bytes(data["secret"])),
         sender=to_canonical_address(data["sender"]),
     )
     instance.secrethash = deserialize_bytes(data["secrethash"])
     return instance
Exemple #4
0
 def from_dict(cls, data: Dict[str, Any]) -> "ReceiveTransferRefundCancelRoute":
     instance = cls(
         routes=data["routes"],
         transfer=data["transfer"],
         secret=Secret(deserialize_bytes(data["secret"])),
     )
     return instance
Exemple #5
0
 def from_dict(cls, data: Dict[str, Any]) -> 'ReceiveTransferRefundCancelRoute':
     instance = cls(
         routes=data['routes'],
         transfer=data['transfer'],
         secret=Secret(deserialize_bytes(data['secret'])),
     )
     return instance
Exemple #6
0
def random_secret() -> Secret:
    """ Return a random 32 byte secret except the 0 secret since it's not accepted in the contracts
    """
    while True:
        secret = os.urandom(constants.SECRET_LENGTH)
        if secret != constants.EMPTY_HASH:
            return Secret(secret)
Exemple #7
0
def random_payment_hash_invoice() -> PaymentHashInvoice:
    """ Return a random 32 byte secret except the 0 secret since it's not accepted in the contracts
        """
    while True:
        secret = os.urandom(constants.SECRETHASH_LENGTH)
        if secret != constants.EMPTY_HASH:
            secret = Secret(secret)
            return sha3(secret)
Exemple #8
0
    def from_dict(cls, data: Dict[str, Any]) -> "ContractSendSecretReveal":
        restored = cls(
            expiration=BlockExpiration(int(data["expiration"])),
            secret=Secret(serialization.deserialize_bytes(data["secret"])),
            triggered_by_block_hash=BlockHash(
                deserialize_bytes(data["triggered_by_block_hash"])),
        )

        return restored
Exemple #9
0
    def from_dict(cls, data: Dict[str, Any]) -> 'SendSecretReveal':
        restored = cls(
            recipient=to_canonical_address(data['recipient']),
            channel_identifier=ChannelID(int(data['channel_identifier'])),
            message_identifier=MessageID(int(data['message_identifier'])),
            secret=Secret(serialization.deserialize_bytes(data['secret'])),
        )

        return restored
Exemple #10
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 #11
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 #12
0
    def from_dict(cls, data: Dict[str, Any]) -> 'SendBalanceProof':
        restored = cls(
            recipient=to_canonical_address(data['recipient']),
            channel_identifier=ChannelID(int(data['channel_identifier'])),
            message_identifier=MessageID(int(data['message_identifier'])),
            payment_identifier=PaymentID(int(data['payment_identifier'])),
            token_address=to_canonical_address(data['token_address']),
            secret=Secret(serialization.deserialize_bytes(data['secret'])),
            balance_proof=data['balance_proof'],
        )

        return restored
Exemple #13
0
def message_from_sendevent(send_event, our_address):
    if type(send_event) == SendLockedTransfer:
        message = LockedTransfer.from_event(send_event)
    elif type(send_event) == SendDirectTransfer:
        message = DirectTransfer.from_event(send_event)
    elif type(send_event) == SendRevealSecret:
        message = RevealSecret.from_event(send_event)
    elif type(send_event) == SendBalanceProof:
        message = Secret.from_event(send_event)
    elif type(send_event) == SendSecretRequest:
        message = SecretRequest.from_event(send_event)
    elif type(send_event) == SendRefundTransfer:
        message = RefundTransfer.from_event(send_event)
    elif type(send_event) == SendProcessed:
        message = Processed.from_event(send_event)
    else:
        raise ValueError(f'Unknown event type {send_event}')

    return message
Exemple #14
0
def message_from_sendevent(send_event, our_address):
    if type(send_event) == SendLockedTransfer:
        message = LockedTransfer.from_event(send_event)
    elif type(send_event) == SendDirectTransfer:
        message = DirectTransfer.from_event(send_event)
    elif type(send_event) == SendRevealSecret:
        message = RevealSecret.from_event(send_event)
    elif type(send_event) == SendBalanceProof:
        message = Secret.from_event(send_event)
    elif type(send_event) == SendSecretRequest:
        message = SecretRequest.from_event(send_event)
    elif type(send_event) == SendRefundTransfer:
        message = RefundTransfer.from_event(send_event)
    elif type(send_event) == SendProcessed:
        message = Processed.from_event(send_event)
    else:
        raise ValueError(f'Unknown event type {send_event}')

    return message
Exemple #15
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 #16
0
# Set at 64 since parity's default is 64 and Geth's default is 128
# 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):
Exemple #17
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]
Exemple #18
0
def reveal_secret_with_resolver(
        raiden: "RaidenService", chain_state: ChainState,
        secret_request_event: SendSecretRequest) -> bool:

    resolver_endpoint = raiden.config.resolver_endpoint
    if not resolver_endpoint:
        return False

    log.debug("Using resolver to fetch secret",
              resolver_endpoint=resolver_endpoint)

    assert isinstance(raiden.wal,
                      WriteAheadLog), "RaidenService has not been started"
    current_state = raiden.wal.state_manager.current_state

    if current_state is None:
        return False

    task = current_state.payment_mapping.secrethashes_to_task[
        secret_request_event.secrethash]
    token = task.target_state.transfer.token

    request = {
        "token": to_hex(token),
        "secrethash": to_hex(secret_request_event.secrethash),
        "amount": secret_request_event.amount,
        "payment_identifier": secret_request_event.payment_identifier,
        "payment_sender": to_hex(secret_request_event.recipient),
        "expiration": secret_request_event.expiration,
        "payment_recipient": to_hex(raiden.address),
        "chain_id": chain_state.chain_id,
    }

    # loop until we get a valid response from the resolver or until timeout
    while True:
        current_state = views.state_from_raiden(raiden)

        if secret_request_event.expiration < current_state.block_number:
            log.debug("Stopped using resolver, transfer expired",
                      resolver_endpoint=resolver_endpoint)
            # The locked transfer is expired now, so it makes no sense to continue processing it.
            # When returning `False`, the event handler would contiue processing the events, which
            # is not what is wanted here, so we return `True` to cancel
            return True

        response = None

        try:
            # before calling resolver, update block height
            request["chain_height"] = chain_state.block_number
            response = requests.post(resolver_endpoint, json=request)
        except requests.exceptions.RequestException:
            pass

        # no response means the resolver could not be reached and we should try again
        if response is not None:
            if response.status_code == HTTPStatus.OK:
                # request succeeded so we can break the loop and use the secret
                break
            elif response.status_code == HTTPStatus.SERVICE_UNAVAILABLE:
                # treat SERVICE UNAVAILABLE as if the resolver could not be reached and try again
                pass
            else:
                # on any other status code, treat the request as having failed and return False
                return False
        gevent.sleep(5)

    log.debug("Got secret from resolver, dispatching secret reveal",
              resolver_endpoint=resolver_endpoint)
    state_change = ReceiveSecretReveal(
        sender=secret_request_event.recipient,
        secret=Secret(to_bytes(hexstr=json.loads(response.content)["secret"])),
    )
    raiden.handle_and_track_state_changes([state_change])
    return True
def test_mediated_transfer_calls_pfs(raiden_chain: List[App], token_addresses: List[TokenAddress]):
    app0, app1, app2 = raiden_chain
    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, "Fixture token_addresses don't have correspoding token_network"

    with patch("raiden.routing.query_paths", return_value=([], None)) as patched:

        app0.raiden.start_mediated_transfer_with_secret(
            token_network_address=token_network_address,
            amount=PaymentAmount(10),
            target=TargetAddress(app1.raiden.address),
            identifier=PaymentID(1),
            secret=Secret(b"1" * 32),
        )
        assert not patched.called

        # Setup PFS config
        app0.raiden.config.pfs_config = PFSConfig(
            info=PFSInfo(
                url="mock-address",
                chain_id=app0.raiden.rpc_client.chain_id,
                token_network_registry_address=token_network_registry_address,
                user_deposit_address=factories.make_address(),
                payment_address=factories.make_address(),
                confirmed_block_number=chain_state.block_number,
                message="",
                operator="",
                version="",
                price=TokenAmount(0),
            ),
            maximum_fee=TokenAmount(100),
            iou_timeout=BlockTimeout(100),
            max_paths=5,
        )

        app0.raiden.start_mediated_transfer_with_secret(
            token_network_address=token_network_address,
            amount=PaymentAmount(11),
            target=TargetAddress(app2.raiden.address),
            identifier=PaymentID(2),
            secret=Secret(b"2" * 32),
        )
        assert patched.call_count == 1

        # Mediator should not re-query PFS
        locked_transfer = factories.create(
            factories.LockedTransferProperties(
                amount=TokenAmount(5),
                initiator=factories.HOP1,
                target=TargetAddress(app2.raiden.address),
                sender=factories.HOP1,
                pkey=factories.HOP1_KEY,
                token=token_address,
                canonical_identifier=factories.make_canonical_identifier(
                    token_network_address=token_network_address
                ),
            )
        )
        app0.raiden.on_messages([locked_transfer])
        assert patched.call_count == 1
Exemple #20
0
# Set at 64 since parity's default is 64 and Geth's default is 128
# 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 = to_checksum_address(NULL_ADDRESS_BYTES)

EMPTY_HASH = BlockHash(bytes(32))
EMPTY_BALANCE_HASH = BalanceHash(bytes(32))
EMPTY_MESSAGE_HASH = AdditionalHash(bytes(32))
EMPTY_HASH_KECCAK = keccak(EMPTY_HASH)
EMPTY_SIGNATURE = Signature(bytes(65))
EMPTY_MERKLE_ROOT = Locksroot(bytes(32))
EMPTY_SECRET = Secret(b"")
ZERO_TOKENS = TokenAmount(0)

SECRET_HEXSTRING_LENGTH = len(to_hex(EMPTY_HASH))
SECRETHASH_HEXSTRING_LENGTH = SECRET_HEXSTRING_LENGTH

RECEIPT_FAILURE_CODE = 0


class EthClient(Enum):
    GETH = "geth"
    PARITY = "parity"


ETH_RPC_DEFAULT_PORT = 8545
HTTP_PORT = 80
Exemple #21
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 #22
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 #23
0
def deserialize_secret(data: str) -> Secret:
    return Secret(deserialize_bytes(data))
Exemple #24
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 #25
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
Exemple #26
0
def random_secret() -> Secret:
    """ Return a random 32 byte secret"""
    return Secret(os.urandom(constants.SECRET_LENGTH))
Exemple #27
0
def ishash(data: bytes) -> bool:
    return isinstance(data, bytes) and len(data) == 32 or data is Secret(b"")
def test_pfs_send_unique_capacity_and_fee_updates_during_mediated_transfer(
        raiden_network):
    """
    Tests that PFSCapacityUpdates and PFSFeeUpdates are being
    sent only once with the most recent state change in a batch.
    """
    app0, app1 = raiden_network
    chain_state = views.state_from_app(app0)

    # There have been two PFSCapacityUpdates and two PFSFeeUpdates per channel per node
    assert len(get_messages(app0)) == 4
    # The mediator has two channels
    assert len(get_messages(app1)) == 4

    # Now we create two state_changes (Deposit) regarding the same channel
    # and trigger handle_state_changes() of node0. The expected outcome
    # is that only 1 PFSCapacityUpdate and 1 PFSFeeUpdate is being sent
    # not one per state change
    pfs_fee_update_1_of_app0 = get_messages(app0)[1]
    assert isinstance(pfs_fee_update_1_of_app0, PFSFeeUpdate)
    pfs_capacity_update_2_of_app0 = get_messages(app0)[2]
    assert isinstance(pfs_capacity_update_2_of_app0, PFSCapacityUpdate)
    canonical_identifier = pfs_fee_update_1_of_app0.canonical_identifier
    new_total_deposit_1 = pfs_capacity_update_2_of_app0.other_capacity * 2

    deposit_transaction_1 = TransactionChannelDeposit(
        app1.raiden.address, TokenAmount(new_total_deposit_1),
        chain_state.block_number)
    channel_deposit_1 = ContractReceiveChannelDeposit(
        transaction_hash=make_transaction_hash(),
        canonical_identifier=canonical_identifier,
        deposit_transaction=deposit_transaction_1,
        block_number=chain_state.block_number,
        block_hash=chain_state.block_hash,
        fee_config=MediationFeeConfig(),
    )

    new_total_deposit_2 = new_total_deposit_1 * 2
    deposit_transaction_2 = TransactionChannelDeposit(
        app1.raiden.address, TokenAmount(new_total_deposit_2),
        chain_state.block_number)

    channel_deposit_2 = ContractReceiveChannelDeposit(
        transaction_hash=make_transaction_hash(),
        canonical_identifier=canonical_identifier,
        deposit_transaction=deposit_transaction_2,
        block_number=chain_state.block_number,
        block_hash=chain_state.block_hash,
        fee_config=MediationFeeConfig(),
    )

    state_changes = [channel_deposit_1, channel_deposit_2]

    app0.raiden.handle_state_changes(state_changes=state_changes)

    # Now we should see that app0 send 2 new messages,
    # one PFSCapacityUpdate and one PFSFeeUpdate with
    # the updated amount of the initial amount * 4
    # so sending should only be triggered by the second state change

    pfs_capacity_update_3_of_app0 = get_messages(app0)[4]
    assert isinstance(pfs_capacity_update_3_of_app0, PFSCapacityUpdate)
    assert len(get_messages(app0)) == 6
    assert (pfs_capacity_update_3_of_app0.other_capacity ==
            pfs_capacity_update_2_of_app0.updating_capacity * 4)

    # Now we want to test if this also works with a state_change
    # that triggers only a PFSCapacityUpdate and no PFSFeeUpdate.
    # So at the end we expect 1 more PFSCapacityUpdate in the room.

    lock_secret_1 = keccak(b"test_end_state")
    unlock_message_1 = Unlock(
        chain_id=chain_state.chain_id,
        message_identifier=MessageID(123132),
        payment_identifier=PaymentID(1),
        nonce=Nonce(2),
        token_network_address=canonical_identifier.token_network_address,
        channel_identifier=canonical_identifier.channel_identifier,
        transferred_amount=TokenAmount(400),
        locked_amount=LockedAmount(0),
        locksroot=Locksroot(keccak(b"")),
        secret=Secret(lock_secret_1),
        signature=Signature(bytes(65)),
    )
    unlock_message_1.sign(app1.raiden.signer)
    balance_proof_1 = balanceproof_from_envelope(unlock_message_1)

    unlock_1 = ReceiveUnlock(
        message_identifier=MessageID(5135),
        secret=Secret(lock_secret_1),
        balance_proof=balance_proof_1,
        sender=balance_proof_1.sender,
    )

    lock_secret_2 = keccak(b"test_end_state_again")

    unlock_message_2 = Unlock(
        chain_id=chain_state.chain_id,
        message_identifier=MessageID(223132),
        payment_identifier=PaymentID(2),
        nonce=Nonce(2),
        token_network_address=canonical_identifier.token_network_address,
        channel_identifier=canonical_identifier.channel_identifier,
        transferred_amount=TokenAmount(500),
        locked_amount=LockedAmount(0),
        locksroot=Locksroot(keccak(b"")),
        secret=Secret(lock_secret_2),
        signature=Signature(bytes(65)),
    )

    unlock_message_2.sign(app1.raiden.signer)

    balance_proof_2 = balanceproof_from_envelope(unlock_message_2)

    unlock_2 = ReceiveUnlock(
        message_identifier=MessageID(5135),
        secret=Secret(lock_secret_2),
        balance_proof=balance_proof_2,
        sender=balance_proof_2.sender,
    )

    state_changes_2 = [unlock_1, unlock_2]

    app0.raiden.handle_state_changes(state_changes=state_changes_2)

    assert len(get_messages(app0)) == 7
    assert len([
        x for x in get_messages(app0) if isinstance(x, PFSCapacityUpdate)
    ]) == 4