Example #1
0
def handle_secretreveal(target_state, state_change, channel_state):
    """ Validates and handles a ReceiveSecretReveal state change. """
    valid_secret = state_change.hashlock == target_state.transfer.lock.hashlock

    if valid_secret:
        channel.register_secret(
            channel_state,
            state_change.secret,
            state_change.hashlock,
        )

        transfer = target_state.transfer
        route = target_state.route

        target_state.state = 'reveal_secret'
        target_state.secret = state_change.secret
        reveal = SendRevealSecret(
            transfer.identifier,
            target_state.secret,
            transfer.token,
            route.node_address,
        )

        iteration = TransitionResult(target_state, [reveal])

    else:
        # TODO: event for byzantine behavior
        iteration = TransitionResult(target_state, list())

    return iteration
Example #2
0
def set_secret(state, channelidentifiers_to_channels, secret, secrethash):
    """ Set the secret to all mediated transfers.
    It doesn't matter if the secret was learned through the blockchain or a
    secret reveal message.
    """
    state.secret = secret

    for pair in state.transfers_pair:
        payer_channel = channelidentifiers_to_channels[
            pair.payer_transfer.balance_proof.channel_address
        ]
        channel.register_secret(
            payer_channel,
            secret,
            secrethash,
        )

        payee_channel = channelidentifiers_to_channels[
            pair.payee_transfer.balance_proof.channel_address
        ]
        channel.register_secret(
            payee_channel,
            secret,
            secrethash,
        )
Example #3
0
def set_secret(state, channelidentifiers_to_channels, secret, secrethash):
    """ Set the secret to all mediated transfers.
    It doesn't matter if the secret was learned through the blockchain or a
    secret reveal message.
    """
    state.secret = secret

    for pair in state.transfers_pair:
        payer_channel = channelidentifiers_to_channels[
            pair.payer_transfer.balance_proof.channel_address
        ]
        channel.register_secret(
            payer_channel,
            secret,
            secrethash,
        )

        payee_channel = channelidentifiers_to_channels[
            pair.payee_transfer.balance_proof.channel_address
        ]
        channel.register_secret(
            payee_channel,
            secret,
            secrethash,
        )
Example #4
0
def test_secret_revealed(raiden_chain, deposit, settle_timeout, token_addresses):
    app0, app1, app2 = raiden_chain
    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(app0),
        app0.raiden.default_registry.address,
        token_address,
    )

    amount = 10
    identifier = 1
    secret = pending_mediated_transfer(
        raiden_chain,
        token_network_identifier,
        amount,
        identifier,
    )
    secrethash = sha3(secret)

    gevent.sleep(.1)  # wait for the messages

    channel_state2_1 = get_channelstate(app2, app1, token_network_identifier)

    # the secret hasn't been revealed yet (through messages)

    assert len(channel_state2_1.our_state.secrethashes_to_lockedlocks) == 1
    proofs = list(channel.get_known_unlocks(channel_state2_1.our_state))
    assert not proofs

    channel.register_secret(channel_state2_1, secret, secrethash)

    # Close the channel
    netting_channel_proxy = app2.raiden.chain.netting_channel(channel_state2_1.identifier)
    netting_channel_proxy.channel_close(
        registry_address,
        channel_state2_1.partner_state.balance_proof,
    )

    # Reveal the secret through the blockchain (this needs to emit the
    # SecretRevealed event)
    for unlock_proof in channel.get_known_unlocks(channel_state2_1.partner_state):
        netting_channel_proxy.unlock(unlock_proof)

    settle_expiration = app0.raiden.chain.block_number() + settle_timeout
    wait_until_block(app0.raiden.chain, settle_expiration)

    assert_synched_channel_state(
        token_address,
        app1, deposit - amount, [],
        app2, deposit + amount, [],
    )

    assert_synched_channel_state(
        token_address,
        app0, deposit - amount, [],
        app1, deposit + amount, [],
    )
