flwr-nightly 1.9.0.dev20240425__tar.gz → 1.9.0.dev20240429__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of flwr-nightly might be problematic. Click here for more details.
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/PKG-INFO +1 -1
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/pyproject.toml +1 -1
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/__init__.py +1 -1
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/app.py +17 -93
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/supernode/__init__.py +2 -0
- flwr_nightly-1.9.0.dev20240429/src/py/flwr/client/supernode/app.py +281 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/crypto/symmetric_encryption.py +15 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/app.py +105 -1
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_server.py +3 -1
- flwr_nightly-1.9.0.dev20240429/src/py/flwr/server/superlink/fleet/grpc_rere/server_interceptor.py +169 -0
- flwr_nightly-1.9.0.dev20240425/src/py/flwr/client/supernode/app.py +0 -119
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/LICENSE +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/README.md +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/app.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/config_utils.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/example.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/new.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/.gitignore.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/README.md.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/__init__.py.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/client.numpy.py.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/client.pytorch.py.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/client.sklearn.py.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/client.tensorflow.py.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/server.numpy.py.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/server.pytorch.py.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/server.sklearn.py.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/server.tensorflow.py.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/code/task.pytorch.py.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/pyproject.numpy.toml.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/pyproject.pytorch.toml.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/pyproject.sklearn.toml.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/new/templates/app/pyproject.tensorflow.toml.tpl +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/run/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/run/run.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/cli/utils.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/client.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/client_app.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/dpfedavg_numpy_client.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/grpc_client/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/grpc_client/connection.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/grpc_rere_client/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/grpc_rere_client/client_interceptor.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/grpc_rere_client/connection.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/heartbeat.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/message_handler/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/message_handler/message_handler.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/message_handler/task_handler.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/centraldp_mods.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/comms_mods.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/localdp_mod.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/secure_aggregation/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/secure_aggregation/secagg_mod.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/secure_aggregation/secaggplus_mod.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/mod/utils.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/node_state.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/node_state_tests.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/numpy_client.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/rest_client/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/rest_client/connection.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/typing.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/address.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/constant.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/context.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/date.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/differential_privacy.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/differential_privacy_constants.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/dp.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/exit_handlers.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/grpc.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/logger.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/message.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/object_ref.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/parameter.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/pyproject.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/record/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/record/configsrecord.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/record/conversion_utils.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/record/metricsrecord.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/record/parametersrecord.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/record/recordset.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/record/typeddict.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/recordset_compat.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/retry_invoker.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/crypto/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/crypto/shamir.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/ndarrays_arithmetic.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/quantization.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/secaggplus_constants.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/secure_aggregation/secaggplus_utils.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/serde.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/telemetry.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/typing.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/common/version.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/driver_pb2.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/driver_pb2.pyi +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/driver_pb2_grpc.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/driver_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/error_pb2.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/error_pb2.pyi +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/error_pb2_grpc.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/error_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/fleet_pb2.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/fleet_pb2.pyi +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/fleet_pb2_grpc.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/fleet_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/node_pb2.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/node_pb2.pyi +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/node_pb2_grpc.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/node_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/recordset_pb2.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/recordset_pb2.pyi +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/recordset_pb2_grpc.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/recordset_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/task_pb2.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/task_pb2.pyi +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/task_pb2_grpc.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/task_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/transport_pb2.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/transport_pb2.pyi +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/transport_pb2_grpc.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/proto/transport_pb2_grpc.pyi +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/py.typed +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/client_manager.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/client_proxy.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/compat/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/compat/app.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/compat/app_utils.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/compat/driver_client_proxy.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/compat/legacy_context.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/criterion.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/driver/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/driver/driver.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/driver/grpc_driver.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/history.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/run_serverapp.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/server.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/server_app.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/server_config.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/aggregate.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/bulyan.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/dp_adaptive_clipping.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/dp_fixed_clipping.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/dpfedavg_adaptive.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/dpfedavg_fixed.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fault_tolerant_fedavg.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedadagrad.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedadam.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedavg.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedavg_android.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedavgm.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedmedian.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedopt.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedprox.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedtrimmedavg.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedxgb_bagging.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedxgb_cyclic.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedxgb_nn_avg.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/fedyogi.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/krum.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/qfedavg.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/strategy/strategy.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/driver/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/driver/driver_grpc.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/driver/driver_servicer.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/grpc_bidi/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/grpc_bidi/flower_service_servicer.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_bridge.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/grpc_bidi/grpc_client_proxy.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/grpc_rere/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/grpc_rere/fleet_servicer.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/message_handler/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/message_handler/message_handler.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/rest_rere/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/rest_rere/rest_api.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/vce/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/vce/backend/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/vce/backend/backend.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/vce/backend/raybackend.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/fleet/vce/vce_api.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/state/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/state/in_memory_state.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/state/sqlite_state.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/state/state.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/state/state_factory.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/superlink/state/utils.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/typing.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/utils/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/utils/tensorboard.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/utils/validator.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/workflow/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/workflow/constant.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/workflow/default_workflows.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/workflow/secure_aggregation/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/workflow/secure_aggregation/secagg_workflow.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/server/workflow/secure_aggregation/secaggplus_workflow.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/simulation/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/simulation/app.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/simulation/ray_transport/__init__.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/simulation/ray_transport/ray_actor.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/simulation/ray_transport/ray_client_proxy.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/simulation/ray_transport/utils.py +0 -0
- {flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/simulation/run_simulation.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
6
|
name = "flwr-nightly"
|
|
7
|
-
version = "1.9.0.
|
|
7
|
+
version = "1.9.0.dev20240429"
|
|
8
8
|
description = "Flower: A Friendly Federated Learning Framework"
|
|
9
9
|
license = "Apache-2.0"
|
|
10
10
|
authors = ["The Flower Authors <hello@flower.ai>"]
|
{flwr_nightly-1.9.0.dev20240425 → flwr_nightly-1.9.0.dev20240429}/src/py/flwr/client/__init__.py
RENAMED
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
"""Flower client."""
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
from .app import run_client_app as run_client_app
|
|
19
18
|
from .app import start_client as start_client
|
|
20
19
|
from .app import start_numpy_client as start_numpy_client
|
|
21
20
|
from .client import Client as Client
|
|
22
21
|
from .client_app import ClientApp as ClientApp
|
|
23
22
|
from .numpy_client import NumPyClient as NumPyClient
|
|
23
|
+
from .supernode import run_client_app as run_client_app
|
|
24
24
|
from .supernode import run_supernode as run_supernode
|
|
25
25
|
from .typing import ClientFn as ClientFn
|
|
26
26
|
|
|
@@ -14,13 +14,12 @@
|
|
|
14
14
|
# ==============================================================================
|
|
15
15
|
"""Flower client app."""
|
|
16
16
|
|
|
17
|
-
import argparse
|
|
18
17
|
import sys
|
|
19
18
|
import time
|
|
20
19
|
from logging import DEBUG, ERROR, INFO, WARN
|
|
21
|
-
from pathlib import Path
|
|
22
20
|
from typing import Callable, ContextManager, Optional, Tuple, Type, Union
|
|
23
21
|
|
|
22
|
+
from cryptography.hazmat.primitives.asymmetric import ec
|
|
24
23
|
from grpc import RpcError
|
|
25
24
|
|
|
26
25
|
from flwr.client.client import Client
|
|
@@ -36,10 +35,8 @@ from flwr.common.constant import (
|
|
|
36
35
|
TRANSPORT_TYPES,
|
|
37
36
|
ErrorCode,
|
|
38
37
|
)
|
|
39
|
-
from flwr.common.exit_handlers import register_exit_handlers
|
|
40
38
|
from flwr.common.logger import log, warn_deprecated_feature
|
|
41
39
|
from flwr.common.message import Error
|
|
42
|
-
from flwr.common.object_ref import load_app, validate
|
|
43
40
|
from flwr.common.retry_invoker import RetryInvoker, exponential
|
|
44
41
|
|
|
45
42
|
from .grpc_client.connection import grpc_connection
|
|
@@ -47,94 +44,6 @@ from .grpc_rere_client.connection import grpc_request_response
|
|
|
47
44
|
from .message_handler.message_handler import handle_control_message
|
|
48
45
|
from .node_state import NodeState
|
|
49
46
|
from .numpy_client import NumPyClient
|
|
50
|
-
from .supernode.app import parse_args_run_client_app
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
def run_client_app() -> None:
|
|
54
|
-
"""Run Flower client app."""
|
|
55
|
-
log(INFO, "Long-running Flower client starting")
|
|
56
|
-
|
|
57
|
-
event(EventType.RUN_CLIENT_APP_ENTER)
|
|
58
|
-
|
|
59
|
-
args = _parse_args_run_client_app().parse_args()
|
|
60
|
-
|
|
61
|
-
# Obtain certificates
|
|
62
|
-
if args.insecure:
|
|
63
|
-
if args.root_certificates is not None:
|
|
64
|
-
sys.exit(
|
|
65
|
-
"Conflicting options: The '--insecure' flag disables HTTPS, "
|
|
66
|
-
"but '--root-certificates' was also specified. Please remove "
|
|
67
|
-
"the '--root-certificates' option when running in insecure mode, "
|
|
68
|
-
"or omit '--insecure' to use HTTPS."
|
|
69
|
-
)
|
|
70
|
-
log(
|
|
71
|
-
WARN,
|
|
72
|
-
"Option `--insecure` was set. "
|
|
73
|
-
"Starting insecure HTTP client connected to %s.",
|
|
74
|
-
args.server,
|
|
75
|
-
)
|
|
76
|
-
root_certificates = None
|
|
77
|
-
else:
|
|
78
|
-
# Load the certificates if provided, or load the system certificates
|
|
79
|
-
cert_path = args.root_certificates
|
|
80
|
-
if cert_path is None:
|
|
81
|
-
root_certificates = None
|
|
82
|
-
else:
|
|
83
|
-
root_certificates = Path(cert_path).read_bytes()
|
|
84
|
-
log(
|
|
85
|
-
DEBUG,
|
|
86
|
-
"Starting secure HTTPS client connected to %s "
|
|
87
|
-
"with the following certificates: %s.",
|
|
88
|
-
args.server,
|
|
89
|
-
cert_path,
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
log(
|
|
93
|
-
DEBUG,
|
|
94
|
-
"Flower will load ClientApp `%s`",
|
|
95
|
-
getattr(args, "client-app"),
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
client_app_dir = args.dir
|
|
99
|
-
if client_app_dir is not None:
|
|
100
|
-
sys.path.insert(0, client_app_dir)
|
|
101
|
-
|
|
102
|
-
app_ref: str = getattr(args, "client-app")
|
|
103
|
-
valid, error_msg = validate(app_ref)
|
|
104
|
-
if not valid and error_msg:
|
|
105
|
-
raise LoadClientAppError(error_msg) from None
|
|
106
|
-
|
|
107
|
-
def _load() -> ClientApp:
|
|
108
|
-
client_app = load_app(app_ref, LoadClientAppError)
|
|
109
|
-
|
|
110
|
-
if not isinstance(client_app, ClientApp):
|
|
111
|
-
raise LoadClientAppError(
|
|
112
|
-
f"Attribute {app_ref} is not of type {ClientApp}",
|
|
113
|
-
) from None
|
|
114
|
-
|
|
115
|
-
return client_app
|
|
116
|
-
|
|
117
|
-
_start_client_internal(
|
|
118
|
-
server_address=args.server,
|
|
119
|
-
load_client_app_fn=_load,
|
|
120
|
-
transport="rest" if args.rest else "grpc-rere",
|
|
121
|
-
root_certificates=root_certificates,
|
|
122
|
-
insecure=args.insecure,
|
|
123
|
-
max_retries=args.max_retries,
|
|
124
|
-
max_wait_time=args.max_wait_time,
|
|
125
|
-
)
|
|
126
|
-
register_exit_handlers(event_type=EventType.RUN_CLIENT_APP_LEAVE)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def _parse_args_run_client_app() -> argparse.ArgumentParser:
|
|
130
|
-
"""Parse flower-client-app command line arguments."""
|
|
131
|
-
parser = argparse.ArgumentParser(
|
|
132
|
-
description="Start a Flower client app",
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
parse_args_run_client_app(parser=parser)
|
|
136
|
-
|
|
137
|
-
return parser
|
|
138
47
|
|
|
139
48
|
|
|
140
49
|
def _check_actionable_client(
|
|
@@ -165,6 +74,9 @@ def start_client(
|
|
|
165
74
|
root_certificates: Optional[Union[bytes, str]] = None,
|
|
166
75
|
insecure: Optional[bool] = None,
|
|
167
76
|
transport: Optional[str] = None,
|
|
77
|
+
authentication_keys: Optional[
|
|
78
|
+
Tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]
|
|
79
|
+
] = None,
|
|
168
80
|
max_retries: Optional[int] = None,
|
|
169
81
|
max_wait_time: Optional[float] = None,
|
|
170
82
|
) -> None:
|
|
@@ -249,6 +161,7 @@ def start_client(
|
|
|
249
161
|
root_certificates=root_certificates,
|
|
250
162
|
insecure=insecure,
|
|
251
163
|
transport=transport,
|
|
164
|
+
authentication_keys=authentication_keys,
|
|
252
165
|
max_retries=max_retries,
|
|
253
166
|
max_wait_time=max_wait_time,
|
|
254
167
|
)
|
|
@@ -269,6 +182,9 @@ def _start_client_internal(
|
|
|
269
182
|
root_certificates: Optional[Union[bytes, str]] = None,
|
|
270
183
|
insecure: Optional[bool] = None,
|
|
271
184
|
transport: Optional[str] = None,
|
|
185
|
+
authentication_keys: Optional[
|
|
186
|
+
Tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]
|
|
187
|
+
] = None,
|
|
272
188
|
max_retries: Optional[int] = None,
|
|
273
189
|
max_wait_time: Optional[float] = None,
|
|
274
190
|
) -> None:
|
|
@@ -393,6 +309,7 @@ def _start_client_internal(
|
|
|
393
309
|
retry_invoker,
|
|
394
310
|
grpc_max_message_length,
|
|
395
311
|
root_certificates,
|
|
312
|
+
authentication_keys,
|
|
396
313
|
) as conn:
|
|
397
314
|
# pylint: disable-next=W0612
|
|
398
315
|
receive, send, create_node, delete_node, get_run = conn
|
|
@@ -606,7 +523,14 @@ def start_numpy_client(
|
|
|
606
523
|
|
|
607
524
|
def _init_connection(transport: Optional[str], server_address: str) -> Tuple[
|
|
608
525
|
Callable[
|
|
609
|
-
[
|
|
526
|
+
[
|
|
527
|
+
str,
|
|
528
|
+
bool,
|
|
529
|
+
RetryInvoker,
|
|
530
|
+
int,
|
|
531
|
+
Union[bytes, str, None],
|
|
532
|
+
Optional[Tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]],
|
|
533
|
+
],
|
|
610
534
|
ContextManager[
|
|
611
535
|
Tuple[
|
|
612
536
|
Callable[[], Optional[Message]],
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# Copyright 2024 Flower Labs GmbH. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""Flower SuperNode."""
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import sys
|
|
19
|
+
from logging import DEBUG, INFO, WARN
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Callable, Optional, Tuple
|
|
22
|
+
|
|
23
|
+
from cryptography.hazmat.primitives.asymmetric import ec
|
|
24
|
+
from cryptography.hazmat.primitives.serialization import (
|
|
25
|
+
load_ssh_private_key,
|
|
26
|
+
load_ssh_public_key,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
from flwr.client.client_app import ClientApp, LoadClientAppError
|
|
30
|
+
from flwr.common import EventType, event
|
|
31
|
+
from flwr.common.exit_handlers import register_exit_handlers
|
|
32
|
+
from flwr.common.logger import log
|
|
33
|
+
from flwr.common.object_ref import load_app, validate
|
|
34
|
+
from flwr.common.secure_aggregation.crypto.symmetric_encryption import (
|
|
35
|
+
ssh_types_to_elliptic_curve,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
from ..app import _start_client_internal
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def run_supernode() -> None:
|
|
42
|
+
"""Run Flower SuperNode."""
|
|
43
|
+
log(INFO, "Starting Flower SuperNode")
|
|
44
|
+
|
|
45
|
+
event(EventType.RUN_SUPERNODE_ENTER)
|
|
46
|
+
|
|
47
|
+
_ = _parse_args_run_supernode().parse_args()
|
|
48
|
+
|
|
49
|
+
log(
|
|
50
|
+
DEBUG,
|
|
51
|
+
"Flower SuperNode starting...",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Graceful shutdown
|
|
55
|
+
register_exit_handlers(
|
|
56
|
+
event_type=EventType.RUN_SUPERNODE_LEAVE,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def run_client_app() -> None:
|
|
61
|
+
"""Run Flower client app."""
|
|
62
|
+
log(INFO, "Long-running Flower client starting")
|
|
63
|
+
|
|
64
|
+
event(EventType.RUN_CLIENT_APP_ENTER)
|
|
65
|
+
|
|
66
|
+
args = _parse_args_run_client_app().parse_args()
|
|
67
|
+
|
|
68
|
+
root_certificates = _get_certificates(args)
|
|
69
|
+
log(
|
|
70
|
+
DEBUG,
|
|
71
|
+
"Flower will load ClientApp `%s`",
|
|
72
|
+
getattr(args, "client-app"),
|
|
73
|
+
)
|
|
74
|
+
load_fn = _get_load_client_app_fn(args)
|
|
75
|
+
authentication_keys = _try_setup_client_authentication(args)
|
|
76
|
+
|
|
77
|
+
_start_client_internal(
|
|
78
|
+
server_address=args.server,
|
|
79
|
+
load_client_app_fn=load_fn,
|
|
80
|
+
transport="rest" if args.rest else "grpc-rere",
|
|
81
|
+
root_certificates=root_certificates,
|
|
82
|
+
insecure=args.insecure,
|
|
83
|
+
authentication_keys=authentication_keys,
|
|
84
|
+
max_retries=args.max_retries,
|
|
85
|
+
max_wait_time=args.max_wait_time,
|
|
86
|
+
)
|
|
87
|
+
register_exit_handlers(event_type=EventType.RUN_CLIENT_APP_LEAVE)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _get_certificates(args: argparse.Namespace) -> Optional[bytes]:
|
|
91
|
+
"""Load certificates if specified in args."""
|
|
92
|
+
# Obtain certificates
|
|
93
|
+
if args.insecure:
|
|
94
|
+
if args.root_certificates is not None:
|
|
95
|
+
sys.exit(
|
|
96
|
+
"Conflicting options: The '--insecure' flag disables HTTPS, "
|
|
97
|
+
"but '--root-certificates' was also specified. Please remove "
|
|
98
|
+
"the '--root-certificates' option when running in insecure mode, "
|
|
99
|
+
"or omit '--insecure' to use HTTPS."
|
|
100
|
+
)
|
|
101
|
+
log(
|
|
102
|
+
WARN,
|
|
103
|
+
"Option `--insecure` was set. "
|
|
104
|
+
"Starting insecure HTTP client connected to %s.",
|
|
105
|
+
args.server,
|
|
106
|
+
)
|
|
107
|
+
root_certificates = None
|
|
108
|
+
else:
|
|
109
|
+
# Load the certificates if provided, or load the system certificates
|
|
110
|
+
cert_path = args.root_certificates
|
|
111
|
+
if cert_path is None:
|
|
112
|
+
root_certificates = None
|
|
113
|
+
else:
|
|
114
|
+
root_certificates = Path(cert_path).read_bytes()
|
|
115
|
+
log(
|
|
116
|
+
DEBUG,
|
|
117
|
+
"Starting secure HTTPS client connected to %s "
|
|
118
|
+
"with the following certificates: %s.",
|
|
119
|
+
args.server,
|
|
120
|
+
cert_path,
|
|
121
|
+
)
|
|
122
|
+
return root_certificates
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _get_load_client_app_fn(
|
|
126
|
+
args: argparse.Namespace,
|
|
127
|
+
) -> Callable[[], ClientApp]:
|
|
128
|
+
"""Get the load_client_app_fn function."""
|
|
129
|
+
client_app_dir = args.dir
|
|
130
|
+
if client_app_dir is not None:
|
|
131
|
+
sys.path.insert(0, client_app_dir)
|
|
132
|
+
|
|
133
|
+
app_ref: str = getattr(args, "client-app")
|
|
134
|
+
valid, error_msg = validate(app_ref)
|
|
135
|
+
if not valid and error_msg:
|
|
136
|
+
raise LoadClientAppError(error_msg) from None
|
|
137
|
+
|
|
138
|
+
def _load() -> ClientApp:
|
|
139
|
+
client_app = load_app(app_ref, LoadClientAppError)
|
|
140
|
+
|
|
141
|
+
if not isinstance(client_app, ClientApp):
|
|
142
|
+
raise LoadClientAppError(
|
|
143
|
+
f"Attribute {app_ref} is not of type {ClientApp}",
|
|
144
|
+
) from None
|
|
145
|
+
|
|
146
|
+
return client_app
|
|
147
|
+
|
|
148
|
+
return _load
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _parse_args_run_supernode() -> argparse.ArgumentParser:
|
|
152
|
+
"""Parse flower-supernode command line arguments."""
|
|
153
|
+
parser = argparse.ArgumentParser(
|
|
154
|
+
description="Start a Flower SuperNode",
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
parser.add_argument(
|
|
158
|
+
"client-app",
|
|
159
|
+
nargs="?",
|
|
160
|
+
default="",
|
|
161
|
+
help="For example: `client:app` or `project.package.module:wrapper.app`. "
|
|
162
|
+
"This is optional and serves as the default ClientApp to be loaded when "
|
|
163
|
+
"the ServerApp does not specify `fab_id` and `fab_version`. "
|
|
164
|
+
"If not provided, defaults to an empty string.",
|
|
165
|
+
)
|
|
166
|
+
_parse_args_common(parser)
|
|
167
|
+
parser.add_argument(
|
|
168
|
+
"--flwr-dir",
|
|
169
|
+
default=None,
|
|
170
|
+
help="""The path containing installed Flower Apps.
|
|
171
|
+
By default, this value isequal to:
|
|
172
|
+
|
|
173
|
+
- `$FLWR_HOME/` if `$FLWR_HOME` is defined
|
|
174
|
+
- `$XDG_DATA_HOME/.flwr/` if `$XDG_DATA_HOME` is defined
|
|
175
|
+
- `$HOME/.flwr/` in all other cases
|
|
176
|
+
""",
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
return parser
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _parse_args_run_client_app() -> argparse.ArgumentParser:
|
|
183
|
+
"""Parse flower-client-app command line arguments."""
|
|
184
|
+
parser = argparse.ArgumentParser(
|
|
185
|
+
description="Start a Flower client app",
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
parser.add_argument(
|
|
189
|
+
"client-app",
|
|
190
|
+
help="For example: `client:app` or `project.package.module:wrapper.app`",
|
|
191
|
+
)
|
|
192
|
+
_parse_args_common(parser=parser)
|
|
193
|
+
|
|
194
|
+
return parser
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _parse_args_common(parser: argparse.ArgumentParser) -> None:
|
|
198
|
+
parser.add_argument(
|
|
199
|
+
"--insecure",
|
|
200
|
+
action="store_true",
|
|
201
|
+
help="Run the client without HTTPS. By default, the client runs with "
|
|
202
|
+
"HTTPS enabled. Use this flag only if you understand the risks.",
|
|
203
|
+
)
|
|
204
|
+
parser.add_argument(
|
|
205
|
+
"--rest",
|
|
206
|
+
action="store_true",
|
|
207
|
+
help="Use REST as a transport layer for the client.",
|
|
208
|
+
)
|
|
209
|
+
parser.add_argument(
|
|
210
|
+
"--root-certificates",
|
|
211
|
+
metavar="ROOT_CERT",
|
|
212
|
+
type=str,
|
|
213
|
+
help="Specifies the path to the PEM-encoded root certificate file for "
|
|
214
|
+
"establishing secure HTTPS connections.",
|
|
215
|
+
)
|
|
216
|
+
parser.add_argument(
|
|
217
|
+
"--server",
|
|
218
|
+
default="0.0.0.0:9092",
|
|
219
|
+
help="Server address",
|
|
220
|
+
)
|
|
221
|
+
parser.add_argument(
|
|
222
|
+
"--max-retries",
|
|
223
|
+
type=int,
|
|
224
|
+
default=None,
|
|
225
|
+
help="The maximum number of times the client will try to connect to the"
|
|
226
|
+
"server before giving up in case of a connection error. By default,"
|
|
227
|
+
"it is set to None, meaning there is no limit to the number of tries.",
|
|
228
|
+
)
|
|
229
|
+
parser.add_argument(
|
|
230
|
+
"--max-wait-time",
|
|
231
|
+
type=float,
|
|
232
|
+
default=None,
|
|
233
|
+
help="The maximum duration before the client stops trying to"
|
|
234
|
+
"connect to the server in case of connection error. By default, it"
|
|
235
|
+
"is set to None, meaning there is no limit to the total time.",
|
|
236
|
+
)
|
|
237
|
+
parser.add_argument(
|
|
238
|
+
"--dir",
|
|
239
|
+
default="",
|
|
240
|
+
help="Add specified directory to the PYTHONPATH and load Flower "
|
|
241
|
+
"app from there."
|
|
242
|
+
" Default: current working directory.",
|
|
243
|
+
)
|
|
244
|
+
parser.add_argument(
|
|
245
|
+
"--authentication-keys",
|
|
246
|
+
nargs=2,
|
|
247
|
+
metavar=("CLIENT_PRIVATE_KEY", "CLIENT_PUBLIC_KEY"),
|
|
248
|
+
type=str,
|
|
249
|
+
help="Provide two file paths: (1) the client's private "
|
|
250
|
+
"key file, and (2) the client's public key file.",
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def _try_setup_client_authentication(
|
|
255
|
+
args: argparse.Namespace,
|
|
256
|
+
) -> Optional[Tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]]:
|
|
257
|
+
if not args.authentication_keys:
|
|
258
|
+
return None
|
|
259
|
+
|
|
260
|
+
ssh_private_key = load_ssh_private_key(
|
|
261
|
+
Path(args.authentication_keys[0]).read_bytes(),
|
|
262
|
+
None,
|
|
263
|
+
)
|
|
264
|
+
ssh_public_key = load_ssh_public_key(Path(args.authentication_keys[1]).read_bytes())
|
|
265
|
+
|
|
266
|
+
try:
|
|
267
|
+
client_private_key, client_public_key = ssh_types_to_elliptic_curve(
|
|
268
|
+
ssh_private_key, ssh_public_key
|
|
269
|
+
)
|
|
270
|
+
except TypeError:
|
|
271
|
+
sys.exit(
|
|
272
|
+
"The file paths provided could not be read as a private and public "
|
|
273
|
+
"key pair. Client authentication requires an elliptic curve public and "
|
|
274
|
+
"private key pair. Please provide the file paths containing elliptic "
|
|
275
|
+
"curve private and public keys to '--authentication-keys'."
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
return (
|
|
279
|
+
client_private_key,
|
|
280
|
+
client_public_key,
|
|
281
|
+
)
|
|
@@ -117,3 +117,18 @@ def verify_hmac(key: bytes, message: bytes, hmac_value: bytes) -> bool:
|
|
|
117
117
|
return True
|
|
118
118
|
except InvalidSignature:
|
|
119
119
|
return False
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def ssh_types_to_elliptic_curve(
|
|
123
|
+
private_key: serialization.SSHPrivateKeyTypes,
|
|
124
|
+
public_key: serialization.SSHPublicKeyTypes,
|
|
125
|
+
) -> Tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]:
|
|
126
|
+
"""Cast SSH key types to elliptic curve."""
|
|
127
|
+
if isinstance(private_key, ec.EllipticCurvePrivateKey) and isinstance(
|
|
128
|
+
public_key, ec.EllipticCurvePublicKey
|
|
129
|
+
):
|
|
130
|
+
return (private_key, public_key)
|
|
131
|
+
|
|
132
|
+
raise TypeError(
|
|
133
|
+
"The provided key is not an EllipticCurvePrivateKey or EllipticCurvePublicKey"
|
|
134
|
+
)
|
|
@@ -16,15 +16,21 @@
|
|
|
16
16
|
|
|
17
17
|
import argparse
|
|
18
18
|
import asyncio
|
|
19
|
+
import csv
|
|
19
20
|
import importlib.util
|
|
20
21
|
import sys
|
|
21
22
|
import threading
|
|
22
23
|
from logging import ERROR, INFO, WARN
|
|
23
24
|
from os.path import isfile
|
|
24
25
|
from pathlib import Path
|
|
25
|
-
from typing import List, Optional, Tuple
|
|
26
|
+
from typing import List, Optional, Sequence, Set, Tuple
|
|
26
27
|
|
|
27
28
|
import grpc
|
|
29
|
+
from cryptography.hazmat.primitives.asymmetric import ec
|
|
30
|
+
from cryptography.hazmat.primitives.serialization import (
|
|
31
|
+
load_ssh_private_key,
|
|
32
|
+
load_ssh_public_key,
|
|
33
|
+
)
|
|
28
34
|
|
|
29
35
|
from flwr.common import GRPC_MAX_MESSAGE_LENGTH, EventType, event
|
|
30
36
|
from flwr.common.address import parse_address
|
|
@@ -36,6 +42,10 @@ from flwr.common.constant import (
|
|
|
36
42
|
)
|
|
37
43
|
from flwr.common.exit_handlers import register_exit_handlers
|
|
38
44
|
from flwr.common.logger import log
|
|
45
|
+
from flwr.common.secure_aggregation.crypto.symmetric_encryption import (
|
|
46
|
+
public_key_to_bytes,
|
|
47
|
+
ssh_types_to_elliptic_curve,
|
|
48
|
+
)
|
|
39
49
|
from flwr.proto.fleet_pb2_grpc import ( # pylint: disable=E0611
|
|
40
50
|
add_FleetServicer_to_server,
|
|
41
51
|
)
|
|
@@ -51,6 +61,7 @@ from .superlink.fleet.grpc_bidi.grpc_server import (
|
|
|
51
61
|
start_grpc_server,
|
|
52
62
|
)
|
|
53
63
|
from .superlink.fleet.grpc_rere.fleet_servicer import FleetServicer
|
|
64
|
+
from .superlink.fleet.grpc_rere.server_interceptor import AuthenticateServerInterceptor
|
|
54
65
|
from .superlink.fleet.vce import start_vce
|
|
55
66
|
from .superlink.state import StateFactory
|
|
56
67
|
|
|
@@ -354,10 +365,28 @@ def run_superlink() -> None:
|
|
|
354
365
|
sys.exit(f"Fleet IP address ({address_arg}) cannot be parsed.")
|
|
355
366
|
host, port, is_v6 = parsed_address
|
|
356
367
|
address = f"[{host}]:{port}" if is_v6 else f"{host}:{port}"
|
|
368
|
+
|
|
369
|
+
maybe_keys = _try_setup_client_authentication(args, certificates)
|
|
370
|
+
interceptors: Optional[Sequence[grpc.ServerInterceptor]] = None
|
|
371
|
+
if maybe_keys is not None:
|
|
372
|
+
(
|
|
373
|
+
client_public_keys,
|
|
374
|
+
server_private_key,
|
|
375
|
+
server_public_key,
|
|
376
|
+
) = maybe_keys
|
|
377
|
+
interceptors = [
|
|
378
|
+
AuthenticateServerInterceptor(
|
|
379
|
+
client_public_keys,
|
|
380
|
+
server_private_key,
|
|
381
|
+
server_public_key,
|
|
382
|
+
)
|
|
383
|
+
]
|
|
384
|
+
|
|
357
385
|
fleet_server = _run_fleet_api_grpc_rere(
|
|
358
386
|
address=address,
|
|
359
387
|
state_factory=state_factory,
|
|
360
388
|
certificates=certificates,
|
|
389
|
+
interceptors=interceptors,
|
|
361
390
|
)
|
|
362
391
|
grpc_servers.append(fleet_server)
|
|
363
392
|
elif args.fleet_api_type == TRANSPORT_TYPE_VCE:
|
|
@@ -390,6 +419,70 @@ def run_superlink() -> None:
|
|
|
390
419
|
driver_server.wait_for_termination(timeout=1)
|
|
391
420
|
|
|
392
421
|
|
|
422
|
+
def _try_setup_client_authentication(
|
|
423
|
+
args: argparse.Namespace,
|
|
424
|
+
certificates: Optional[Tuple[bytes, bytes, bytes]],
|
|
425
|
+
) -> Optional[Tuple[Set[bytes], ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey]]:
|
|
426
|
+
if not args.require_client_authentication:
|
|
427
|
+
return None
|
|
428
|
+
|
|
429
|
+
if certificates is None:
|
|
430
|
+
sys.exit(
|
|
431
|
+
"Client authentication only works over secure connections. "
|
|
432
|
+
"Please provide certificate paths using '--certificates' when "
|
|
433
|
+
"enabling '--require-client-authentication'."
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
client_keys_file_path = Path(args.require_client_authentication[0])
|
|
437
|
+
if not client_keys_file_path.exists():
|
|
438
|
+
sys.exit(
|
|
439
|
+
"The provided path to the client public keys CSV file does not exist: "
|
|
440
|
+
f"{client_keys_file_path}. "
|
|
441
|
+
"Please provide the CSV file path containing known client public keys "
|
|
442
|
+
"to '--require-client-authentication'."
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
client_public_keys: Set[bytes] = set()
|
|
446
|
+
ssh_private_key = load_ssh_private_key(
|
|
447
|
+
Path(args.require_client_authentication[1]).read_bytes(),
|
|
448
|
+
None,
|
|
449
|
+
)
|
|
450
|
+
ssh_public_key = load_ssh_public_key(
|
|
451
|
+
Path(args.require_client_authentication[2]).read_bytes()
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
try:
|
|
455
|
+
server_private_key, server_public_key = ssh_types_to_elliptic_curve(
|
|
456
|
+
ssh_private_key, ssh_public_key
|
|
457
|
+
)
|
|
458
|
+
except TypeError:
|
|
459
|
+
sys.exit(
|
|
460
|
+
"The file paths provided could not be read as a private and public "
|
|
461
|
+
"key pair. Client authentication requires an elliptic curve public and "
|
|
462
|
+
"private key pair. Please provide the file paths containing elliptic "
|
|
463
|
+
"curve private and public keys to '--require-client-authentication'."
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
with open(client_keys_file_path, newline="", encoding="utf-8") as csvfile:
|
|
467
|
+
reader = csv.reader(csvfile)
|
|
468
|
+
for row in reader:
|
|
469
|
+
for element in row:
|
|
470
|
+
public_key = load_ssh_public_key(element.encode())
|
|
471
|
+
if isinstance(public_key, ec.EllipticCurvePublicKey):
|
|
472
|
+
client_public_keys.add(public_key_to_bytes(public_key))
|
|
473
|
+
else:
|
|
474
|
+
sys.exit(
|
|
475
|
+
"Error: Unable to parse the public keys in the .csv "
|
|
476
|
+
"file. Please ensure that the .csv file contains valid "
|
|
477
|
+
"SSH public keys and try again."
|
|
478
|
+
)
|
|
479
|
+
return (
|
|
480
|
+
client_public_keys,
|
|
481
|
+
server_private_key,
|
|
482
|
+
server_public_key,
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
|
|
393
486
|
def _try_obtain_certificates(
|
|
394
487
|
args: argparse.Namespace,
|
|
395
488
|
) -> Optional[Tuple[bytes, bytes, bytes]]:
|
|
@@ -417,6 +510,7 @@ def _run_fleet_api_grpc_rere(
|
|
|
417
510
|
address: str,
|
|
418
511
|
state_factory: StateFactory,
|
|
419
512
|
certificates: Optional[Tuple[bytes, bytes, bytes]],
|
|
513
|
+
interceptors: Optional[Sequence[grpc.ServerInterceptor]] = None,
|
|
420
514
|
) -> grpc.Server:
|
|
421
515
|
"""Run Fleet API (gRPC, request-response)."""
|
|
422
516
|
# Create Fleet API gRPC server
|
|
@@ -429,6 +523,7 @@ def _run_fleet_api_grpc_rere(
|
|
|
429
523
|
server_address=address,
|
|
430
524
|
max_message_length=GRPC_MAX_MESSAGE_LENGTH,
|
|
431
525
|
certificates=certificates,
|
|
526
|
+
interceptors=interceptors,
|
|
432
527
|
)
|
|
433
528
|
|
|
434
529
|
log(INFO, "Flower ECE: Starting Fleet API (gRPC-rere) on %s", address)
|
|
@@ -606,6 +701,15 @@ def _add_args_common(parser: argparse.ArgumentParser) -> None:
|
|
|
606
701
|
"Flower will just create a state in memory.",
|
|
607
702
|
default=DATABASE,
|
|
608
703
|
)
|
|
704
|
+
parser.add_argument(
|
|
705
|
+
"--require-client-authentication",
|
|
706
|
+
nargs=3,
|
|
707
|
+
metavar=("CLIENT_KEYS", "SERVER_PRIVATE_KEY", "SERVER_PUBLIC_KEY"),
|
|
708
|
+
type=str,
|
|
709
|
+
help="Provide three file paths: (1) a .csv file containing a list of "
|
|
710
|
+
"known client public keys for authentication, (2) the server's private "
|
|
711
|
+
"key file, and (3) the server's public key file.",
|
|
712
|
+
)
|
|
609
713
|
|
|
610
714
|
|
|
611
715
|
def _add_args_driver_api(parser: argparse.ArgumentParser) -> None:
|