Ejemplo n.º 1
0
def set_onchain_secret(state, channelidentifiers_to_channels, secret,
                       secrethash, block_number):
    """ Set the secret to all mediated transfers.

    The secret should have been learned from the secret registry.
    """
    state.secret = secret

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

        payee_channel = channelidentifiers_to_channels[
            pair.payee_transfer.balance_proof.channel_identifier]
        channel.register_onchain_secret(
            channel_state=payee_channel,
            secret=secret,
            secrethash=secrethash,
            secret_reveal_block_number=block_number,
        )
Ejemplo n.º 2
0
def set_onchain_secret(state, channelidentifiers_to_channels, secret, secrethash):
    """ Set the secret to all mediated transfers.

    The secret should have been learned from the secret registry.
    """
    state.secret = secret

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

        payee_channel = channelidentifiers_to_channels[
            pair.payee_transfer.balance_proof.channel_address
        ]
        channel.register_onchain_secret(
            payee_channel,
            secret,
            secrethash,
        )
Ejemplo n.º 3
0
def set_onchain_secret(state, channelidentifiers_to_channels, secret, secrethash):
    """ Set the secret to all mediated transfers.

    The secret should have been learned from the secret registry.
    """
    state.secret = secret

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

        payee_channel = channelidentifiers_to_channels[
            pair.payee_transfer.balance_proof.channel_address
        ]
        channel.register_onchain_secret(
            payee_channel,
            secret,
            secrethash,
        )
Ejemplo n.º 4
0
def handle_onchain_secretreveal(
    initiator_state: InitiatorTransferState,
    state_change: ContractReceiveSecretReveal,
    channel_state: NettingChannelState,
    pseudo_random_generator: random.Random,
    block_number: BlockNumber,
) -> TransitionResult[Optional[InitiatorTransferState]]:
    """ When a secret is revealed on-chain all nodes learn the secret.

    This check the on-chain secret corresponds to the one used by the
    initiator, and if valid a new balance proof is sent to the next hop with
    the current lock removed from the pending locks and the transferred amount
    updated.
    """
    iteration: TransitionResult[Optional[InitiatorTransferState]]
    secret = state_change.secret
    secrethash = initiator_state.transfer_description.secrethash
    is_valid_secret = is_valid_secret_reveal(state_change=state_change,
                                             transfer_secrethash=secrethash)
    is_channel_open = channel.get_status(
        channel_state) == ChannelState.STATE_OPENED
    is_lock_expired = state_change.block_number > initiator_state.transfer.lock.expiration

    is_lock_unlocked = is_valid_secret and not is_lock_expired

    if is_lock_unlocked:
        channel.register_onchain_secret(
            channel_state=channel_state,
            secret=secret,
            secrethash=secrethash,
            secret_reveal_block_number=state_change.block_number,
        )

    lock = initiator_state.transfer.lock
    expired = channel.is_lock_expired(
        end_state=channel_state.our_state,
        lock=lock,
        block_number=block_number,
        lock_expiration_threshold=lock.expiration,
    )

    if is_lock_unlocked and is_channel_open and not expired:
        events = events_for_unlock_lock(
            initiator_state,
            channel_state,
            state_change.secret,
            state_change.secrethash,
            pseudo_random_generator,
            block_number,
        )
        iteration = TransitionResult(None, events)
    else:
        events = list()
        iteration = TransitionResult(initiator_state, events)

    return iteration
Ejemplo n.º 5
0
def test_target_transfer_invalid_if_lock_registered_onchain():
    lock_amount = 7
    block_number = 1
    initiator = factories.HOP6
    pseudo_random_generator = random.Random()

    our_balance = 100
    our_address = factories.make_address()
    partner_balance = 130

    from_channel = factories.make_channel(
        our_address=our_address,
        our_balance=our_balance,
        partner_address=UNIT_TRANSFER_SENDER,
        partner_balance=partner_balance,
    )
    from_route = factories.route_from_channel(from_channel)
    expiration = block_number + from_channel.settle_timeout - from_channel.reveal_timeout

    from_transfer = factories.make_signed_transfer_for(
        from_channel,
        lock_amount,
        initiator,
        our_address,
        expiration,
        UNIT_SECRET,
        identifier=1,
        nonce=1,
    )

    init = ActionInitTarget(
        from_route,
        from_transfer,
    )

    secrethash = from_transfer.lock.secrethash
    # mock register secret on-chain
    from_channel.our_state.secrethashes_to_lockedlocks[
        secrethash] = from_transfer.lock
    channel.register_onchain_secret(
        channel_state=from_channel,
        secret=UNIT_SECRET,
        secrethash=secrethash,
        secret_reveal_block_number=0,
        delete_lock=True,
    )

    init_transition = target.state_transition(
        None,
        init,
        from_channel,
        pseudo_random_generator,
        block_number,
    )
    assert init_transition.new_state is None