Example #5
0
def test_channelstate_unlock():
    """The node must call unlock after the channel is settled"""
    our_model1, _ = create_model(70)
    partner_model1, privkey2 = create_model(100)
    channel_state = create_channel_from_models(our_model1, partner_model1)

    lock_amount = 10
    lock_expiration = 100
    lock_secret = sha3(b'test_channelstate_lockedtransfer_overspent')
    lock_secrethash = sha3(lock_secret)
    lock = HashTimeLockState(
        lock_amount,
        lock_expiration,
        lock_secrethash,
    )

    nonce = 1
    transferred_amount = 0
    receive_lockedtransfer = make_receive_transfer_mediated(
        channel_state,
        privkey2,
        nonce,
        transferred_amount,
        lock,
    )

    is_valid, _, msg = channel.handle_receive_lockedtransfer(
        channel_state,
        receive_lockedtransfer,
    )
    assert is_valid, msg

    channel.register_secret(channel_state, lock_secret, lock_secrethash)

    closed_block_number = lock_expiration - channel_state.reveal_timeout - 1
    close_state_change = ContractReceiveChannelClosed(
        channel_state.token_network_identifier,
        channel_state.identifier,
        partner_model1.participant_address,
        closed_block_number,
    )
    iteration = channel.handle_channel_closed(channel_state, close_state_change)
    assert not must_contain_entry(iteration.events, ContractSendChannelBatchUnlock, {})

    settle_block_number = lock_expiration + channel_state.reveal_timeout + 1
    settle_state_change = ContractReceiveChannelSettled(
        channel_state.token_network_identifier,
        channel_state.identifier,
        settle_block_number,
    )
    iteration = channel.handle_channel_settled(
        channel_state,
        settle_state_change,
        settle_block_number,
    )
    assert must_contain_entry(iteration.events, ContractSendChannelBatchUnlock, {})
Example #6
0
def test_secret_revealed(raiden_chain, deposit, settle_timeout, token_addresses):
    app0, app1, app2 = raiden_chain
    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(app0),
        app0.raiden.default_registry.address,
        token_address,
    )

    amount = 10
    identifier = 1
    secret = pending_mediated_transfer(
        raiden_chain,
        token_network_identifier,
        amount,
        identifier,
    )
    secrethash = sha3(secret)

    gevent.sleep(.1)  # wait for the messages

    # The secret hasn't been revealed yet
    channel_state2_1 = get_channelstate(app2, app1, token_network_identifier)
    assert len(channel_state2_1.our_state.secrethashes_to_lockedlocks) == 1

    channel.register_secret(channel_state2_1, secret, secrethash)

    # Close the channel
    # This needs to register the secrets on chain
    netting_channel_proxy = app2.raiden.chain.payment_channel(
        token_network_identifier,
        channel_state2_1.identifier,
    )
    netting_channel_proxy.channel_close(
        registry_address,
        channel_state2_1.partner_state.balance_proof,
    )

    settle_expiration = app0.raiden.chain.block_number() + settle_timeout
    wait_until_block(app0.raiden.chain, settle_expiration)

    assert_synced_channel_state(
        token_address,
        app1, deposit - amount, [],
        app2, deposit + amount, [],
    )

    assert_synced_channel_state(
        token_address,
        app0, deposit - amount, [],
        app1, deposit + amount, [],
    )
Example #7
0
def make_mediated_transfer(
    from_channel,
    partner_channel,
    initiator,
    target,
    lock,
    pkey,
    secret=None,
):
    """ Helper to create and register a mediated transfer from `from_channel` to
    `partner_channel`."""
    payment_identifier = channel.get_next_nonce(from_channel.our_state)
    message_identifier = random.randint(0, UINT64_MAX)

    lockedtransfer = channel.send_lockedtransfer(
        from_channel,
        initiator,
        target,
        lock.amount,
        message_identifier,
        payment_identifier,
        lock.expiration,
        lock.secrethash,
    )
    mediated_transfer_msg = LockedTransfer.from_event(lockedtransfer)

    address = privatekey_to_address(pkey)
    sign_key = PrivateKey(pkey)
    mediated_transfer_msg.sign(sign_key, address)

    # compute the signature
    balance_proof = balanceproof_from_envelope(mediated_transfer_msg)
    lockedtransfer.balance_proof = balance_proof

    # if this fails it's not the right key for the current `from_channel`
    assert mediated_transfer_msg.sender == from_channel.our_state.address
    receive_lockedtransfer = lockedtransfersigned_from_message(
        mediated_transfer_msg)

    channel.handle_receive_lockedtransfer(
        partner_channel,
        receive_lockedtransfer,
    )

    if secret is not None:
        secrethash = sha3(secret)

        channel.register_secret(from_channel, secret, secrethash)
        channel.register_secret(partner_channel, secret, secrethash)

    return mediated_transfer_msg
