State machine for a node mediating a transfer.

def state_transition(
        mediator_state: Optional[MediatorTransferState],
        state_change: StateChange,
        channelidentifiers_to_channels: ChannelMap,
        nodeaddresses_to_networkstates: NodeNetworkStateMap,
        pseudo_random_generator: random.Random,
        block_number: BlockNumber,
        block_hash: BlockHash,
) -> TransitionResult[MediatorTransferState]:
    """ State machine for a node mediating a transfer. """
    # pylint: disable=too-many-branches
    # Notes:
    # - A user cannot cancel a mediated transfer after it was initiated, she
    #   may only reject to mediate before hand. This is because the mediator
    #   doesn't control the secret reveal and needs to wait for the lock
    #   expiration before safely discarding the transfer.

    iteration = TransitionResult(mediator_state, list())

    if type(state_change) == ActionInitMediator:
        assert isinstance(state_change, ActionInitMediator), MYPY_ANNOTATION
        if mediator_state is None:
            iteration = handle_init(
                state_change=state_change,
                channelidentifiers_to_channels=channelidentifiers_to_channels,
                nodeaddresses_to_networkstates=nodeaddresses_to_networkstates,
                pseudo_random_generator=pseudo_random_generator,
                block_number=block_number,
            )

    elif type(state_change) == Block:
        assert isinstance(state_change, Block), MYPY_ANNOTATION
        assert mediator_state, 'Block should be accompanied by a valid mediator state'
        iteration = handle_block(
            mediator_state=mediator_state,
            state_change=state_change,
            channelidentifiers_to_channels=channelidentifiers_to_channels,
            pseudo_random_generator=pseudo_random_generator,
        )

    elif type(state_change) == ReceiveTransferRefund:
        assert isinstance(state_change, ReceiveTransferRefund), MYPY_ANNOTATION
        msg = 'ReceiveTransferRefund should be accompanied by a valid mediator state'
        assert mediator_state, msg
        iteration = handle_refundtransfer(
            mediator_state=mediator_state,
            mediator_state_change=state_change,
            channelidentifiers_to_channels=channelidentifiers_to_channels,
            nodeaddresses_to_networkstates=nodeaddresses_to_networkstates,
            pseudo_random_generator=pseudo_random_generator,
            block_number=block_number,
        )

    elif type(state_change) == ReceiveSecretReveal:
        assert isinstance(state_change, ReceiveSecretReveal), MYPY_ANNOTATION
        msg = 'ReceiveSecretReveal should be accompanied by a valid mediator state'
        assert mediator_state, msg
        iteration = handle_offchain_secretreveal(
            mediator_state=mediator_state,
            mediator_state_change=state_change,
            channelidentifiers_to_channels=channelidentifiers_to_channels,
            pseudo_random_generator=pseudo_random_generator,
            block_number=block_number,
            block_hash=block_hash,
        )

    elif type(state_change) == ContractReceiveSecretReveal:
        assert isinstance(state_change, ContractReceiveSecretReveal), MYPY_ANNOTATION
        msg = 'ContractReceiveSecretReveal should be accompanied by a valid mediator state'
        assert mediator_state, msg
        iteration = handle_onchain_secretreveal(
            mediator_state=mediator_state,
            onchain_secret_reveal=state_change,
            channelidentifiers_to_channels=channelidentifiers_to_channels,
            pseudo_random_generator=pseudo_random_generator,
            block_number=block_number,
        )

    elif type(state_change) == ReceiveUnlock:
        assert isinstance(state_change, ReceiveUnlock), MYPY_ANNOTATION
        assert mediator_state, 'ReceiveUnlock should be accompanied by a valid mediator state'
        iteration = handle_unlock(
            mediator_state=mediator_state,
            state_change=state_change,
            channelidentifiers_to_channels=channelidentifiers_to_channels,
        )

    elif type(state_change) == ReceiveLockExpired:
        assert isinstance(state_change, ReceiveLockExpired), MYPY_ANNOTATION
        assert mediator_state, 'ReceiveLockExpired should be accompanied by a valid mediator state'
        iteration = handle_lock_expired(
            mediator_state=mediator_state,
            state_change=state_change,
            channelidentifiers_to_channels=channelidentifiers_to_channels,
            block_number=block_number,
        )
    elif type(state_change) == ActionChangeNodeNetworkState:
        assert isinstance(state_change, ActionChangeNodeNetworkState), MYPY_ANNOTATION
        msg = 'ActionChangeNodeNetworkState should be accompanied by a valid mediator state'
        assert mediator_state, msg
        iteration = handle_node_change_network_state(
            mediator_state=mediator_state,
            state_change=state_change,
            channelidentifiers_to_channels=channelidentifiers_to_channels,
            pseudo_random_generator=pseudo_random_generator,
            block_number=block_number,
        )

    # this is the place for paranoia
    if iteration.new_state is not None:
        assert isinstance(iteration.new_state, MediatorTransferState)
        sanity_check(iteration.new_state, channelidentifiers_to_channels)

    return clear_if_finalized(iteration, channelidentifiers_to_channels)