Ejemplo n.º 6
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
Ejemplo n.º 7
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
Ejemplo n.º 8
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
Ejemplo n.º 9
0
def handle_onchain_secretreveal(
    target_state: TargetTransferState,
    state_change: ContractReceiveSecretReveal,
    channel_state: NettingChannelState,
):
    """ Validates and handles a ContractReceiveSecretReveal state change. """
    valid_secret = state_change.secrethash == target_state.transfer.lock.secrethash

    if valid_secret:
        channel.register_onchain_secret(
            channel_state=channel_state,
            secret=state_change.secret,
            secrethash=state_change.secrethash,
            secret_reveal_block_number=state_change.block_number,
        )

        target_state.state = 'reveal_secret'
        target_state.secret = state_change.secret

    return TransitionResult(target_state, list())
Ejemplo n.º 10
0
def handle_onchain_secretreveal(
        initiator_state: InitiatorTransferState,
        state_change: ContractReceiveSecretReveal,
        channel_state: NettingChannelState,
) -> TransitionResult:
    """ Validates and handles a ContractReceiveSecretReveal state change. """
    valid_secret = state_change.secrethash == initiator_state.transfer.lock.secrethash

    iteration = TransitionResult(initiator_state, list())
    if valid_secret:
        # Register LockedTransfer in secrethashes_to_onchain_unlockedlocks
        # without removing the LockedTransfer from secrethashes_to_lockedlocks
        channel.register_onchain_secret(
            channel_state=channel_state,
            secret=state_change.secret,
            secrethash=state_change.secrethash,
            delete_lock=False,
        )
        iteration.new_state = initiator_state

    return iteration
Ejemplo n.º 11
0
def handle_onchain_secretreveal(
        target_state: TargetTransferState,
        state_change: ContractReceiveSecretReveal,
        channel_state: NettingChannelState,
):
    """ Validates and handles a ContractReceiveSecretReveal state change. """
    valid_secret = is_valid_secret_reveal(
        state_change=state_change,
        transfer_secrethash=target_state.transfer.lock.secrethash,
        secret=state_change.secret,
    )

    if valid_secret:
        channel.register_onchain_secret(
            channel_state=channel_state,
            secret=state_change.secret,
            secrethash=state_change.secrethash,
            secret_reveal_block_number=state_change.block_number,
        )

        target_state.state = TargetTransferState.ONCHAIN_UNLOCK
        target_state.secret = state_change.secret

    return TransitionResult(target_state, list())
Ejemplo n.º 12
0
def set_onchain_secret(
        state: MediatorTransferState,
        channelidentifiers_to_channels: typing.ChannelMap,
        secret: typing.Secret,
        secrethash: typing.SecretHash,
        block_number: typing.BlockNumber,
) -> typing.List[Event]:
    """ Set the secret to all mediated transfers.

    The secret should have been learned from the secret registry.
    """
    state.secret = secret

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

        payee_channel = channelidentifiers_to_channels[
            pair.payee_transfer.balance_proof.channel_identifier
        ]
        channel.register_onchain_secret(
            channel_state=payee_channel,
            secret=secret,
            secrethash=secrethash,
            secret_reveal_block_number=block_number,
        )

    # Like the off-chain secret reveal, the secret should never be revealed
    # on-chain if there is a waiting transfer.
    if state.waiting_transfer:
        payer_channel = channelidentifiers_to_channels[
            state.waiting_transfer.transfer.balance_proof.channel_identifier
        ]
        channel.register_onchain_secret(
            channel_state=payer_channel,
            secret=secret,
            secrethash=secrethash,
            secret_reveal_block_number=block_number,
        )

        unexpected_reveal = EventUnexpectedSecretReveal(
            secrethash=secrethash,
            reason='The mediator has a waiting transfer.',
        )
        return [unexpected_reveal]

    return list()