Example #8
0
def handle_secretreveal(
    target_state: TargetTransferState,
    state_change: ReceiveSecretReveal,
    channel_state: NettingChannelState,
    pseudo_random_generator: random.Random,
):
    """ Validates and handles a ReceiveSecretReveal state change. """
    valid_secret = state_change.secrethash == target_state.transfer.lock.secrethash
    waiting_for_secret = target_state.state == 'secret_request'

    if valid_secret and waiting_for_secret:
        if isinstance(state_change, ReceiveSecretReveal):
            channel.register_secret(
                channel_state,
                state_change.secret,
                state_change.secrethash,
            )
        elif isinstance(state_change, ContractReceiveSecretReveal):
            channel.register_onchain_secret(
                channel_state=channel_state,
                secret=state_change.secret,
                secrethash=state_change.secrethash,
                secret_reveal_block_number=state_change.block_number,
            )
        else:
            assert False, 'Got unexpected StateChange'

        route = target_state.route
        message_identifier = message_identifier_from_prng(
            pseudo_random_generator)
        target_state.state = 'reveal_secret'
        target_state.secret = state_change.secret
        recipient = route.node_address

        # Send the secret reveal message only once, delivery is guaranteed by
        # the transport and not by the state machine
        reveal = SendSecretReveal(
            recipient=recipient,
            channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE,
            message_identifier=message_identifier,
            secret=target_state.secret,
        )

        iteration = TransitionResult(target_state, [reveal])

    else:
        # TODO: event for byzantine behavior
        iteration = TransitionResult(target_state, list())

    return iteration
Example #9
0
def make_mediated_transfer(
        from_channel,
        partner_channel,
        initiator,
        target,
        lock,
        pkey,
        secret=None,
):
    """ Helper to create and register a mediated transfer from `from_channel` to
    `partner_channel`."""
    payment_identifier = channel.get_next_nonce(from_channel.our_state)
    message_identifier = random.randint(0, UINT64_MAX)

    lockedtransfer = channel.send_lockedtransfer(
        from_channel,
        initiator,
        target,
        lock.amount,
        message_identifier,
        payment_identifier,
        lock.expiration,
        lock.secrethash,
    )
    mediated_transfer_msg = LockedTransfer.from_event(lockedtransfer)

    sign_key = PrivateKey(pkey)
    mediated_transfer_msg.sign(sign_key)

    # compute the signature
    balance_proof = balanceproof_from_envelope(mediated_transfer_msg)
    lockedtransfer.balance_proof = balance_proof

    # if this fails it's not the right key for the current `from_channel`
    assert mediated_transfer_msg.sender == from_channel.our_state.address
    receive_lockedtransfer = lockedtransfersigned_from_message(mediated_transfer_msg)

    channel.handle_receive_lockedtransfer(
        partner_channel,
        receive_lockedtransfer,
    )

    if secret is not None:
        secrethash = sha3(secret)

        channel.register_secret(from_channel, secret, secrethash)
        channel.register_secret(partner_channel, secret, secrethash)

    return mediated_transfer_msg
Example #10
0
def test_channelstate_withdraw():
    """Event close must be properly handled if there are no locks to unlock"""
    our_model1, _ = create_model(70)
    partner_model1, privkey2 = create_model(100)
    channel_state = create_channel_from_models(our_model1, partner_model1)
    payment_network_identifier = factories.make_address()

    lock_amount = 10
    lock_expiration = 100
    lock_secret = sha3(b'test_channelstate_lockedtransfer_overspent')
    lock_secrethash = sha3(lock_secret)
    lock = HashTimeLockState(
        lock_amount,
        lock_expiration,
        lock_secrethash,
    )

    nonce = 1
    transferred_amount = 0
    receive_lockedtransfer = make_receive_transfer_mediated(
        channel_state,
        privkey2,
        nonce,
        transferred_amount,
        lock,
    )

    is_valid, _, msg = channel.handle_receive_lockedtransfer(
        channel_state,
        receive_lockedtransfer,
    )
    assert is_valid, msg

    channel.register_secret(channel_state, lock_secret, lock_secrethash)

    # If the channel is closed, withdraw must be done even if the lock is not
    # at risk of expiring
    closed_block_number = lock_expiration - channel_state.reveal_timeout - 1
    state_change = ContractReceiveChannelClosed(
        payment_network_identifier,
        channel_state.token_address,
        channel_state.identifier,
        partner_model1.participant_address,
        closed_block_number,
    )
    iteration = channel.handle_channel_closed(channel_state, state_change)
    assert must_contain_entry(iteration.events, ContractSendChannelWithdraw,
                              {})
Example #11
0
def test_events_for_onchain_secretreveal():
    """ Secret must be registered on-chain when the unsafe region is reached and
    the secret is known.
    """
    amount = 3
    block_number = 10
    expiration = block_number + 30
    initiator = HOP1
    target_address = UNIT_TRANSFER_TARGET

    from_channel = factories.make_channel(
        our_address=target_address,
        partner_address=UNIT_TRANSFER_SENDER,
        partner_balance=amount,
    )
    from_route = factories.route_from_channel(from_channel)

    from_transfer = factories.make_signed_transfer_for(
        from_channel,
        amount,
        initiator,
        target_address,
        expiration,
        UNIT_SECRET,
    )

    channel.handle_receive_lockedtransfer(
        from_channel,
        from_transfer,
    )

    channel.register_secret(from_channel, UNIT_SECRET, UNIT_SECRETHASH)

    safe_to_wait = expiration - from_channel.reveal_timeout - 1
    unsafe_to_wait = expiration - from_channel.reveal_timeout

    state = TargetTransferState(from_route, from_transfer)
    events = target.events_for_onchain_secretreveal(state, from_channel,
                                                    safe_to_wait)
    assert not events

    events = target.events_for_onchain_secretreveal(state, from_channel,
                                                    unsafe_to_wait)
    assert events
    assert isinstance(events[0], ContractSendSecretReveal)
    assert events[0].secret == UNIT_SECRET
Example #12
0
def handle_secretreveal(
    target_state,
    state_change,
    channel_state,
    pseudo_random_generator,
):
    """ Validates and handles a ReceiveSecretReveal state change. """
    valid_secret = state_change.secrethash == target_state.transfer.lock.secrethash

    if valid_secret:
        if isinstance(state_change, ReceiveSecretReveal):
            channel.register_secret(
                channel_state,
                state_change.secret,
                state_change.secrethash,
            )
        elif isinstance(state_change, ContractReceiveSecretReveal):
            channel.register_onchain_secret(
                channel_state,
                state_change.secret,
                state_change.secrethash,
            )
        else:
            assert False, 'Got unexpected StateChange'

        route = target_state.route
        message_identifier = message_identifier_from_prng(
            pseudo_random_generator)
        target_state.state = 'reveal_secret'
        target_state.secret = state_change.secret
        recipient = route.node_address
        queue_name = b'global'
        reveal = SendRevealSecret(
            recipient,
            queue_name,
            message_identifier,
            target_state.secret,
        )

        iteration = TransitionResult(target_state, [reveal])

    else:
        # TODO: event for byzantine behavior
        iteration = TransitionResult(target_state, list())

    return iteration
Example #13
0
def handle_secretreveal(
        target_state,
        state_change,
        channel_state,
        pseudo_random_generator,
):
    """ Validates and handles a ReceiveSecretReveal state change. """
    valid_secret = state_change.secrethash == target_state.transfer.lock.secrethash

    if valid_secret:
        if isinstance(state_change, ReceiveSecretReveal):
            channel.register_secret(
                channel_state,
                state_change.secret,
                state_change.secrethash,
            )
        elif isinstance(state_change, ContractReceiveSecretReveal):
            channel.register_onchain_secret(
                channel_state,
                state_change.secret,
                state_change.secrethash,
            )
        else:
            assert False, 'Got unexpected StateChange'

        route = target_state.route
        message_identifier = message_identifier_from_prng(pseudo_random_generator)
        target_state.state = 'reveal_secret'
        target_state.secret = state_change.secret
        recipient = route.node_address
        queue_name = b'global'
        reveal = SendRevealSecret(
            recipient,
            queue_name,
            message_identifier,
            target_state.secret,
        )

        iteration = TransitionResult(target_state, [reveal])

    else:
        # TODO: event for byzantine behavior
        iteration = TransitionResult(target_state, list())

    return iteration
Example #14
0
def test_events_for_onchain_secretreveal():
    """ Secret must be registered on-chain when the unsafe region is reached and
    the secret is known.
    """
    amount = 3
    block_number = 10
    expiration = block_number + 30
    initiator = HOP1
    target_address = UNIT_TRANSFER_TARGET

    from_channel = factories.make_channel(
        our_address=target_address,
        partner_address=UNIT_TRANSFER_SENDER,
        partner_balance=amount,
    )
    from_route = factories.route_from_channel(from_channel)

    from_transfer = factories.make_signed_transfer_for(
        from_channel,
        amount,
        initiator,
        target_address,
        expiration,
        UNIT_SECRET,
    )

    channel.handle_receive_lockedtransfer(
        from_channel,
        from_transfer,
    )

    channel.register_secret(from_channel, UNIT_SECRET, UNIT_SECRETHASH)

    safe_to_wait = expiration - from_channel.reveal_timeout - 1
    unsafe_to_wait = expiration - from_channel.reveal_timeout

    state = TargetTransferState(from_route, from_transfer)
    events = target.events_for_onchain_secretreveal(state, from_channel, safe_to_wait)
    assert not events

    events = target.events_for_onchain_secretreveal(state, from_channel, unsafe_to_wait)
    assert events
    assert isinstance(events[0], ContractSendSecretReveal)
    assert events[0].secret == UNIT_SECRET
Example #15
0
def handle_secretreveal(
    target_state,
    state_change,
    channel_state,
    pseudo_random_generator,
):
    """ Validates and handles a ReceiveSecretReveal state change. """
    valid_secret = state_change.secrethash == target_state.transfer.lock.secrethash

    if valid_secret:
        channel.register_secret(
            channel_state,
            state_change.secret,
            state_change.secrethash,
        )

        transfer = target_state.transfer
        route = target_state.route

        message_identifier = message_identifier_from_prng(
            pseudo_random_generator)
        target_state.state = 'reveal_secret'
        target_state.secret = state_change.secret
        recipient = route.node_address
        queue_name = 'global'
        reveal = SendRevealSecret(
            recipient,
            queue_name,
            message_identifier,
            target_state.secret,
            transfer.token,
        )

        iteration = TransitionResult(target_state, [reveal])

    else:
        # TODO: event for byzantine behavior
        iteration = TransitionResult(target_state, list())

    return iteration
Example #16
0
def test_channelstate_receive_lockedtransfer():
    """Tests receiving a mediated transfer.

    The transfer is done in three steps:
        - a mediated transfer including a lock in its balance proof is sent
        - the secret is revealed
        - the unlocked balance proof is sent updating the transferred_amount
    """
    our_model1, _ = create_model(70)
    partner_model1, privkey2 = create_model(100)
    channel_state = create_channel_from_models(our_model1, partner_model1)

    # Step 1: Simulate receiving a transfer
    # - The receiver end state doesnt change
    # - The lock must be registered with the sender end
    lock_amount = 30
    lock_expiration = 10
    lock_secret = sha3(b'test_end_state')
    lock_secrethash = sha3(lock_secret)
    lock = HashTimeLockState(
        lock_amount,
        lock_expiration,
        lock_secrethash,
    )

    nonce = 1
    transferred_amount = 0
    receive_lockedtransfer = make_receive_transfer_mediated(
        channel_state,
        privkey2,
        nonce,
        transferred_amount,
        lock,
    )

    is_valid, msg = channel.handle_receive_lockedtransfer(
        channel_state,
        receive_lockedtransfer,
    )
    assert is_valid, msg

    our_model2 = our_model1
    partner_model2 = partner_model1._replace(
        distributable=partner_model1.distributable - lock_amount,
        amount_locked=lock_amount,
        next_nonce=2,
        merkletree_leaves=[lock.lockhash],
    )
    assert_partner_state(channel_state.our_state, channel_state.partner_state, our_model2)
    assert_partner_state(channel_state.partner_state, channel_state.our_state, partner_model2)

    # Step 2: Simulate learning the secret
    # - Registers the secret, this must not change the balance/locked amount
    channel.register_secret(channel_state, lock_secret, lock_secrethash)

    assert_partner_state(channel_state.our_state, channel_state.partner_state, our_model2)
    assert_partner_state(channel_state.partner_state, channel_state.our_state, partner_model2)

    # Step 3: Simulate unlocking the lock
    # - Update the balances
    transferred_amount = 0
    message_identifier = random.randint(0, UINT64_MAX)
    secret_message = Secret(
        message_identifier=message_identifier,
        payment_identifier=1,
        nonce=2,
        channel=channel_state.identifier,
        transferred_amount=transferred_amount + lock_amount,
        locksroot=EMPTY_MERKLE_ROOT,
        secret=lock_secret,
    )
    secret_message.sign(privkey2, channel_state.partner_state.address)

    balance_proof = balanceproof_from_envelope(secret_message)
    unlock_state_change = ReceiveUnlock(
        lock_secret,
        balance_proof,
    )

    is_valid, msg = channel.handle_unlock(channel_state, unlock_state_change)
    assert is_valid, msg

    our_model3 = our_model2._replace(
        balance=our_model2.balance + lock_amount,
        distributable=our_model2.balance + lock_amount,
    )
    partner_model3 = partner_model2._replace(
        balance=partner_model2.balance - lock_amount,
        amount_locked=0,
        next_nonce=3,
        merkletree_leaves=[],
    )

    assert_partner_state(channel_state.our_state, channel_state.partner_state, our_model3)
    assert_partner_state(channel_state.partner_state, channel_state.our_state, partner_model3)