Showing preview only (1,346K chars total). Download the full file or copy to clipboard to get everything.
Repository: xaynetwork/xaynet
Branch: master
Commit: 3289a3003288
Files: 247
Total size: 1.2 MB
Directory structure:
gitextract_ecf7igk4/
├── .dockerignore
├── .github/
│ ├── codecov.yml
│ ├── dependabot.yml
│ └── workflows/
│ ├── dockercompose-validation.yml
│ ├── dockerfile-validation.yml
│ ├── dockerhub-cleanup.yml
│ ├── dockerhub-master.yml
│ ├── dockerhub-pr-with-parameters.yml
│ ├── dockerhub-release.yml
│ ├── kubernetes-manifests.yml
│ ├── rust-audit-cron.yml
│ ├── rust-next.yml
│ └── rust.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── README.tpl
├── ROADMAP.md
├── bindings/
│ └── python/
│ ├── .gitignore
│ ├── .isort.cfg
│ ├── .pylintrc
│ ├── Cargo.toml
│ ├── README.md
│ ├── examples/
│ │ ├── README.md
│ │ ├── download_global_model.py
│ │ ├── download_global_model_async.py
│ │ ├── hello_world.py
│ │ ├── hello_world_async.py
│ │ ├── keras_house_prices/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── keras_house_prices/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── data_handlers/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── data_handler.py
│ │ │ │ │ └── regression_data.py
│ │ │ │ ├── participant.py
│ │ │ │ └── regressor.py
│ │ │ └── setup.py
│ │ ├── multiple_participants.py
│ │ ├── participate_in_update.py
│ │ └── restore.py
│ ├── migration_guide.md
│ ├── src/
│ │ ├── lib.rs
│ │ └── python_ffi.rs
│ └── xaynet_sdk/
│ ├── __init__.py
│ ├── async_participant.py
│ └── participant.py
├── configs/
│ ├── config.toml
│ └── docker-dev.toml
├── docker/
│ ├── .dev.env
│ ├── Dockerfile
│ └── docker-compose.yml
├── k8s/
│ └── coordinator/
│ ├── base/
│ │ ├── deployment.yaml
│ │ ├── kustomization.yaml
│ │ └── service.yaml
│ └── development/
│ ├── cert-volume-mount.yaml
│ ├── config-volume-mount.yaml
│ ├── config.toml
│ ├── history-limit.yaml
│ ├── ingress.yaml
│ └── kustomization.yaml
├── rust/
│ ├── .gitignore
│ ├── Cargo.toml
│ ├── benches/
│ │ ├── Cargo.toml
│ │ ├── messages/
│ │ │ ├── sum.rs
│ │ │ └── update.rs
│ │ └── models/
│ │ ├── from_primitives.rs
│ │ └── to_primitives.rs
│ ├── examples/
│ │ ├── Cargo.toml
│ │ └── test-drive/
│ │ ├── main.rs
│ │ ├── participant.rs
│ │ └── settings.rs
│ ├── rustfmt.toml
│ ├── xaynet/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ ├── xaynet-analytics/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── controller.rs
│ │ ├── data_combination/
│ │ │ ├── data_combiner.rs
│ │ │ ├── data_points/
│ │ │ │ ├── data_point.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── screen_active_time.rs
│ │ │ │ ├── screen_enter_count.rs
│ │ │ │ ├── was_active_each_past_period.rs
│ │ │ │ └── was_active_past_n_days.rs
│ │ │ └── mod.rs
│ │ ├── database/
│ │ │ ├── analytics_event/
│ │ │ │ ├── adapter.rs
│ │ │ │ ├── data_model.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── repo.rs
│ │ │ ├── common.rs
│ │ │ ├── controller_data/
│ │ │ │ ├── adapter.rs
│ │ │ │ ├── data_model.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── repo.rs
│ │ │ ├── isar.rs
│ │ │ ├── mod.rs
│ │ │ └── screen_route/
│ │ │ ├── adapter.rs
│ │ │ ├── data_model.rs
│ │ │ ├── mod.rs
│ │ │ └── repo.rs
│ │ ├── lib.rs
│ │ └── sender.rs
│ ├── xaynet-core/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── common.rs
│ │ ├── crypto/
│ │ │ ├── encrypt.rs
│ │ │ ├── hash.rs
│ │ │ ├── mod.rs
│ │ │ ├── prng.rs
│ │ │ └── sign.rs
│ │ ├── lib.rs
│ │ ├── mask/
│ │ │ ├── config/
│ │ │ │ ├── mod.rs
│ │ │ │ └── serialization.rs
│ │ │ ├── masking.rs
│ │ │ ├── mod.rs
│ │ │ ├── model.rs
│ │ │ ├── object/
│ │ │ │ ├── mod.rs
│ │ │ │ └── serialization/
│ │ │ │ ├── mod.rs
│ │ │ │ ├── unit.rs
│ │ │ │ └── vect.rs
│ │ │ ├── scalar.rs
│ │ │ └── seed.rs
│ │ ├── message/
│ │ │ ├── message.rs
│ │ │ ├── mod.rs
│ │ │ ├── payload/
│ │ │ │ ├── chunk.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── sum.rs
│ │ │ │ ├── sum2.rs
│ │ │ │ └── update.rs
│ │ │ ├── traits.rs
│ │ │ └── utils/
│ │ │ ├── chunkable_iterator.rs
│ │ │ └── mod.rs
│ │ └── testutils/
│ │ ├── messages.rs
│ │ ├── mod.rs
│ │ └── multipart.rs
│ ├── xaynet-mobile/
│ │ ├── .cargo/
│ │ │ └── config.toml
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ ├── build.rs
│ │ ├── cbindgen.toml
│ │ ├── src/
│ │ │ ├── ffi/
│ │ │ │ ├── config.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── participant.rs
│ │ │ │ └── settings.rs
│ │ │ ├── lib.rs
│ │ │ ├── participant.rs
│ │ │ ├── reqwest_client.rs
│ │ │ └── settings.rs
│ │ ├── tests/
│ │ │ ├── ffi_test.c
│ │ │ └── minunit.h
│ │ └── xaynet_ffi.h
│ ├── xaynet-sdk/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── client.rs
│ │ ├── lib.rs
│ │ ├── message_encoder/
│ │ │ ├── chunker.rs
│ │ │ ├── encoder.rs
│ │ │ └── mod.rs
│ │ ├── settings/
│ │ │ ├── max_message_size.rs
│ │ │ └── mod.rs
│ │ ├── state_machine/
│ │ │ ├── io.rs
│ │ │ ├── mod.rs
│ │ │ ├── phase.rs
│ │ │ ├── phases/
│ │ │ │ ├── awaiting.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── new_round.rs
│ │ │ │ ├── sending.rs
│ │ │ │ ├── sum.rs
│ │ │ │ ├── sum2.rs
│ │ │ │ └── update.rs
│ │ │ ├── state_machine.rs
│ │ │ └── tests/
│ │ │ ├── mod.rs
│ │ │ ├── phases/
│ │ │ │ ├── mod.rs
│ │ │ │ ├── new_round.rs
│ │ │ │ ├── sum.rs
│ │ │ │ ├── sum2.rs
│ │ │ │ └── update.rs
│ │ │ └── utils.rs
│ │ ├── traits.rs
│ │ └── utils/
│ │ ├── concurrent_futures.rs
│ │ └── mod.rs
│ └── xaynet-server/
│ ├── Cargo.toml
│ └── src/
│ ├── bin/
│ │ └── main.rs
│ ├── examples.rs
│ ├── lib.rs
│ ├── metrics/
│ │ ├── mod.rs
│ │ └── recorders/
│ │ ├── influxdb/
│ │ │ ├── dispatcher.rs
│ │ │ ├── mod.rs
│ │ │ ├── models.rs
│ │ │ ├── recorder.rs
│ │ │ └── service.rs
│ │ └── mod.rs
│ ├── rest.rs
│ ├── services/
│ │ ├── fetchers/
│ │ │ ├── mod.rs
│ │ │ ├── model.rs
│ │ │ ├── round_parameters.rs
│ │ │ ├── seed_dict.rs
│ │ │ └── sum_dict.rs
│ │ ├── messages/
│ │ │ ├── decryptor.rs
│ │ │ ├── error.rs
│ │ │ ├── message_parser.rs
│ │ │ ├── mod.rs
│ │ │ ├── multipart/
│ │ │ │ ├── buffer.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── service.rs
│ │ │ ├── state_machine.rs
│ │ │ └── task_validator.rs
│ │ ├── mod.rs
│ │ └── tests/
│ │ ├── fetchers.rs
│ │ ├── mod.rs
│ │ └── utils.rs
│ ├── settings/
│ │ ├── mod.rs
│ │ └── s3.rs
│ ├── state_machine/
│ │ ├── coordinator.rs
│ │ ├── events.rs
│ │ ├── initializer.rs
│ │ ├── mod.rs
│ │ ├── phases/
│ │ │ ├── failure.rs
│ │ │ ├── handler.rs
│ │ │ ├── idle.rs
│ │ │ ├── mod.rs
│ │ │ ├── phase.rs
│ │ │ ├── shutdown.rs
│ │ │ ├── sum.rs
│ │ │ ├── sum2.rs
│ │ │ ├── unmask.rs
│ │ │ └── update.rs
│ │ ├── requests.rs
│ │ └── tests/
│ │ ├── coordinator_state.rs
│ │ ├── event_bus.rs
│ │ ├── impls.rs
│ │ ├── initializer.rs
│ │ ├── mod.rs
│ │ └── utils.rs
│ └── storage/
│ ├── coordinator_storage/
│ │ ├── mod.rs
│ │ └── redis/
│ │ ├── impls.rs
│ │ └── mod.rs
│ ├── mod.rs
│ ├── model_storage/
│ │ ├── mod.rs
│ │ ├── noop.rs
│ │ └── s3.rs
│ ├── store.rs
│ ├── tests/
│ │ ├── mod.rs
│ │ └── utils.rs
│ ├── traits.rs
│ └── trust_anchor/
│ ├── mod.rs
│ └── noop.rs
└── scripts/
└── bump_version.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
**/.ignore
**/shell.nix
**/.envrc
.git
.github
assets
bindings
configs
docker
k8s
rust/target
scripts
================================================
FILE: .github/codecov.yml
================================================
coverage:
status:
patch: off
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: cargo
directory: "/rust"
schedule:
interval: daily
time: "09:00"
timezone: "Europe/Berlin"
- package-ecosystem: cargo
directory: "/bindings/python"
schedule:
interval: weekly
day: "monday"
- package-ecosystem: pip
directory: "/bindings/python/examples/keras_house_prices"
schedule:
interval: weekly
day: "monday"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
================================================
FILE: .github/workflows/dockercompose-validation.yml
================================================
name: docker-compose validation
on:
push:
paths:
- 'docker/docker-compose*yml'
jobs:
check-docker-compose:
name: docker-compose validation
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Verify docker-compose
working-directory: ./docker
run: docker-compose -f docker-compose.yml config -q
================================================
FILE: .github/workflows/dockerfile-validation.yml
================================================
name: Dockerfiles linting
on:
push:
paths:
- 'docker/Dockerfile**'
jobs:
lint:
name: Dockerfiles linting
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Lint file
run: docker run -v $GITHUB_WORKSPACE/docker/Dockerfile:/Dockerfile replicated/dockerfilelint /Dockerfile
================================================
FILE: .github/workflows/dockerhub-cleanup.yml
================================================
name: DockerHub Scheduled Cleanup
on:
schedule:
- cron: '00 00 * * sun'
workflow_dispatch:
jobs:
dockerhub-cleanup-inactive:
name: Cleanup inactive xaynet tags on Dockerhub
runs-on: ubuntu-latest
steps:
- name: Setup hub-tool
env:
DHUSER: ${{ secrets.DOCKER_USERNAME }}
DHTOKEN: ${{ secrets.DOCKER_PASSWORD }}
run: |
export DEBIAN_FRONTEND="noninteractive"
sudo apt update
sudo apt install -y jq
LATEST=$(curl -s "https://api.github.com/repos/docker/hub-tool/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
wget https://github.com/docker/hub-tool/releases/download/${LATEST}/hub-tool-linux-amd64.tar.gz -O /tmp/hub-tool-linux-amd64.tar.gz
tar xzvf /tmp/hub-tool-linux-amd64.tar.gz --strip-components 1 -C /tmp hub-tool/hub-tool
mkdir -pv -m 700 ~/.docker
chmod -v 600 ~/.docker/config.json
echo -ne "ewogICJ1c2VybmFtZSI6ICJESFVTRVIiLAogICJwYXNzd29yZCI6ICJESFRPS0VOIgp9Cg==" | base64 -d > /tmp/auth.json
echo -ne "ewogICJhdXRocyI6IHsKICAgICJodWItdG9vbCI6IHsKICAgICAgImF1dGgiOiAiREhVU0VSVE9LRU4iCiAgICB9LAogICAgImh1Yi10b29sLXJlZnJlc2gtdG9rZW4iOiB7CiAgICAgICJhdXRoIjogIkRIVVNFUiIKICAgIH0sCiAgICAiaHViLXRvb2wtdG9rZW4iOiB7CiAgICAgICJhdXRoIjogIkRIVVNFUiIsCiAgICAgICJpZGVudGl0eXRva2VuIjogIkpXVFRPS0VOIgogICAgfQogIH0KfQoK" | base64 -d > ~/.docker/config.json
RUSERTOKEN=$(echo -ne "${DHUSER}:${DHTOKEN}" | base64 -w0)
RUSER=$(echo -ne "${DHUSER}:" | base64 -w0)
RTOKEN=$(echo -ne "${DHTOKEN}" | base64 -w0)
sed -i -e "s,DHUSERTOKEN,${RUSERTOKEN},g" -e "s,DHUSER,${RUSER},g" -e "s,DHTOKEN,${RTOKEN},g" /tmp/auth.json ~/.docker/config.json
JWT=$(curl -s -XPOST "https://hub.docker.com/v2/users/login" -H "Content-Type:application/json" -d "@/tmp/auth.json" | jq -r .token)
sed -i -e "s,JWTTOKEN,${JWT},g" ~/.docker/config.json
- name: Delete target tags
run: |
echo -e "Inactive tags:"
/tmp/hub-tool tag ls xaynetwork/xaynet | grep -e STATUS -e inactive
TAGS=$(/tmp/hub-tool tag ls xaynetwork/xaynet | grep inactive | grep -v -e "v[0-9]\+\.[0-9]\+\.[0-9]\+" | awk '{ print $1 }')
if [[ ! -z ${TAGS} ]]
then
echo -e "\n\n"
for tag in ${TAGS}
do
/tmp/hub-tool tag rm -f ${tag}
done
fi
================================================
FILE: .github/workflows/dockerhub-master.yml
================================================
name: DockerHub (master)
on:
push:
branches:
- master
jobs:
build-tag-push-master:
name: build-tag-push-master
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: build-tag-push
uses: docker/build-push-action@v3
id: docker
with:
context: .
file: docker/Dockerfile
tags: xaynetwork/xaynet:development
push: true
build-args: COORDINATOR_FEATURES=metrics
- name: Notify on Slack
uses: 8398a7/action-slack@v3
if: always()
with:
status: custom
fields: workflow,job,repo,ref
custom_payload: |
{
username: 'GitHub Actions',
icon_emoji: ':octocat:',
attachments: [{
color: '${{ steps.docker.outcome }}' === 'success' ? 'good' : '${{ steps.docker.outcome }}' === 'failure' ? 'danger' : 'warning',
text: `${process.env.AS_WORKFLOW}\nRepository: :xaynet: ${process.env.AS_REPO}\nRef: ${process.env.AS_REF}\nTags: development`,
}]
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
================================================
FILE: .github/workflows/dockerhub-pr-with-parameters.yml
================================================
name: DockerHub (PR) with parameters
on:
issue_comment:
types: [created]
jobs:
check_comments:
name: Check comments for /deploy
runs-on: ubuntu-latest
steps:
- name: Check for Command
id: command
uses: xt0rted/slash-command-action@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
command: deploy
reaction: "true"
reaction-type: "eyes"
allow-edits: "false"
permission-level: write
- uses: jungwinter/split@v2
id: split
with:
msg: '${{ steps.command.outputs.command-arguments }}'
maxsplit: 1
- uses: xt0rted/pull-request-comment-branch@v1
id: comment-branch
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v3
if: success()
with:
ref: ${{ steps.comment-branch.outputs.head_ref }}
- name: Find and Replace
uses: jacobtomlinson/gha-find-replace@master
with:
find: "newTag: development"
replace: "newTag: ${{ steps.comment-branch.outputs.head_ref }}"
include: "kustomization.yaml"
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: build-tag-push
uses: docker/build-push-action@v3
id: docker
with:
context: .
file: docker/Dockerfile
tags: xaynetwork/xaynet:${{ steps.comment-branch.outputs.head_ref }}
push: true
build-args: |
${{ steps.split.outputs._0 }}
${{ steps.split.outputs._1 }}
- name: Notify on Slack
uses: 8398a7/action-slack@v3
if: ${{ success() }}
with:
status: custom
fields: workflow,job,repo,ref
custom_payload: |
{
username: 'GitHub Actions',
icon_emoji: ':octocat:',
attachments: [{
color: '${{ steps.docker.outcome }}' === 'success' ? 'good' : '${{ steps.docker.outcome }}' === 'failure' ? 'danger' : 'warning',
text: `${process.env.AS_WORKFLOW}\nRepository: :xaynet: ${process.env.AS_REPO}\nRef: ${process.env.AS_REF}\nTags: ${{ steps.comment-branch.outputs.head_ref }}`,
}]
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
================================================
FILE: .github/workflows/dockerhub-release.yml
================================================
name: DockerHub (Release)
on:
push:
tags:
- v[0-9]+.[0-9]+.[0-9]+
jobs:
build-tag-push-release:
name: build-tag-push-release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: build-tag-push
uses: docker/build-push-action@v3
id: docker
with:
context: .
file: docker/Dockerfile
tags: xaynetwork/xaynet:latest
push: true
build-args: RELEASE_BUILD=1
- name: Notify on Slack
uses: 8398a7/action-slack@v3
if: always()
with:
status: custom
fields: workflow,job,repo,ref
custom_payload: |
{
username: 'GitHub Actions',
icon_emoji: ':octocat:',
attachments: [{
color: '${{ steps.docker.outcome }}' === 'success' ? 'good' : '${{ steps.docker.outcome }}' === 'failure' ? 'danger' : 'warning',
text: `${process.env.AS_WORKFLOW}\nRepository: :xaynet: ${process.env.AS_REPO}\nRef: ${process.env.AS_REF} :heavy_check_mark:`,
}]
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
================================================
FILE: .github/workflows/kubernetes-manifests.yml
================================================
name: Kubernetes manifests validation
on:
push:
paths:
- 'k8s/**'
jobs:
k8s-kustomize-validation:
name: Kubernetes manifests validation
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Verify Kubernetes manifests
run: kubectl kustomize $GITHUB_WORKSPACE/k8s/coordinator/development > /dev/null # Print only errors, if any
================================================
FILE: .github/workflows/rust-audit-cron.yml
================================================
name: Rust Audit for Security Vulnerabilities (master)
on:
schedule:
- cron: '00 08 * * mon-fri'
jobs:
audit:
name: Rust Audit
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
ref: master
- name: Run rust-audit
id: rust-audit
run: |
cargo audit --deny-warnings -f rust/Cargo.lock
- name: Notify on Slack
uses: 8398a7/action-slack@v3
if: ${{ failure() }}
with:
status: custom
fields: workflow,job,repo
custom_payload: |
{
username: 'GitHub Actions',
icon_emoji: ':octocat:',
attachments: [{
color: '${{ steps.rust-audit.outcome }}' === 'success' ? 'good' : '${{ steps.rust-audit.outcome }}' === 'failure' ? 'danger' : 'warning',
text: `${process.env.AS_WORKFLOW}\nRepository: ${process.env.AS_REPO}\nRef: master :warning:`,
}]
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
================================================
FILE: .github/workflows/rust-next.yml
================================================
name: Rust-CI Next
on:
schedule:
- cron: '00 04 10,20 * *'
jobs:
registry-cache:
name: cargo-fetch
timeout-minutes: 5
runs-on: ubuntu-latest
outputs:
cache-key: ${{ steps.cache-key.outputs.key }}
cache-date: ${{ steps.get-date.outputs.date }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install stable toolchain
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
default: true
# We want to create a new cache after a week. Otherwise, the cache will
# take up too much space by caching old dependencies
- name: Year + ISO week number
id: get-date
run: echo "::set-output name=date::$(/bin/date -u "+%Y-%V")"
shell: bash
# We can use the registry cache of the normal rust ci
- name: Cache key
id: cache-key
run: echo "::set-output name=key::$(echo ${{ runner.os }}-cargo-registry-${{ steps.get-date.outputs.date }}-${{ hashFiles('**/Cargo.lock') }})"
shell: bash
- name: Cache cargo registry
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ steps.cache-key.outputs.key }}
restore-keys: ${{ runner.os }}-cargo-registry-${{ steps.get-date.outputs.date }}-
- name: cargo fetch
working-directory: ./rust
run: cargo fetch
format:
name: cargo-fmt
needs: registry-cache
timeout-minutes: 10
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
cargo_manifest: [rust, bindings/python]
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install nightly toolchain
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
components: rustfmt
default: true
- name: Use cached cargo registry
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ needs.registry-cache.outputs.cache-key }}
# cargo fmt does not create any artifacts, therefore we don't need to cache the target folder
- name: cargo fmt
working-directory: ${{ matrix.cargo_manifest }}
run: cargo fmt --all -- --check
check:
name: cargo-check
needs: registry-cache
timeout-minutes: 20
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
rust_version: [stable, beta]
cargo_manifest: [rust, bindings/python]
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install toolchain
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust_version }}
default: true
- name: Use cached cargo registry
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ needs.registry-cache.outputs.cache-key }}
- name: cargo check
working-directory: ${{ matrix.cargo_manifest }}
env:
RUSTFLAGS: "-D warnings"
run: |
cargo check --all-targets
cargo check --all-targets --all-features
clippy:
name: cargo-clippy
needs: [registry-cache, check]
timeout-minutes: 20
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
rust_version: [stable, beta]
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install toolchain
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust_version }}
default: true
components: clippy
- name: Use cached cargo registry
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ needs.registry-cache.outputs.cache-key }}
- name: cargo clippy
working-directory: rust
run: |
cargo clippy --all-targets -- --deny warnings --deny clippy::cargo
cargo clippy --all-targets --all-features -- --deny warnings --deny clippy::cargo
docs:
name: cargo-doc
needs: [registry-cache, check]
timeout-minutes: 20
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
rust_version: [stable, beta]
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install toolchain
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust_version }}
default: true
- name: Use cached cargo registry
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ needs.registry-cache.outputs.cache-key }}
- name: Check the building of docs
working-directory: ./rust
run: cargo doc --all-features --document-private-items --no-deps --color always
notify:
name: notify
if: failure()
needs: [format, check, clippy, docs]
timeout-minutes: 20
runs-on: ubuntu-latest
steps:
- name: Notify on Slack
uses: 8398a7/action-slack@v3
with:
status: custom
fields: workflow,repo
custom_payload: |
{
username: 'GitHub Actions',
icon_emoji: ':octocat:',
attachments: [{
color: 'danger',
text: `${process.env.AS_WORKFLOW} :warning:\nRepository: ${process.env.AS_REPO}`,
}]
}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
================================================
FILE: .github/workflows/rust.yml
================================================
name: Rust-CI
on:
push:
paths:
- 'rust/**'
- 'bindings/python/**'
- '.github/workflows/rust.yml'
- 'README.md'
- 'README.tpl'
env:
RUST_STABLE: 1.55.0
RUST_NIGHTLY: nightly-2021-09-09
jobs:
registry-cache:
name: cargo-fetch
timeout-minutes: 5
runs-on: ubuntu-latest
outputs:
cache-key: ${{ steps.cache-key.outputs.key }}
cache-date: ${{ steps.get-date.outputs.date }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install stable toolchain
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.RUST_STABLE }}
default: true
# We want to create a new cache after a week. Otherwise, the cache will
# take up too much space by caching old dependencies
- name: Year + ISO week number
id: get-date
run: echo "::set-output name=date::$(/bin/date -u "+%Y-%V")"
shell: bash
- name: Cache key
id: cache-key
run: echo "::set-output name=key::$(echo ${{ runner.os }}-cargo-registry-${{ steps.get-date.outputs.date }}-${{ hashFiles('**/Cargo.lock') }})"
shell: bash
- name: Cache cargo registry
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ steps.cache-key.outputs.key }}
restore-keys: ${{ runner.os }}-cargo-registry-${{ steps.get-date.outputs.date }}-
- name: cargo fetch
working-directory: ./rust
run: cargo fetch
format:
name: cargo-fmt
needs: registry-cache
timeout-minutes: 10
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
cargo_manifest: [rust, bindings/python]
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install nightly toolchain
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.RUST_NIGHTLY }}
components: rustfmt
default: true
- name: Use cached cargo registry
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ needs.registry-cache.outputs.cache-key }}
# cargo fmt does not create any artifacts, therefore we don't need to cache the target folder
- name: cargo fmt
working-directory: ${{ matrix.cargo_manifest }}
run: cargo fmt --all -- --check
check:
name: cargo-check
needs: registry-cache
timeout-minutes: 20
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
cargo_manifest: [rust, bindings/python]
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install stable toolchain
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.RUST_STABLE }}
default: true
- name: Use cached cargo registry
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ needs.registry-cache.outputs.cache-key }}
- name: Cache build artifacts
uses: actions/cache@v3.0.8
with:
path: ${{ matrix.cargo_manifest }}/target
key: ${{ runner.os }}-cargo-${{ steps.rust-toolchain.outputs.rustc }}-check-${{ matrix.cargo_manifest }}-${{ needs.registry-cache.outputs.cache-date }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-${{ steps.rust-toolchain.outputs.rustc }}-${{ matrix.cargo_manifest }}-check-${{ needs.registry-cache.outputs.cache-date }}-
- name: cargo check
working-directory: ${{ matrix.cargo_manifest }}
env:
RUSTFLAGS: "-D warnings"
run: |
cargo check --all-targets
cargo check --all-targets --all-features
clippy:
name: cargo-clippy
needs: [registry-cache, check]
timeout-minutes: 20
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install stable toolchain
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.RUST_STABLE }}
default: true
components: clippy
- name: Use cached cargo registry
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ needs.registry-cache.outputs.cache-key }}
- name: Cache build artifacts
uses: actions/cache@v3.0.8
with:
path: ${{ github.workspace }}/rust/target
key: ${{ runner.os }}-cargo-${{ steps.rust-toolchain.outputs.rustc }}-clippy-${{ needs.registry-cache.outputs.cache-date }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-${{ steps.rust-toolchain.outputs.rustc }}-clippy-${{ needs.registry-cache.outputs.cache-date }}-
- name: cargo clippy
working-directory: rust
run: |
cargo clippy --all-targets -- --deny warnings --deny clippy::cargo
cargo clippy --all-targets --all-features -- --deny warnings --deny clippy::cargo
test:
name: cargo-test
needs: [registry-cache, check]
timeout-minutes: 20
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install stable toolchain
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.RUST_STABLE }}
default: true
- name: Use cached cargo registry
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ needs.registry-cache.outputs.cache-key }}
- name: Cache build artifacts
uses: actions/cache@v3.0.8
with:
path: ${{ github.workspace }}/rust/target
key: ${{ runner.os }}-cargo-${{ steps.rust-toolchain.outputs.rustc }}-tests-${{ needs.registry-cache.outputs.cache-date }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-${{ steps.rust-toolchain.outputs.rustc }}-tests-${{ needs.registry-cache.outputs.cache-date }}-
- name: Start docker-compose
working-directory: ./docker
run: docker-compose up -d influxdb minio redis
- name: Run tests (unit & integration & doc)
working-directory: ./rust
env:
RUSTFLAGS: "-D warnings"
run: |
cargo test --lib --bins --examples --tests -- -Z unstable-options --include-ignored
cargo test --lib --bins --examples --tests --all-features -- -Z unstable-options --include-ignored
cargo test --doc --all-features
- name: Stop docker-compose
working-directory: ./docker
run: docker-compose down
bench:
name: cargo-bench
needs: [registry-cache, check]
timeout-minutes: 20
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install stable toolchain
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.RUST_STABLE }}
default: true
- name: Use cached cargo registry
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ needs.registry-cache.outputs.cache-key }}
- name: Cache build artifacts
uses: actions/cache@v3.0.8
with:
path: ${{ github.workspace }}/rust/target
key: ${{ runner.os }}-cargo-${{ steps.rust-toolchain.outputs.rustc }}-bench-${{ needs.registry-cache.outputs.cache-date }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-${{ steps.rust-toolchain.outputs.rustc }}-bench-${{ needs.registry-cache.outputs.cache-date }}-
- name: Run Bench
working-directory: ./rust/benches
run: cargo bench
- name: Upload bench artifacts
uses: actions/upload-artifact@v3
with:
name: bench_${{ github.sha }}
path: ${{ github.workspace }}/rust/benches/target/criterion
docs:
name: cargo-doc
needs: [registry-cache, check]
timeout-minutes: 20
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install stable toolchain
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.RUST_STABLE }}
default: true
- name: Use cached cargo registry
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ needs.registry-cache.outputs.cache-key }}
- name: Cache build artifacts
uses: actions/cache@v3.0.8
with:
path: ${{ github.workspace }}/rust/target
key: ${{ runner.os }}-cargo-${{ steps.rust-toolchain.outputs.rustc }}-doc-${{ needs.registry-cache.outputs.cache-date }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-${{ steps.rust-toolchain.outputs.rustc }}-doc-${{ needs.registry-cache.outputs.cache-date }}-
- name: Check the building of docs
working-directory: ./rust
run: cargo doc --all-features --document-private-items --no-deps --color always
coverage:
name: cargo-tarpaulin
needs: [registry-cache, check]
timeout-minutes: 20
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install stable toolchain
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ env.RUST_STABLE }}
default: true
profile: minimal
- name: Use cached cargo registry
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ needs.registry-cache.outputs.cache-key }}
- name: Cache build artifacts
uses: actions/cache@v3.0.8
with:
path: ${{ github.workspace }}/rust/target
key: ${{ runner.os }}-cargo-${{ steps.rust-toolchain.outputs.rustc }}-tarpaulin-${{ needs.registry-cache.outputs.cache-date }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-${{ steps.rust-toolchain.outputs.rustc }}-tarpaulin-${{ needs.registry-cache.outputs.cache-date }}-
- name: Start docker-compose
working-directory: ./docker
run: docker-compose up -d influxdb minio redis
- name: Run cargo-tarpaulin
uses: actions-rs/tarpaulin@v0.1
with:
version: '0.16.0'
args: '--manifest-path rust/Cargo.toml --all-features --force-clean --lib --ignore-tests --ignored --workspace --exclude xaynet-analytics'
- name: Stop docker-compose
working-directory: ./docker
run: docker-compose down
- name: Upload to codecov.io
uses: codecov/codecov-action@v3.1.0
with:
token: ${{ secrets.CODECOV_TOKEN }}
python_sdk:
name: python sdk
needs: [registry-cache, format, check]
timeout-minutes: 20
runs-on: ubuntu-latest
env:
working-directory: ./bindings/python
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install Rust
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.RUST_STABLE }}
default: true
- name: Cache cargo registry
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ needs.registry-cache.outputs.cache-key }}
- name: Cache cargo target
uses: actions/cache@v3.0.8
with:
path: ${{ env.working-directory }}/target
key: ${{ runner.os }}-cargo-${{ steps.rust-toolchain.outputs.rustc }}-python-bindings-${{ needs.registry-cache.outputs.cache-date }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-${{ steps.rust-toolchain.outputs.rustc }}-python-bindings-${{ needs.registry-cache.outputs.cache-date }}-
- name: Setup Python 3.6
uses: actions/setup-python@v4
with:
python-version: 3.6
architecture: "x64"
- name: Get pip cache dir
id: pip-cache
run: echo "::set-output name=dir::$(pip cache dir)"
- name: Cache pip packages
uses: actions/cache@v3.0.8
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip-${{ hashFiles('./bindings/python/setup.py') }}
- name: Install dependencies and build sdk
run: |
pip install --upgrade pip
pip install --upgrade setuptools
pip install maturin==0.9.1 black==20.8b1 isort==5.7.0
maturin build
working-directory: ${{ env.working-directory }}
- name: black
working-directory: ${{ env.working-directory }}
run: black --check .
- name: isort
working-directory: ${{ env.working-directory }}
run: isort --check-only --diff .
readme:
name: cargo-readme
timeout-minutes: 20
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install stable toolchain
id: rust-toolchain
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ env.RUST_STABLE }}
default: true
- name: Cache cargo readme
uses: actions/cache@v3.0.8
with:
path: |
~/.cargo/registry
~/.cargo/git
~/.cargo/bin/cargo-readme
key: ${{ runner.os }}-cargo-readme-bin
- name: Install cargo readme
run: cargo install cargo-readme || true
- name: Check that readme matches docs
working-directory: ./
run: |
cargo readme --project-root rust/xaynet/ --template ../../README.tpl --output ../../CARGO_README.md
git diff --exit-code --no-index README.md CARGO_README.md
================================================
FILE: .gitignore
================================================
**/.ignore/
# https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
# General
**.DS_Store
**.swp
# vscode workspace settings
.vscode/*
CARGO_README.md
================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to the [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [unreleased]
### Changed
#### `xaynet-sdk`
- Update to `tokio` `v1.x`
- Update to `reqwest` `v0.11.x`
- Update to `bytes` `v1.x`
#### `xaynet-mobile`
- Update to `tokio` `v1.x`
- Update to `reqwest` `v0.11.x`
#### `examples`
- Update to `tokio` `v1.x`
- Update to `reqwest` `v0.11.x`
#### `xaynet-server`
- Update to `tokio` `v1.x`
- Update to `warp` `v0.3.x`
- Update to `bytes` `v1.x`
- Update to `rusoto_core` `v0.46.x`
- Update to `rusoto_s3` `v0.46.x`
- Update to `tower` `v0.4.x`
- Update to `redis` `v0.19.x`
- Enable optional server side client authentication via tls
- Environment variable prefixes respect the `__` separator now, i.e. all envs have changed from
`XAYNET_*` to `XAYNET__*`.
## [0.11.0] - 2021-01-18
### Added
#### Rust SDK `xaynet-sdk`
`xaynet-sdk` contains the basic building blocks required to run the _Privacy-Enhancing Technology_
(PET) Protocol. It consists of a state machine and two I/O interfaces with which specific Xaynet
participants can be developed that are adapted to the respective environments/requirements.
If you are interested in building your own Xaynet participant, you can take a look at
`xaynet-sdk`, our [Rust participant](https://github.com/xaynetwork/xaynet/blob/master/rust/examples/test-drive/participant.rs)
which we use primarily for testing or at
[`xaynet-mobile`](https://github.com/xaynetwork/xaynet/blob/master/rust/xaynet-mobile/src/participant.rs)
our mobile friendly participant.
#### A Mobile friendly Xaynet participant `xaynet-mobile`
`xaynet-mobile` provides a mobile friendly implementation of a Xaynet participant. It gives the user
a lot of control on how to drive the participant execution. You can regularly pause the execution of
the participant, save it, and later restore it and continue the execution. When running on a device
that is low on battery or does not have access to Wi-Fi for instance, it can be useful to be able to
pause the participant.
**C API**
Furthermore, `xaynet-mobile` offers `C` bindings that allow `xaynet-mobile` to be used in other
programming languages such as `Dart`.
#### Python participant SDK `xaynet-sdk-python`
We are happy to announce that we finally released `xaynet-sdk-python` a Python SDK that
consists of two experimental Xaynet participants (`ParticipantABC` and `AsyncParticipant`).
The `ParticipantABC` API is similar to the old one which we introduced in `v0.8.0`. Aside from some
changes to the method signature, the biggest change is that the participant now runs in its own
thread. To migrate from `v0.8.0` to `v0.11.0` please follow the
[migration guide](https://github.com/xaynetwork/xaynet/blob/master/bindings/python/migration_guide.md).
However, we noticed that our Participant API may be difficult to integrate with existing
applications, considering the code for the training has to be moved into the `train_round` method,
which can lead to significant changes to the existing code. Therefore, we offer a second API
(`AsyncParticipant`) in which the training of the model is no longer part of the participant.
A more in-depth explanation of the differences between the Participant APIs
and examples of how to use them can be found
[here](https://github.com/xaynetwork/xaynet/blob/master/bindings/python/README.md).
#### Multi-part messages
Participant messages can get large, possibly too large to be sent successfully in one go. On mobile
devices in particular, the internet connection may not be as reliable. In order to make the
transmission of messages more robust, we implemented multi-part messages to break a large message
into parts and send them sequentially to the coordinator. If the transmission of part of
a message fails, only that part will be resent and not the entire message.
#### Coordinator state managed in Redis
In order to be able to restore the state of the coordinator after a failure or shutdown,
the state is managed in Redis and no longer in memory.
The Redis client can be configured via the `[redis]` setting:
```toml
[redis]
url = "redis://127.0.0.1/"
```
#### Support for storing global models in S3/Minio
The coordinator is able to save a global model in S3/Minio after a successful round.
The S3 client can be configured via the `[s3]` setting:
```toml
[s3]
access_key = "minio"
secret_access_key = "minio123"
region = ["minio", "http://localhost:9000"]
[s3.buckets]
global_models = "global-models"
```
`xaynet-server` must be compiled with the feature flag `model-persistence` in order to enable
this feature.
#### Restore coordinator state
The state of the coordinator can be restored after a failure or shutdown.
Restoring the coordinator be configured via the `[restore]` setting:
```toml
[restore]
enable = true
```
`xaynet-server` must be compiled with the feature flag `model-persistence` in order to enable
this feature.
#### Improved collection of state machine metrics
In `v0.10.0` we introduced the collection of metrics that are emitted in the state machine of
`xaynet-server` and sent to an InfluxDB instance. In `v0.11.0` we have revised the implementation
and improved it further. Metrics are now sent much faster and adding metrics to the code has
become much easier.
### Removed
- `xaynet_client` (was split into `xaynet_sdk` and `xaynet_mobile`)
- `xaynet_ffi` (is now part of `xaynet_mobile`)
- `xaynet_macro`
## [0.10.0] - 2020-09-22
### Added
- Preparation for redis support: prepare for `xaynet_server` to store PET data in redis [#416](https://github.com/xaynetwork/xaynet/pull/416), [#515](https://github.com/xaynetwork/xaynet/pull/515)
- Add support for multipart messages in the message structure [#508](https://github.com/xaynetwork/xaynet/pull/508), [#513](https://github.com/xaynetwork/xaynet/pull/513), [#514](https://github.com/xaynetwork/xaynet/pull/514)
- Generalised scalar extension [#496](https://github.com/xaynetwork/xaynet/pull/496), [#507](https://github.com/xaynetwork/xaynet/pull/507)
- Add server metrics [#487](https://github.com/xaynetwork/xaynet/pull/487), [#488](https://github.com/xaynetwork/xaynet/pull/488), [#489](https://github.com/xaynetwork/xaynet/pull/489), [#493](https://github.com/xaynetwork/xaynet/pull/493)
- Refactor the client into a state machine, and add a client tailored for mobile devices [#471](https://github.com/xaynetwork/xaynet/pull/471), [#497](https://github.com/xaynetwork/xaynet/pull/497), [#506](https://github.com/xaynetwork/xaynet/pull/506)
### Changed
- Split the xaynet crate into several sub-crates:
- `xaynet_core` (0.1.0 released), re-exported as `xaynet::core`
- `xaynet_client` (0.1.0 released), re-exported as `xaynet::client` when compiled with `--features client`
- `xaynet_server` (0.1.0 released), re-exported as `xaynet::server` when compiled with `--features server`
- `xaynet_macro` (0.1.0 released)
- `xaynet_ffi` (not released)
## [0.9.0] - 2020-07-24
`xain/xain-fl` repository was renamed to `xaynetwork/xaynet`.
The new crate will be published as `xaynet` under `v0.9.0`.
### Added
This release introduces the integration of the [PET protocol](https://uploads-ssl.webflow.com/5f0c5c0bb18a279f0a62919e/5f157004da6585f299fa542b_XayNet%20Whitepaper%202.1.pdf) into the platform.
**Note:**
The integration of the PET protocol required a complete rewrite of the codebase and is therefore not compatible with the previous release.
## [0.8.0] - 2020-04-08
### Added
- New tutorial for the Python SDK [#355](https://github.com/xaynetwork/xaynet/pull/355)
- Swagger description of the REST API [#345](https://github.com/xaynetwork/xaynet/pull/345), and is published at https://xain-fl.readthedocs.io/en/latest/ [#358](https://github.com/xaynetwork/xaynet/pull/358)
- The Python examples now accepts additional parameters (model size, heartbeat period, verbosity, etc.) [#351](https://github.com/xaynetwork/xaynet/pull/351)
- Publish docker images to dockerhub
### Security
- Stop using `pickle` for messages serialization
[#355](https://github.com/xaynetwork/xaynet/pull/355). `pickle` is insecure
and can lead to remote code execution. Instead, the default
aggregator uses `numpy.save()`.
### Fixed
- The documentation has been updated at https://xain-fl.readthedocs.io/en/latest/ [#358](https://github.com/xaynetwork/xaynet/pull/358)
- Document aggregator error on Darwin platform [#365](https://github.com/xaynetwork/xaynet/pull/365/files)
### Changed
- Simplified the Python SDK API [#355](https://github.com/xaynetwork/xaynet/pull/355)
- Added unit tests for the coordinator and aggregator [#353](https://github.com/xaynetwork/xaynet/pull/353), [#352](https://github.com/xaynetwork/xaynet/pull/352)
- Refactor the metrics store [#340](https://github.com/xaynetwork/xaynet/pull/340)
- Speed up the docker builds [#348](https://github.com/xaynetwork/xaynet/pull/348)
## [0.7.0] - 2020-03-25
On this release we archived the Python code under the `legacy` folder and shifted the development to Rust.
This release has many breaking changes from the previous versions.
More details will be made available through the updated README.md of the repository.
## [0.6.0] - 2020-02-26
- HOTFIX add disclaimer (#309) [janpetschexain]
- PB-314: document the new weight exchange mechanism (#308) [Corentin Henry]
- PB-407 add more debug level logging (#303) [janpetschexain]
- PB-44 add heartbeat time and timeout to config (#305) [Robert Steiner]
- PB-423 lock round access (#304) [kwok]
- PB-439 Make thread pool workers configurable (#302) [Robert Steiner]
- PB-159: update xain-{proto,sdk} dependencies to the right branch (#301) [Corentin Henry]
- PB-159: remove weights from gRPC messages (#298) [Corentin Henry]
- PB-431 send participant state to influxdb (#300) [Robert Steiner]
- PB-434 separate metrics (#296) [Robert Steiner]
- PB-406 :snowflake: Configure mypy (#297) [Anastasiia Tymoshchuk]
- PB-428 send coordinator states (#292) [Robert Steiner]
- PB-425 split weight init from training (#295) [janpetschexain]
- PB-398 Round resumption in Coordinator (#285) [kwok]
- Merge pull request #294 from xainag/master. [Daniel Kravetz]
- Hotfix: PB-432 :pencil: :books: Update test badge and CI to reflect changes. [Daniel Kravetz]
- PB-417 Start new development cycle (#291) [Anastasiia Tymoshchuk, kwok]
## [0.5.0] - 2020-02-12
Fix minor issues, update documentation.
- PB-402 Add more logs (#281) [Robert Steiner]
- DO-76 :whale: non alpine image (#287) [Daniel Kravetz]
- PB-401 Add console renderer (#280) [Robert Steiner]
- DO-80 :ambulance: Update dev Dockerfile to build gRPC (#286) [Daniel Kravetz]
- DO-78 :sparkles: add grafana (#284) [Daniel Kravetz]
- DO-66 :sparkles: Add keycloak (#283) [Daniel Kravetz]
- PB-400 increment epoch base (#282) [janpetschexain]
- PB-397 Simplify write metrics function (#279) [Robert Steiner]
- PB-385 Fix xain-sdk test (#278) [Robert Steiner]
- PB-352 Add sdk config (#272) [Robert Steiner]
- Merge pull request #277 from xainag/master. [Daniel Kravetz]
- Hotfix: update ci. [Daniel Kravetz]
- DO-72 :art: Make CI name and feature consistent with other repos. [Daniel Kravetz]
- DO-47 :newspaper: Build test package on release branch. [Daniel Kravetz]
- PB-269: enable reading participants weights from S3 (#254) [Corentin Henry]
- PB-363 Start new development cycle (#271) [Anastasiia Tymoshchuk]
- PB-119 enable isort diff (#262) [janpetschexain]
- PB-363 :gem: Release v0.4.0. [Daniel Kravetz]
- DO-73 :green_heart: Disable continue_on_failure for CI jobs. Fix mypy. [Daniel Kravetz]
## [0.4.0] - 2020-02-04
Flatten model weights instead of using lists.
Fix minor issues, update documentation.
- PB-116: pin docutils version (#259) [Corentin Henry]
- PB-119 update isort config and calls (#260) [janpetschexain]
- PB-351 Store participant metrics (#244) [Robert Steiner]
- Adjust isort config (#258) [Robert Steiner]
- PB-366 flatten weights (#253) [janpetschexain]
- PB-379 Update black setup (#255) [Anastasiia Tymoshchuk]
- PB-387 simplify serve module (#251) [Corentin Henry]
- PB-104: make the tests fast again (#252) [Corentin Henry]
- PB-122: handle sigint properly (#250) [Corentin Henry]
- PB-383 write aggregated weights after each round (#246) [Corentin Henry]
- PB-104: Fix exception in monitor_hearbeats() (#248) [Corentin Henry]
- DO-57 Update docker-compose files for provisioning InfluxDB (#249) [Ricardo Saffi Marques]
- DO-59 Provision Redis 5.x for persisting states for the Coordinator (#247) [Ricardo Saffi Marques]
- PB-381: make the log level configurable (#243) [Corentin Henry]
- PB-382: cleanup storage (#245) [Corentin Henry]
- PB-380: split get_logger() (#242) [Corentin Henry]
- XP-332: grpc resource exhausted (#238) [Robert Steiner]
- XP-456: fix coordinator command (#241) [Corentin Henry]
- XP-485 Document revised state machine (#240) [kwok]
- XP-456: replace CLI argument with a config file (#221) [Corentin Henry]
- DO-48 :snowflake: :rocket: Build stable package on git tag with SemVer (#234) [Daniel Kravetz]
- XP-407 update documentation (#239) [janpetschexain]
- XP-406 remove numpy file cli (#237) [janpetschexain]
- XP-544 fix aggregate module (#235) [janpetschexain]
- DO-58: cache xain-fl dependencies in Docker (#232) [Corentin Henry]
- XP-479 Start training rounds from 0 (#226) [kwok]
## [0.3.0] - 2020-01-21
- XP-505 cleanup docstrings in xain_fl.coordinator (#228)
- XP-498 more generic shebangs (#229)
- XP-510 allow for zero epochs on cli (#227)
- XP-508 Replace circleci badge (#225)
- XP-505 docstrings cleanup (#224)
- XP-333 Replace numproto with xain-proto (#220)
- XP-499 Remove conftest, exclude tests folder (#223)
- XP-480 revise message names (#222)
- XP-436 Reinstate FINISHED heartbeat from Coordinator (#219)
- XP-308 store aggregated weights in S3 buckets (#215)
- XP-308 store aggregated weights in S3 buckets (#215)
- XP-422 ai metrics (#216)
- XP-119 Fix gRPC testing setup so that it can run on macOS (#217)
- XP-433 Fix docker headings (#218)
- Xp 373 add sdk as dependency in fl (#214)
- DO-49 Create initial buckets (#213)
- XP-424 Remove unused packages (#212)
- XP-271 fix pylint issues (#210)
- XP-374 Clean up docs (#211)
- DO-43 docker compose minio (#208)
- XP-384 remove unused files (#209)
- XP-357 make controller parametrisable (#201)
- XP 273 scripts cleanup (#206)
- XP-385 Fix docs badge (#204)
- XP-354 Remove proto files (#200)
- DO-17 Add Dockerfiles, dockerignore and docs (#202)
- XP-241 remove legacy participant and sdk dir (#199)
- XP-168 update setup.py (#191)
- XP-261 move tests to own dir (#197)
- XP-257 cleanup cproto dir (#198)
- XP-265 move benchmarks to separate repo (#193)
- XP-255 update codeowners and authors in setup (#195)
- XP-255 update codeowners and authors in setup (#195)
- XP-229 Update Readme.md (#189)
- XP-337 Clean up docs before generation (#188)
- XP-264 put coordinator as own package (#183)
- XP-272 Archive rust code (#186)
- Xp 238 add participant selection (#179)
- XP-229 Update readme (#185)
- XP-334 Add make docs into docs make file (#184)
- XP-291 harmonize docs styles (#181)
- XP-300 Update docs makefile (#180)
- XP-228 Update readme (#178)
- XP-248 use structlog (#173)
- XP-207 model framework agnostic (#166)
- XAIN-284 rename package name (#176)
- XP-251 Add ability to pass params per cmd args to coordinator (#174)
- XP-167 Add gitter badge (#171)
- Hotfix badge versions and style (#170)
- Integrate docs with readthedocs (#169)
- add pull request template (#168)
## [0.2.0] - 2019-12-02
### Changed
- Renamed package from xain to xain-fl
## [0.1.0] - 2019-09-25
The first public release of **XAIN**
### Added
- FedML implementation on well known
[benchmarks](https://github.com/xaynetwork/xaynet/tree/v0.1.0/xain/benchmark) using
a realistic deep learning model structure.
[Unreleased]: https://github.com/xaynetwork/xaynet/compare/v0.11.0...HEAD
[0.11.0]: https://github.com/xaynetwork/xaynet/compare/v0.10.0...v0.11.0
[0.10.0]: https://github.com/xaynetwork/xaynet/compare/v0.9.0...v0.10.0
[0.9.0]: https://github.com/xaynetwork/xaynet/compare/v0.8.0...v0.9.0
[0.8.0]: https://github.com/xaynetwork/xaynet/compare/v0.7.0...v0.8.0
[0.7.0]: https://github.com/xaynetwork/xaynet/compare/v0.6.0...v0.7.0
[0.6.0]: https://github.com/xaynetwork/xaynet/compare/v0.5.0...v0.6.0
[0.5.0]: https://github.com/xaynetwork/xaynet/compare/v0.4.0...v0.5.0
[0.4.0]: https://github.com/xaynetwork/xaynet/compare/v0.3.0...v0.4.0
[0.3.0]: https://github.com/xaynetwork/xaynet/compare/v0.2.0...v0.3.0
[0.2.1]: https://github.com/xaynetwork/xaynet/compare/v0.2.0...v0.2.1
[0.2.0]: https://github.com/xaynetwork/xaynet/compare/v0.1.0...v0.2.0
[0.1.0]: https://github.com/xaynetwork/xaynet/tree/v0.1.0
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
[](https://crates.io/crates/xaynet) [](https://docs.rs/xaynet) [](https://www.rust-lang.org/learn/get-started) [](https://codecov.io/gh/xaynetwork/xaynet)
 [](./ROADMAP.md)

# xaynet
## Xaynet: Train on the Edge with Federated Learning
Want a framework that supports federated learning on the edge, in
desktop browsers, integrates well with mobile apps, is performant, and
preserves privacy? Welcome to XayNet, written entirely in Rust!
### Making federated learning easy for developers
Frameworks for machine learning - including those expressly for
federated learning - exist already. These frameworks typically
facilitate federated learning of cross-silo use cases - for example in
collaborative learning across a limited number of hospitals or for
instance across multiple banks working on a common use case without
the need to share valuable and sensitive data.
This repository focusses on masked cross-device federated learning to
enable the orchestration of machine learning in millions of low-power
edge devices, such as smartphones or even cars. By doing this, we hope
to also increase the pace and scope of adoption of federated learning
in practice and especially allow the protection of end user data. All
data remains in private local premises, whereby only encrypted AI
models get automatically and asynchronously aggregated. Thus, we
provide a solution to the AI privacy dilemma and bridge the
often-existing gap between privacy and convenience. Imagine, for
example, a voice assistant to learn new words directly on device level
and sharing this knowledge with all other instances, without recording
and collecting your voice input centrally. Or, think about search
engine that learns to personalise search results without collecting
your often sensitive search queries centrally… There are thousands of
such use cases that right today still trade privacy for
convenience. We think this shouldn’t be the case and we want to
provide an alternative to overcome this dilemma.
Concretely, we provide developers with:
- **App dev tools**: An SDK to integrate federated learning into
apps written in Dart or other languages of choice for mobile development,
as well as frameworks like Flutter.
- **Privacy via cross-device federated learning**: Train your AI
models locally on edge devices such as mobile phones, browsers,
or even in cars. Federated learning automatically aggregates the
local models into a global model. Thus, all insights inherent in
the local models are captured, while the user data stays
private on end devices.
- **Security Privacy via homomorphic encryption**: Aggregate
models with the highest security and trust. Xayn’s masking
protocol encrypts all models homomorphically. This enables you
to aggregate encrypted local models into a global one – without
having to decrypt local models at all. This protects private and
even the most sensitive data.
### The case for writing this framework in Rust
Our framework for federated learning is not only a framework for
machine learning as such. Rather, it supports the federation of
machine learning that takes place on possibly heterogeneous devices
and where use cases involve many such devices.
The programming language in which this framework is written should
therefore give us strong support for the following:
- **Runs "everywhere"**: the language should not require its own
runtime and code should compile on a wide range of devices.
- **Memory and concurrency safety**: code that compiles should be both
memory safe and free of data races.
- **Secure communication**: state of the art cryptography should be
available in vetted implementations.
- **Asynchronous communication**: abstractions for asynchronous
communication should exist that make federated learning scale.
- **Fast and functional**: the language should offer functional
abstractions but also compile code into fast executables.
Rust is one of the very few choices of modern programming languages
that meets these requirements:
- its concepts of Ownership and Borrowing make it both memory and
thread-safe (hence avoiding many common concurrency issues).
- it has a strong and static type discipline and traits, which
describe shareable functionality of a type.
- it is a modern systems programming language, with some functional
style features such as pattern matching, closures and iterators.
- its idiomatic code compares favourably to idiomatic C in performance.
- it compiles to WASM and can therefore be applied natively in browser
settings.
- it is widely deployable and doesn't necessarily depend on a runtime,
unlike languages such as Java and their need for a virtual machine
to run its code. Foreign Function Interfaces support calls from
other languages/frameworks, including Dart, Python and Flutter.
- it compiles into LLVM, and so it can draw from the abundant tool
suites for LLVM.
---
# Getting Started
## Minimum supported rust version
rustc 1.51.0
## Running the platform
There are a few different ways to run the backend: via docker, or by deploying it to
a Kubernetes cluster or by compiling the code and running the binary manually.
1. Everything described below assumes your shell's working directory to be the root
of the repository.
2. The following instructions assume you have pre-existing knowledge on some
of the referenced software (like `docker` and `docker-compose`) and/or a working
setup (if you decide to compile the Rust code and run the binary manually).
3. In case you need help with setting up your system accordingly, we recommend you
refer to the official documentation of each tool, as supporting them here would be
beyond the scope of this project:
* [Rust](https://www.rust-lang.org/tools/install)
* [Docker](https://docs.docker.com/) and [Docker Compose](https://docs.docker.com/compose/)
* [Kubernetes](https://kubernetes.io/docs/home/)
**Note:**
With Xaynet `v0.11` the coordinator needs a connection to a redis instance in order to save its state.
**Don't connect the coordinator to a Redis instance that is used in production!**
We recommend connecting the coordinator to its own Redis instance. We have invested a lot of
time to make sure that the coordinator only deletes its own data but in the current state of
development, we cannot guarantee that this will always be the case.
### Using Docker
The convenience of using the docker setup is that there's no need to setup a working Rust
environment on your system, as everything is done inside the container.
#### Run an image from Docker Hub
Docker images of the latest releases are provided on
[Docker Hub](https://hub.docker.com/r/xaynetwork/xaynet).
You can try them out with the default `configs/docker-dev.toml` by running:
**Xaynet below v0.11**
```bash
docker run -v ${PWD}/configs/docker-dev.toml:/app/config.toml -p 8081:8081 xaynetwork/xaynet:v0.10.0 /app/coordinator -c /app/config.toml
```
**Xaynet v0.11+**
```bash
# don't forget to adjust the Redis url in configs/docker-dev.toml
docker run -v ${PWD}/configs/docker-dev.toml:/app/config.toml -p 8081:8081 xaynetwork/xaynet:v0.11.0
```
The docker image contains a release build of the coordinator without optional features.
#### Run a coordinator with additional infrastructure
Start the coordinator by pointing to the `docker/docker-compose.yml` file. It spins up all
infrastructure that is essential to run the coordinator with default or optional features.
Keep in mind that this file is used for development only.
```bash
docker-compose -f docker/docker-compose.yml up --build
```
#### Create a release build
If you would like, you can create an optimized release build of the coordinator,
but keep in mind that the compilation will be slower.
```bash
docker build --build-arg RELEASE_BUILD=1 -f ./docker/Dockerfile .
```
#### Build a coordinator with optional features
Optional features can be specified via the build argument `COORDINATOR_FEATURES`.
```bash
docker build --build-arg COORDINATOR_FEATURES=tls,metrics -f ./docker/Dockerfile .
```
### Using Kubernetes
To deploy an instance of the coordinator to your Kubernetes cluster, use the manifests that are
located inside the `k8s/coordinator` folder. The manifests rely on `kustomize` to be generated
(`kustomize` is officially supported by `kubectl` since v1.14). We recommend you thoroughly go
through the manifests and adjust them according to your own setup (namespace, ingress, etc.).
Remember to also check (and adjust if necessary) the default configuration for the coordinator, available
at `k8s/coordinator/development/config.toml`.
Please adjust the domain used in the `k8s/coordinator/development/ingress.yaml` file so it matches
your needs (you can also skip `ingress` altogether, just make sure you remove its reference from
`k8s/coordinator/development/kustomization.yaml`).
Keep in mind that the `ingress` configuration that is shown on `k8s/coordinator/development/ingress.yaml`
relies on resources that aren't available in this repository, due to their sensitive nature
(TLS key and certificate, for instance).
To verify the generated manifests, run:
```bash
kubectl kustomize k8s/coordinator/development
```
To apply them:
```bash
kubectl apply -k k8s/coordinator/development
```
In case you are not exposing your coordinator via `ingress`, you can still reach it using a port-forward.
The example below creates a port-forward at port `8081` assuming the coordinator pod is still using the
`app=coordinator` label:
```bash
kubectl port-forward $(kubectl get pods -l "app=coordinator" -o jsonpath="{.items[0].metadata.name}") 8081
```
### Building the project manually
The coordinator without optional features can be built and started with:
```bash
cd rust
cargo run --bin coordinator -- -c ../configs/config.toml
```
## Running the example
The example can be found under [rust/examples/](./rust/examples/). It uses a dummy model
but is network-capable, so it's a good starting point for checking connectivity with
the coordinator.
### `test-drive`
Make sure you have a running instance of the coordinator and that the clients
you will spawn with the command below are able to reach it through the network.
Here is an example on how to start `20` participants that will connect to a coordinator
running on `127.0.0.1:8081`:
```bash
cd rust
RUST_LOG=info cargo run --example test-drive -- -n 20 -u http://127.0.0.1:8081
```
For more in-depth details on how to run examples, see the accompanying Getting
Started guide under [rust/xaynet-server/src/examples.rs](./rust/xaynet-server/src/examples.rs).
## Troubleshooting
If you have any difficulties running the project, please reach out to us by
[opening an issue](https://github.com/xaynetwork/xaynet/issues/new) and describing your setup
and the problems you're facing.
================================================
FILE: README.tpl
================================================
[](https://crates.io/crates/xaynet) [](https://docs.rs/xaynet) [](https://www.rust-lang.org/learn/get-started) {{badges}} [](./ROADMAP.md)

# {{crate}}
{{readme}}
---
# Getting Started
## Minimum supported rust version
rustc 1.51.0
## Running the platform
There are a few different ways to run the backend: via docker, or by deploying it to
a Kubernetes cluster or by compiling the code and running the binary manually.
1. Everything described below assumes your shell's working directory to be the root
of the repository.
2. The following instructions assume you have pre-existing knowledge on some
of the referenced software (like `docker` and `docker-compose`) and/or a working
setup (if you decide to compile the Rust code and run the binary manually).
3. In case you need help with setting up your system accordingly, we recommend you
refer to the official documentation of each tool, as supporting them here would be
beyond the scope of this project:
* [Rust](https://www.rust-lang.org/tools/install)
* [Docker](https://docs.docker.com/) and [Docker Compose](https://docs.docker.com/compose/)
* [Kubernetes](https://kubernetes.io/docs/home/)
**Note:**
With Xaynet `v0.11` the coordinator needs a connection to a redis instance in order to save its state.
**Don't connect the coordinator to a Redis instance that is used in production!**
We recommend connecting the coordinator to its own Redis instance. We have invested a lot of
time to make sure that the coordinator only deletes its own data but in the current state of
development, we cannot guarantee that this will always be the case.
### Using Docker
The convenience of using the docker setup is that there's no need to setup a working Rust
environment on your system, as everything is done inside the container.
#### Run an image from Docker Hub
Docker images of the latest releases are provided on
[Docker Hub](https://hub.docker.com/r/xaynetwork/xaynet).
You can try them out with the default `configs/docker-dev.toml` by running:
**Xaynet below v0.11**
```bash
docker run -v ${PWD}/configs/docker-dev.toml:/app/config.toml -p 8081:8081 xaynetwork/xaynet:v0.10.0 /app/coordinator -c /app/config.toml
```
**Xaynet v0.11+**
```bash
# don't forget to adjust the Redis url in configs/docker-dev.toml
docker run -v ${PWD}/configs/docker-dev.toml:/app/config.toml -p 8081:8081 xaynetwork/xaynet:v0.11.0
```
The docker image contains a release build of the coordinator without optional features.
#### Run a coordinator with additional infrastructure
Start the coordinator by pointing to the `docker/docker-compose.yml` file. It spins up all
infrastructure that is essential to run the coordinator with default or optional features.
Keep in mind that this file is used for development only.
```bash
docker-compose -f docker/docker-compose.yml up --build
```
#### Create a release build
If you would like, you can create an optimized release build of the coordinator,
but keep in mind that the compilation will be slower.
```bash
docker build --build-arg RELEASE_BUILD=1 -f ./docker/Dockerfile .
```
#### Build a coordinator with optional features
Optional features can be specified via the build argument `COORDINATOR_FEATURES`.
```bash
docker build --build-arg COORDINATOR_FEATURES=tls,metrics -f ./docker/Dockerfile .
```
### Using Kubernetes
To deploy an instance of the coordinator to your Kubernetes cluster, use the manifests that are
located inside the `k8s/coordinator` folder. The manifests rely on `kustomize` to be generated
(`kustomize` is officially supported by `kubectl` since v1.14). We recommend you thoroughly go
through the manifests and adjust them according to your own setup (namespace, ingress, etc.).
Remember to also check (and adjust if necessary) the default configuration for the coordinator, available
at `k8s/coordinator/development/config.toml`.
Please adjust the domain used in the `k8s/coordinator/development/ingress.yaml` file so it matches
your needs (you can also skip `ingress` altogether, just make sure you remove its reference from
`k8s/coordinator/development/kustomization.yaml`).
Keep in mind that the `ingress` configuration that is shown on `k8s/coordinator/development/ingress.yaml`
relies on resources that aren't available in this repository, due to their sensitive nature
(TLS key and certificate, for instance).
To verify the generated manifests, run:
```bash
kubectl kustomize k8s/coordinator/development
```
To apply them:
```bash
kubectl apply -k k8s/coordinator/development
```
In case you are not exposing your coordinator via `ingress`, you can still reach it using a port-forward.
The example below creates a port-forward at port `8081` assuming the coordinator pod is still using the
`app=coordinator` label:
```bash
kubectl port-forward $(kubectl get pods -l "app=coordinator" -o jsonpath="{.items[0].metadata.name}") 8081
```
### Building the project manually
The coordinator without optional features can be built and started with:
```bash
cd rust
cargo run --bin coordinator -- -c ../configs/config.toml
```
## Running the example
The example can be found under [rust/examples/](./rust/examples/). It uses a dummy model
but is network-capable, so it's a good starting point for checking connectivity with
the coordinator.
### `test-drive`
Make sure you have a running instance of the coordinator and that the clients
you will spawn with the command below are able to reach it through the network.
Here is an example on how to start `20` participants that will connect to a coordinator
running on `127.0.0.1:8081`:
```bash
cd rust
RUST_LOG=info cargo run --example test-drive -- -n 20 -u http://127.0.0.1:8081
```
For more in-depth details on how to run examples, see the accompanying Getting
Started guide under [rust/xaynet-server/src/examples.rs](./rust/xaynet-server/src/examples.rs).
## Troubleshooting
If you have any difficulties running the project, please reach out to us by
[opening an issue](https://github.com/xaynetwork/xaynet/issues/new) and describing your setup
and the problems you're facing.
================================================
FILE: ROADMAP.md
================================================
# Roadmap 2021

In Q1 we focus entirely on using XayNet for the [Xayn app] in terms of federated learning and
first simple analytics, such as gathering relevant AI performance data like [NDCG metrics]
because we want to know how our AI models perform without violating the privacy of our users.
As you know, our framework originated with the aim to aggregate machine learning models securely
and privately between edge devices. Thereby, the models are transformed into one-dimensional lists
so that at the end we only aggregate a list of numbers, so why not also aggregate other numerical
analytics data, like AI performance metrics or user behaviour, such as screen times in our app,
all of course with the privacy guarantees of XayNet. As such, we focus predominantly on mobile
cross-device learning but also extend our framework to cover such use cases. In Q1 we take however
mostly care about the internal mobile case and testing so we set the basis to further
generalisation to external cases in the community during the rest of the year.

In Q2 we have three main focus points: Extending XayNet to support also web applications, since
also our [Xayn app] will be provided as a web version via [WASM]; integrating our product analytics
extensions in our [Xayn app] and optimising the client for higher performance, which is one the
major bottlenecks.

In Q3, we can imagine to opening up the analytics layer also to more general use cases outside of
Xayn itself. Until then our core focus is predominantly internally, yet, of course we hope to get
community and external feature suggestions and reviews. Also we want to make the coordinator more
observable as a foundation for further optimisations.
[Xayn app]: https://www.xayn.com/
[NDCG metrics]: https://en.wikipedia.org/wiki/Discounted_cumulative_gain#Normalized_DCG
[WASM]: https://webassembly.org/
================================================
FILE: bindings/python/.gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
global_model.bin
state.bin
================================================
FILE: bindings/python/.isort.cfg
================================================
[settings]
combine_as_imports=True
force_grid_wrap=0
force_sort_within_sections=True
include_trailing_comma=True
indent=4
line_length=88
multi_line_output=3
use_parentheses=True
================================================
FILE: bindings/python/.pylintrc
================================================
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code.
extension-pkg-whitelist=
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=grpc
# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
# ignore-patterns=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
# number of processors available to use.
# Use only 1 because of https://github.com/PyCQA/pylint/issues/374
jobs=1
# Control the amount of potential inferred values when inferring a single
# object. This can help the performance when dealing with large functions or
# complex, nested conditions.
limit-inference-results=100
# Pickle collected data for later comparisons.
persistent=yes
# Specify a configuration file.
#rcfile=
# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages.
suggestion-mode=yes
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
confidence=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once). You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use "--disable=all --enable=classes
# --disable=W".
disable=print-statement,
old-raise-syntax,
backtick,
long-suffix,
old-ne-operator,
old-octal-literal,
import-star-module-level,
non-ascii-bytes-literal,
raw-checker-failed,
bad-inline-option,
locally-disabled,
file-ignored,
suppressed-message,
useless-suppression,
deprecated-pragma,
apply-builtin,
basestring-builtin,
buffer-builtin,
cmp-builtin,
coerce-builtin,
execfile-builtin,
file-builtin,
long-builtin,
raw_input-builtin,
reduce-builtin,
standarderror-builtin,
unicode-builtin,
xrange-builtin,
coerce-method,
delslice-method,
getslice-method,
setslice-method,
no-absolute-import,
old-division,
dict-iter-method,
dict-view-method,
next-method-called,
metaclass-assignment,
indexing-exception,
raising-string,
reload-builtin,
oct-method,
hex-method,
nonzero-method,
cmp-method,
input-builtin,
round-builtin,
intern-builtin,
unichr-builtin,
map-builtin-not-iterating,
zip-builtin-not-iterating,
range-builtin-not-iterating,
filter-builtin-not-iterating,
using-cmp-argument,
eq-without-hash,
div-method,
idiv-method,
rdiv-method,
exception-message-attribute,
invalid-str-codec,
sys-max-int,
bad-python3-import,
deprecated-string-function,
deprecated-str-translate-call,
deprecated-itertools-function,
deprecated-types-field,
next-method-defined,
dict-items-not-iterating,
dict-keys-not-iterating,
dict-values-not-iterating,
deprecated-operator-function,
deprecated-urllib-function,
xreadlines-attribute,
deprecated-sys-function,
exception-escape,
comprehension-escape,
c-extension-no-member,
duplicate-code,
bad-continuation,
fixme,
redefined-builtin,
missing-docstring,
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
# Complete name of functions that never returns. When checking for
# inconsistent-return-statements if a never returning function is called then
# it will be considered as an explicit return statement and no message will be
# printed.
never-returning-functions=sys.exit
[LOGGING]
# Format style used to check logging format string. `old` means using %
# formatting, while `new` is for `{}` formatting.
logging-format-style=old
# Logging modules to check that the string format arguments are in logging
# function parameter format.
logging-modules=logging
[SPELLING]
# Limits count of emitted suggestions for spelling mistakes.
max-spelling-suggestions=4
# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package..
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,
XXX,
TODO
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
# regular expressions currently don't work https://github.com/PyCQA/pylint/issues/2498.
generated-members=
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# Tells whether to warn about missing members when the owner of the attribute
# is inferred to be None.
ignore-none=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local,SQLAlchemy
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid defining new builtins when possible.
additional-builtins=
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,
_cb
# A regular expression matching the name of dummy variables (i.e. expected to
# not be used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored. Default to name
# with leading underscore.
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=no
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Maximum number of characters on a single line.
max-line-length=100
# Maximum number of lines in a module.
max-module-lines=2000
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,
dict-separator
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[SIMILARITIES]
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
# Minimum lines number of a similarity.
min-similarity-lines=10
[BASIC]
# Naming style matching correct argument names.
argument-naming-style=snake_case
# Regular expression matching correct argument names. Overrides argument-
# naming-style.
argument-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming style matching correct attribute names.
attr-naming-style=snake_case
# Regular expression matching correct attribute names. Overrides attr-naming-
# style.
attr-rgx=[a-z_][a-z0-9_]{2,}$
# Bad variable names which should always be refused, separated by a comma.
bad-names=foo,
bar,
baz,
toto,
tutu,
tata
# Naming style matching correct class attribute names.
class-attribute-naming-style=any
# Regular expression matching correct class attribute names. Overrides class-
# attribute-naming-style.
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Naming style matching correct class names.
class-naming-style=PascalCase
# Regular expression matching correct class names. Overrides class-naming-
# style.
class-rgx=[A-Z_][a-zA-Z0-9]+$
# Naming style matching correct constant names.
const-naming-style=UPPER_CASE
# Regular expression matching correct constant names. Overrides const-naming-
# style.
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=1
# Naming style matching correct function names.
function-naming-style=snake_case
# Regular expression matching correct function names. Overrides function-
# naming-style.
function-rgx=[a-z_][a-z0-9_]{2,}$
# Good variable names which should always be accepted, separated by a comma.
good-names=i,
j,
k,
ex,
Run,
_,
logger,
_y
# Include a hint for the correct naming format with invalid-name.
include-naming-hint=no
# Naming style matching correct inline iteration names.
inlinevar-naming-style=any
# Regular expression matching correct inline iteration names. Overrides
# inlinevar-naming-style.
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Naming style matching correct method names.
method-naming-style=snake_case
# Regular expression matching correct method names. Overrides method-naming-
# style.
method-rgx=[a-z_][a-z0-9_]{2,}$
# Naming style matching correct module names.
module-naming-style=snake_case
# Regular expression matching correct module names. Overrides module-naming-
# style.
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
# These decorators are taken in consideration only for invalid-name.
property-classes=abc.abstractproperty
# Naming style matching correct variable names.
variable-naming-style=snake_case
# Regular expression matching correct variable names. Overrides variable-
# naming-style.
variable-rgx=[a-z_][a-z0-9_]{2,30}$
[STRING]
# This flag controls whether the implicit-str-concat-in-sequence should
# generate a warning on implicit string concatenation in sequences defined over
# several lines.
check-str-concat-over-line-jumps=no
[STRING_QUOTES]
# The quote character for triple-quoted docstrings.
docstring-quote=double
# The quote character for string literals.
string-quote=double-avoid-escape
# The quote character for triple-quoted strings (non-docstring).
triple-quote=double
[IMPORTS]
# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Deprecated modules which should not be used, separated by a comma.
deprecated-modules=optparse,tkinter.tix
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled).
ext-import-graph=
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled).
import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled).
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,
__new__,
setUp
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,
_fields,
_replace,
_source,
_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
[DESIGN]
# Maximum number of arguments for function / method.
max-args=10
# Maximum number of attributes for a class (see R0902).
max-attributes=11
# Maximum number of boolean expressions in an if statement.
max-bool-expr=5
# Maximum number of branch for function / method body.
max-branches=26
# Maximum number of locals for function / method body.
max-locals=25
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of public methods for a class (see R0904).
max-public-methods=25
# Maximum number of return / yield for function / method body.
max-returns=6
# Maximum number of statements in function / method body.
max-statements=100
# Minimum number of public methods for a class (see R0903).
min-public-methods=0
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "BaseException, Exception".
overgeneral-exceptions=Exception
================================================
FILE: bindings/python/Cargo.toml
================================================
[package]
name = "xaynet-sdk-python"
version = "0.1.0"
authors = ["Xayn Engineering <engineering@xaynet.dev>"]
edition = "2018"
description = "The Xayn Network project is building a privacy layer for machine learning so that AI projects can meet compliance such as GDPR and CCPA. The approach relies on Federated Learning as enabling technology that allows production AI applications to be fully privacy compliant."
readme = "README.md"
homepage = "https://xaynet.dev/"
repository = "https://github.com/xaynetwork/xaynet/"
license = "Apache-2.0"
keywords = ["federated-learning", "fl", "ai", "machine-learning"]
categories = ["science", "cryptography"]
[package.metadata.maturin]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Intended Audience :: Information Technology",
"Intended Audience :: Science/Research",
"Topic :: Scientific/Engineering",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"Topic :: Software Development",
"Topic :: Software Development :: Libraries",
"Topic :: Software Development :: Libraries :: Application Frameworks",
"Topic :: Software Development :: Libraries :: Python Modules",
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Operating System :: MacOS :: MacOS X",
"Operating System :: POSIX :: Linux",
]
requires-python = ">=3.6"
requires-dist = [
"justbackoff (==0.6.0)",
]
[package.metadata]
# minimum supported rust version
msrv = "1.51.0"
[dependencies]
sodiumoxide = "0.2.7"
tracing = "0.1.36"
tracing-subscriber = { version = "0.3.15", features = ["env-filter"] }
pyo3 = {version = "=0.13.2", features = ["abi3-py36", "extension-module"]}
xaynet-core = { path = "../../rust/xaynet-core", version = "0.2.0"}
xaynet-mobile = { path = "../../rust/xaynet-mobile", version = "0.1.0"}
xaynet-sdk = { path = "../../rust/xaynet-sdk", version = "0.1.0"}
[lib]
name = "xaynet_sdk"
crate-type = ["cdylib"]
================================================
FILE: bindings/python/README.md
================================================

## Installation
**Prerequisites**
- Python 3.6 or higher
**1. Install it via `pip`**
```bash
# create and activate a virtual environment e.g.
pyenv virtualenv xaynet
pyenv activate xaynet
pip install xaynet-sdk-python
```
**2. Build it from source**
```bash
# first install rust via https://rustup.rs/
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# clone the xaynet repository
git clone https://github.com/xaynetwork/xaynet.git
cd xaynet/bindings/python
# create and activate a virtual environment e.g.
pyenv virtualenv xaynet
pyenv activate xaynet
# install maturin
pip install maturin==0.9.1
pip install justbackoff
# install xaynet-sdk
maturin develop
```
## Participant API(s)
The Python SDK that consists of two experimental Xaynet participants `ParticipantABC`
and `AsyncParticipant`.
The word `Async` does not refer to either `asyncio` or asynchronous federated learning.
It refers to the property when a local model can be set. In `ParticipantABC`
the local model can only be set if the participant was selected an update participant
while in `AsyncParticipant` the model can be set at any time.
### `ParticipantABC`
The `ParticipantABC` API is similar to the old one which we introduced in
[`v0.8.0`](https://github.com/xaynetwork/xaynet/blob/v0.8.0/python/sdk/xain_sdk/participant.py#L24).
Aside from some changes to the method signature, the biggest change is that the participant
now runs in its own thread.
To migrate from `v0.8.0` to `v0.11.0` please follow the [migration guide](./migration_guide.md).

**Public API of `ParticipantABC` and `InternalParticipant`**
```python
def spawn_participant(
coordinator_url: str,
participant: ParticipantABC,
args: Tuple = (),
kwargs: dict = {},
state: Optional[List[int]] = None,
scalar: float = 1.0,
):
"""
Spawns a `InternalParticipant` in a separate thread and returns a participant handle.
If a `state` is passed, this state is restored, otherwise a new `InternalParticipant`
is created.
Args:
coordinator_url: The url of the coordinator.
participant: A class that implements `ParticipantABC`.
args: The args that get passed to the constructor of the `participant` class.
kwargs: The kwargs that get passed to the constructor of the `participant` class.
state: A serialized participant state. Defaults to `None`.
scalar: The scalar used for masking. Defaults to `1.0`.
Note:
The `scalar` is used later when the models are aggregated in order to scale their weights.
It can be used when you want to weight the participants updates differently.
For example:
If not all participant updates should be weighted equally but proportionally to their
training samples, the scalar would be set to `scalar = 1 / number_of_samples`.
Returns:
The `InternalParticipant`.
Raises:
CryptoInit: If the initialization of the underling crypto library has failed.
ParticipantInit: If the participant cannot be initialized. This is most
likely caused by an invalid `coordinator_url`.
ParticipantRestore: If the participant cannot be restored due to invalid
serialized state. This exception can never be thrown if the `state` is `None`.
Exception: Any exception that can be thrown during the instantiation of `participant`.
"""
class ParticipantABC(ABC):
def train_round(self, training_input: Optional[TrainingInput]) -> TrainingResult:
"""
Trains a model. `training_input` is the deserialized global model
(see `deserialize_training_input`). If no global model exists
(usually in the first round), `training_input` will be `None`.
In this case the weights of the model should be initialized and returned.
Args:
self: The participant.
training_input: The deserialized global model (weights of the global model) or None.
Returns:
The updated model weights (the local model).
"""
def serialize_training_result(self, training_result: TrainingResult) -> list:
"""
Serializes the `training_result` into a `list`. The data type of the
elements must match the data type defined in the coordinator configuration.
Args:
self: The participant.
training_result: The `TrainingResult` of `train_round`.
Returns:
The `training_result` as a `list`.
"""
def deserialize_training_input(self, global_model: list) -> TrainingInput:
"""
Deserializes the `global_model` from a `list` to the type of `TrainingInput`.
The data type of the elements matches the data type defined in the coordinator
configuration. If no global model exists (usually in the first round), the method will
not be called by the `InternalParticipant`.
Args:
self: The participant.
global_model: The global model.
Returns:
The `TrainingInput` for `train_round`.
"""
def participate_in_update_task(self) -> bool:
"""
A callback used by the `InternalParticipant` to determine whether the
`train_round` method should be called. This callback is only called
if the participant is selected as an update participant. If `participate_in_update_task`
returns `False`, `train_round` will not be called by the `InternalParticipant`.
If the method is not overridden, it returns `True` by default.
Returns:
Whether the `train_round` method should be called when the participant
is an update participant.
"""
def on_new_global_model(self, global_model: Optional[TrainingInput]) -> None:
"""
A callback that is called by the `InternalParticipant` once a new global model is
available. If no global model exists (usually in the first round), `global_model` will
be `None`. If a global model exists, `global_model` is already the deserialized
global model. (See `deserialize_training_input`)
If the method is not overridden, it does nothing by default.
Args:
self: The participant.
global_model: The deserialized global model or `None`.
"""
def on_stop(self) -> None:
"""
A callback that is called by the `InternalParticipant` before the `InternalParticipant`
thread is stopped.
This callback can be used, for example, to show performance values that have been
collected in the participant over the course of the training rounds.
If the method is not overridden, it does nothing by default.
Args:
self: The participant.
"""
class InternalParticipant:
def stop(self) -> List[int]:
"""
Stops the execution of the participant and returns its serialized state.
The serialized state can be passed to the `spawn_participant` function
to restore a participant.
After calling `stop`, the participant is consumed. Every further method
call on the handle of `InternalParticipant` leads to an `UninitializedParticipant`
exception.
Note:
The serialized state contains unencrypted **private key(s)**. If used
in production, it is important that the serialized state is securely saved.
Returns:
The serialized state of the participant.
"""
```
### `AsyncParticipant`
We noticed that the API of `ParticipantABC`/`InternalParticipant` reduces a fair amount of
code on the user side, however, it may not be flexible enough to cover some of the following
use cases:
1. The user wants to use the global/local model in a different thread.
It is possible to provide methods for this on the `InternalParticipant` but they are not
straight forward to implement. To make them thread-safe, it is probably necessary to use
synchronization primitives but this would make the `InternalParticipant` more complicated.
In addition, questions arise such as: Would the user want to be able to get
the current local model at any time or would they like to be notified as soon as a new
local model is available.
2. Train a model without the participant
Since the training of the model is embedded in the `ParticipantABC`, this will probably lead to
code duplication if the user wants to perform the training without the participant. Furthermore,
the embedding of the training in the `ParticipantABC` can also be a problem once the participant
is integrated into an existing application, considering the code for the training has to be
moved into the `train_round` method, which can lead to significant changes to the existing code.
3. Custom exception handling
Last but not least, the question arises how we can inform the user that an exception has been
thrown. We do not want the participant to be terminated with every exception but we want to
give the user the opportunity to respond appropriately.
The main issue we saw is that the participant is responsible for training the model
and to run the PET protocol. Therefore, we offer a second API in which the training
of the model is no longer part of the participant. This results in a simpler and more flexible API,
but it comes with the tradeoff that the user needs to perform the de/serialization of the
global/local on their side.

**Public API of `AsyncParticipant`**
```python
def spawn_async_participant(coordinator_url: str, state: Optional[List[int]] = None, scalar: float = 1.0)
-> (AsyncParticipant, threading.Event):
"""
Spawns a `AsyncParticipant` in a separate thread and returns a participant handle
together with a global model notifier. If a `state` is passed, this state is restored,
otherwise a new participant is created.
The global model notifier sets the flag once a new global model is available.
The flag is also set when the global model is `None` (usually in the first round).
The flag is reset once the method `get_global_model` has been called but it is also possible
to reset the flag manually by calling
[`clear()`](https://docs.python.org/3/library/threading.html#threading.Event.clear).
Args:
coordinator_url: The url of the coordinator.
state: A serialized participant state. Defaults to `None`.
scalar: The scalar used for masking. Defaults to `1.0`.
Note:
The `scalar` is used later when the models are aggregated in order to scale their weights.
It can be used when you want to weight the participants updates differently.
For example:
If not all participant updates should be weighted equally but proportionally to their
training samples, the scalar would be set to `scalar = 1 / number_of_samples`.
Returns:
A tuple which consists of an `AsyncParticipant` and a global model notifier.
Raises:
CryptoInit: If the initialization of the underling crypto library has failed.
ParticipantInit: If the participant cannot be initialized. This is most
likely caused by an invalid `coordinator_url`.
ParticipantRestore: If the participant cannot be restored due to invalid
serialized state. This exception can never be thrown if the `state` is `None`.
"""
class AsyncParticipant:
def get_global_model(self) -> Optional[list]:
"""
Fetches the current global model. This method can be called at any time. If no global
model exists (usually in the first round), the method returns `None`.
Returns:
The current global model or `None`. The data type of the elements matches the data
type defined in the coordinator configuration.
Raises:
GlobalModelUnavailable: If the participant cannot connect to the coordinator to get
the global model.
GlobalModelDataTypeMisMatch: If the data type of the global model does not match
the data type defined in the coordinator configuration.
"""
def set_local_model(self, local_model: list):
"""
Sets a local model. This method can be called at any time. Internally the
participant first caches the local model. As soon as the participant is selected as an
update participant, the currently cached local model is used. This means that the cache
is empty after this operation.
If a local model is already in the cache and `set_local_model` is called with a new local
model, the current cached local model will be replaced by the new one.
If the participant is an update participant and there is no local model in the cache,
the participant waits until a local model is set or until a new round has been started.
Args:
local_model: The local model. The data type of the elements must match the data
type defined in the coordinator configuration.
Raises:
LocalModelLengthMisMatch: If the length of the local model does not match the
length defined in the coordinator configuration.
LocalModelDataTypeMisMatch: If the data type of the local model does not match
the data type defined in the coordinator configuration.
"""
def stop(self) -> List[int]:
"""
Stops the execution of the participant and returns its serialized state.
The serialized state can be passed to the `spawn_async_participant` function
to restore a participant.
After calling `stop`, the participant is consumed. Every further method
call on the handle of `AsyncParticipant` leads to an `UninitializedParticipant`
exception.
Note:
The serialized state contains unencrypted **private key(s)**. If used
in production, it is important that the serialized state is securely saved.
Returns:
The serialized state of the participant.
"""
```
## Enable logging of `xaynet-mobile`
If you are interested in what `xaynet-mobile` is doing under the hood,
you can turn on the logging via the environment variable `XAYNET__CLIENT`.
For example:
`XAYNET__CLIENT=info python examples/participate_in_update.py`
## How can I ... ?
We have created a few [examples](./examples/README.md) that show the basic methods in action.
But if something is missing, not very clear or not working properly, please let us know
by opening an issue.
We are happy to help and open to ideas or feedback :)
================================================
FILE: bindings/python/examples/README.md
================================================
# Examples
Some examples that show how the `ParticipantABC` or `AsyncParticipant` can be used.
## Getting Started
All examples in this section work without changing the coordinator
[config.toml](../../../configs/config.toml) or [docker-dev.toml](../../../configs/docker-dev.toml).
- [`hello_world.py`](./hello_world.py) A basic `ParticipantABC` example
- [`hello_world_async.py`](./hello_world_async.py) A basic `AsyncParticipant` example
- [`download_global_model.py`](./download_global_model.py) A `ParticipantABC` that only downloads the latest global model
- [`download_global_model_async.py`](./download_global_model_async.py) An `AsyncParticipant` that only downloads the latest global model
- [`multiple_participants.py`](./download_global_model_async.py) Spawn multiple `ParticipantABC`s in a single process
- [`participate_in_update.py`](./participate_in_update.py) Only train a model when there is enough battery left
- [`restore.py`](./restore.py) Save and restore the state of an `AsyncParticipant`
## Keras House Prices
- [`keras_house_prices`](./keras_house_prices/) A full machine learning example
================================================
FILE: bindings/python/examples/download_global_model.py
================================================
"""A `ParticipantABC` that only downloads the latest global model"""
import json
import logging
from typing import Optional
import xaynet_sdk
LOG = logging.getLogger(__name__)
class Participant(xaynet_sdk.ParticipantABC):
def __init__(self, model: list) -> None:
self.model = model
super().__init__()
def deserialize_training_input(self, global_model: list) -> list:
return global_model
def train_round(self, training_input: Optional[list]) -> list:
pass
def serialize_training_result(self, training_result: list) -> list:
pass
def participate_in_update_task(self) -> bool:
return False
def on_new_global_model(self, global_model: Optional[list]) -> None:
LOG.info("new global model")
if global_model is not None:
with open("global_model.bin", "w") as filehandle:
filehandle.write(json.dumps(global_model))
def main() -> None:
logging.basicConfig(
format="%(asctime)s.%(msecs)03d %(levelname)8s %(message)s",
level=logging.DEBUG,
datefmt="%b %d %H:%M:%S",
)
participant = xaynet_sdk.spawn_participant(
"http://127.0.0.1:8081", Participant, args=([0.1, 0.2, 0.345, 0.3],)
)
try:
participant.join()
except KeyboardInterrupt:
participant.stop()
if __name__ == "__main__":
main()
================================================
FILE: bindings/python/examples/download_global_model_async.py
================================================
"""An `AsyncParticipant` that only downloads the latest global model"""
import json
import logging
import xaynet_sdk
LOG = logging.getLogger(__name__)
def main() -> None:
logging.basicConfig(
format="%(asctime)s.%(msecs)03d %(levelname)8s %(message)s",
level=logging.DEBUG,
datefmt="%b %d %H:%M:%S",
)
(participant, global_model_notifier) = xaynet_sdk.spawn_async_participant(
"http://127.0.0.1:8081"
)
try:
while global_model_notifier.wait():
LOG.info("a new global model")
global_model = participant.get_global_model()
if global_model is not None:
with open("global_model.bin", "w") as filehandle:
filehandle.write(json.dumps(global_model))
except KeyboardInterrupt:
participant.stop()
if __name__ == "__main__":
main()
================================================
FILE: bindings/python/examples/hello_world.py
================================================
"""A basic `ParticipantABC` example"""
import json
import logging
import time
from typing import Optional
import xaynet_sdk
LOG = logging.getLogger(__name__)
class Participant(xaynet_sdk.ParticipantABC):
def __init__(self, model: list) -> None:
self.model = model
super().__init__()
def deserialize_training_input(self, global_model: list) -> list:
return global_model
def train_round(self, training_input: Optional[list]) -> list:
LOG.info("training")
time.sleep(3.0)
LOG.info("training done")
return self.model
def serialize_training_result(self, training_result: list) -> list:
return training_result
def participate_in_update_task(self) -> bool:
return True
def on_new_global_model(self, global_model: Optional[list]) -> None:
if global_model is not None:
with open("global_model.bin", "w") as filehandle:
filehandle.write(json.dumps(global_model))
def main() -> None:
logging.basicConfig(
format="%(asctime)s.%(msecs)03d %(levelname)8s %(message)s",
level=logging.DEBUG,
datefmt="%b %d %H:%M:%S",
)
participant = xaynet_sdk.spawn_participant(
"http://127.0.0.1:8081", Participant, args=([0.1, 0.2, 0.345, 0.3],)
)
try:
participant.join()
except KeyboardInterrupt:
participant.stop()
if __name__ == "__main__":
main()
================================================
FILE: bindings/python/examples/hello_world_async.py
================================================
"""A basic `AsyncParticipant` example"""
import logging
import time
import xaynet_sdk
LOG = logging.getLogger(__name__)
def training():
LOG.info("training")
time.sleep(10.0)
LOG.info("training done")
def main() -> None:
logging.basicConfig(
format="%(asctime)s.%(msecs)03d %(levelname)8s %(message)s",
level=logging.DEBUG,
datefmt="%b %d %H:%M:%S",
)
(participant, global_model_notifier) = xaynet_sdk.spawn_async_participant(
"http://127.0.0.1:8081"
)
try:
while global_model_notifier.wait():
LOG.info("a new global model")
participant.get_global_model()
training()
participant.set_local_model([0.1, 0.2, 0.345, 0.3])
except KeyboardInterrupt:
participant.stop()
if __name__ == "__main__":
main()
================================================
FILE: bindings/python/examples/keras_house_prices/.gitignore
================================================
data/
================================================
FILE: bindings/python/examples/keras_house_prices/README.md
================================================
# `keras_house_prices` Example
**Prerequisites**
- Python >=3.7.1 <=3.8
1. Adjust the coordinator settings
Change the model length to `55117` and the `bound_type` to `B2`
in [`docker-dev.toml`](../../../../configs/docker-dev.toml).
```toml
[model]
length = 55117
[mask]
bound_type = "B2"
```
Curious what the `bond_type` is? You can find an explanation [here](https://docs.rs/xaynet-core/0.2.0/xaynet_core/mask/index.html#bound-type).
2. Start the coordinator
```shell
# in the root of the repository
docker-compose -f docker/docker-compose.yml up --build
```
**All the commands in this section are run from the
`bindings/python/examples/keras_house_prices` directory.**
3. Install the SDK:
Follow the installation steps described in [bindings/python/README.md](../../README.md).
4. Install the example:
```shell
pip install -e .
```
5. Download the dataset from Kaggle:
https://www.kaggle.com/c/house-prices-advanced-regression-techniques/data
6. Extract the data (into
`python/examples/keras_house_prices/data/` here, but the
location doesn't matter):
```shell
(cd ./data ; unzip house-prices-advanced-regression-techniques.zip)
```
7. Prepare the data:
```shell
split-data --data-directory data --number-of-participants 10
```
8. Run one participant:
```shell
XAYNET__CLIENT=info run-participant --data-directory data --coordinator-url http://127.0.0.1:8081
```
9. Repeat the previous step to run more participants
================================================
FILE: bindings/python/examples/keras_house_prices/keras_house_prices/__init__.py
================================================
================================================
FILE: bindings/python/examples/keras_house_prices/keras_house_prices/data_handlers/__init__.py
================================================
================================================
FILE: bindings/python/examples/keras_house_prices/keras_house_prices/data_handlers/data_handler.py
================================================
"""DataHandler base class to read, preprocess and split data for each example."""
from abc import ABC, abstractmethod
import logging
import os
from typing import Dict, List, Optional
import numpy as np
import pandas as pd
LOG = logging.getLogger(__name__)
class DataHandler(ABC): # pylint: disable=too-many-instance-attributes
"""Base class to handle data preparation
Args:
data_directory: path to the directory where the data is
stored
homogeneity: The level of homogeneity in the assignment
of training samples to each participants. It can take
three values:
- `iid`: meaning samples are randomly assigned to
participants.
- `intermediate`: half of the samples are randomly
assigned to participants, half of the samples
follow the 'total_split' logic.
- `total_split`: if there are more participants than
labels, samples are split among participants so that
each participant has samples from only one class.
if there are more classes than participants, samples
are split so that no class is repeated between
participants.
n_participants: The number of participants into which the
dataset will be split.
NOTE: the random seed is set in the initialisation and will make
the results reproducible.
"""
TEST_RATIO: float = 0.1
MINIMUM_PARTICIPANT_N_SAMPLES: int = 20
def __init__(
self,
data_directory: str,
homogeneity: str = "iid",
n_participants: int = 10,
) -> None:
self.homogeneity: str = homogeneity
self.n_participants: int = n_participants
self.participant_ids: List[str] = [str(p) for p in range(self.n_participants)]
self.data_dir: str = data_directory
self.parts_dir: str = os.path.join(self.data_dir, "split_data")
if not os.path.exists(self.parts_dir):
os.mkdir(self.parts_dir)
LOG.info("created %s dir", self.parts_dir)
self.train_file_path: str = os.path.join(self.data_dir, "train.csv")
self.test_file_path: str = os.path.join(self.data_dir, "test.csv")
self.train_df: pd.DataFrame = pd.DataFrame()
self.test_df: pd.DataFrame = pd.DataFrame()
self.labels: List[str] = []
# set the seed that will be used by numpy to make the results reproducible.
np.random.seed(42)
def read_data(self) -> None:
"""Find the train_set CSV file and load it into a dataframe"""
self.train_df = pd.read_csv(self.train_file_path, index_col=None)
@abstractmethod
def preprocess_data(self) -> None:
"""Abstract method to be implemented by the testcase data handling
subclass, to preprocess the data.
"""
raise NotImplementedError()
def create_testset(self) -> None:
"""Create testset by sampling and removing a TEST_RATIO percentage of
samples from self.train_df. Save the data locally.
"""
n_test_samples: int = int(len(self.train_df) * self.TEST_RATIO)
test_indexes: np.ndarray = np.random.choice(
self.train_df.index, n_test_samples, replace=False
)
self.test_df = self.train_df.loc[test_indexes, :]
self.train_df = self.train_df.drop(test_indexes)
self.test_df.to_csv(self.test_file_path)
def make_discrete_y(self) -> pd.Series:
"""Split a continuous Y variable into discrete bins, one per
participant.
Returns:
discrete_y: The discrete dependent variable.
"""
discrete_y: pd.Series = pd.cut(
self.train_df["Y"],
bins=self.n_participants,
labels=range(self.n_participants),
)
self.labels = list(set(discrete_y))
return discrete_y
def make_iid_split(
self,
input_df: pd.DataFrame,
target_length: int,
assigned_samples: Optional[List[str]] = None,
) -> np.ndarray:
"""Randomly select samples so that each participant has a similar
amount of samples.
Args:
input_df: DataFrame containing the samples to be selected.
target_length: Length of the full dataset considered for
IID split.
assigned_samples: List of sample IDs already assigned to
previous participants.
Returns:
The selected sample indexes.
"""
if assigned_samples is not None:
input_df = input_df.drop(assigned_samples)
samples_ids_per_participant: int = int(target_length / self.n_participants)
selected_sample_ids: np.ndarray = np.random.choice(
input_df.index, samples_ids_per_participant, replace=False
)
return selected_sample_ids
@staticmethod
def split_lists(
longer_list: List[str], shorter_list: List[str]
) -> Dict[str, List[str]]:
"""Split the lists of labels and participant IDs.
We use longer and shorter list to make sure that the elements of the longer list
are distributed to the elements of the shorter.
For example:
- If there are more participants than labels, the samples of each label will be
distributed to different participants, and each participant will have samples
from only one label.
- If there are more labels than participants, each participant will have samples
from more than one label, but samples from a single label will belong to only one
participant.
Args:
longer_list: List of either labels or participant IDS,
whichever is longer.
shorter_list: List of either labels or participant IDS,
whichever is shorter.
Returns:
Dictionary whose keys are the elements of the shorted
list, and its values are a sample without replacement of
the elements of the longer list.
"""
ratio: int = len(longer_list) // len(shorter_list)
splits: List[List[str]] = [
longer_list[i : i + ratio] for i in range(0, len(longer_list), ratio)
]
splits_by_shorter_element: Dict[str, List[str]] = {
item: splits[i] for i, item in enumerate(shorter_list)
}
return splits_by_shorter_element
def make_total_split(
self, discrete_y: pd.Series, participant_id: str, participant_ids: List[str]
) -> np.ndarray:
"""Select labels for one participant.
If there are more labels than participants, it will select a
list of labels not assigned to any other participant. If there
are more participants than labels, it will select one label
only for this participant (the label may re-occur for other
participants).
Args:
discrete_y: The discrete dependent variable.
participant_id: The ID of the participant for which we are
currently selecting the samples for its dataset.
participant_ids: List of all participant IDs.
Returns:
List of selected samples for the current participant.
"""
labels_by_participant_id: Dict[str, List[str]]
selected_labels: List[str]
if len(self.labels) >= self.n_participants:
labels_by_participant_id = self.split_lists(
list(self.labels), participant_ids
)
selected_labels = labels_by_participant_id[participant_id]
else:
participant_ids_by_label = self.split_lists(participant_ids, self.labels)
selected_labels = [
label
for label, ids in participant_ids_by_label.items()
if participant_id in ids
]
selected_samples: np.ndarray = np.array(
[i for i, label in discrete_y.items() if label in selected_labels]
)
return selected_samples
def make_intermediate_split(
self, assigned_samples: List[str], participant_id: str, discrete_y: pd.Series
) -> np.ndarray:
"""Handles an intermediate split, 50% IID and 50% total_split.
Args:
assigned_samples: Samples that have already been assigned
to a participant.
participant_id: The ID of the participant that will have
samples assigned to.
discrete_y: The discrete dependent variable.
Raises:
AssertionError: If the selected samples are not
unique. Typically if there was replacement, or the
random seed had not been set.
Returns:
The IDs of the selected samples for this participant.
"""
remaining_samples_df: pd.DataFrame = self.train_df.drop(assigned_samples)
first_half_df: pd.DataFrame = remaining_samples_df.sample(frac=0.5)
second_half_df: pd.DataFrame = remaining_samples_df.drop(first_half_df.index)
target_length: int = len(self.train_df) // 2
iid_samples: np.ndarray = self.make_iid_split(first_half_df, target_length)
second_half_y: pd.Series = discrete_y.loc[second_half_df.index]
total_split_samples: np.ndarray = self.make_total_split(
second_half_y, participant_id, self.participant_ids
)
selected_samples: np.ndarray = np.concatenate(
(iid_samples, total_split_samples)
)
if len(set(selected_samples)) != len(selected_samples):
raise AssertionError
return selected_samples
def split_data(self) -> None:
"""Split the data.
Continuous variables (for regression) are made discrete only
for the purpose of splitting the data (not for analysis).
For each participant ID, it performs the data split according
to the level of homogeneity selected.
Saves the dataframe for each participant locally.
"""
discrete_y: pd.Series = self.make_discrete_y()
np.random.shuffle(self.labels)
np.random.shuffle(self.participant_ids)
assigned_samples: List[str] = []
selected_samples: np.ndarray
for participant_id in self.participant_ids:
if self.homogeneity == "iid":
selected_samples = self.make_iid_split(
self.train_df, len(self.train_df), assigned_samples
)
elif self.homogeneity == "total_split":
selected_samples = self.make_total_split(
discrete_y, participant_id, self.participant_ids
)
else:
selected_samples = self.make_intermediate_split(
assigned_samples, participant_id, discrete_y
)
participant_df: pd.DataFrame = self.train_df.loc[selected_samples, :]
LOG.info(
"participant %s df has shape %s", participant_id, participant_df.shape
)
if len(participant_df) < self.MINIMUM_PARTICIPANT_N_SAMPLES:
LOG.info(
"participant %s has only %d samples.",
participant_id,
len(participant_df),
)
LOG.info("consider decreasing the number of participants")
# TODO: edge case: non-IID splits (especially 'total_split') with
# too many participants may lead to an empty df. Pandas will save
# the CSV anyway, but we may have problems reading the files later.
# Solve this with: https://xainag.atlassian.net/browse/AP-154
output_filepath: str = os.path.join(
self.parts_dir, f"data_part_{participant_id}.csv"
)
participant_df.to_csv(output_filepath, index=False)
LOG.info("participant df saved to %s", output_filepath)
assigned_samples.extend(participant_df.index)
def run(self) -> None:
"""One function to run them all."""
self.read_data()
self.preprocess_data()
self.create_testset()
self.split_data()
================================================
FILE: bindings/python/examples/keras_house_prices/keras_house_prices/data_handlers/regression_data.py
================================================
"""Implementation of the RegressionData subclass, to handle the data of regression examples."""
import argparse
import logging
from keras_house_prices.data_handlers.data_handler import DataHandler
import numpy as np
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
LOG = logging.getLogger(__name__)
class RegressionData(DataHandler):
"""Data processing logic that is specific to the house prices dataset."""
def __init__(
self, data_directory: str, homogeneity: str, n_participants: int
) -> None:
super().__init__(
data_directory, homogeneity=homogeneity, n_participants=n_participants
)
def fill_nan(self) -> None:
"""Filling missing data in the dataframe."""
self.train_df["PoolQC"] = self.train_df["PoolQC"].fillna("None")
self.train_df["MiscFeature"] = self.train_df["MiscFeature"].fillna("None")
self.train_df["Alley"] = self.train_df["Alley"].fillna("None")
self.train_df["Fence"] = self.train_df["Fence"].fillna("None")
self.train_df["FireplaceQu"] = self.train_df["FireplaceQu"].fillna("None")
self.train_df["LotFrontage"] = self.train_df.groupby("Neighborhood")[
"LotFrontage"
].transform(lambda x: x.fillna(x.median()))
for col in ("GarageType", "GarageFinish", "GarageQual", "GarageCond"):
self.train_df[col] = self.train_df[col].fillna("None")
for col in ("GarageYrBlt", "GarageArea", "GarageCars"):
self.train_df[col] = self.train_df[col].fillna(0)
for col in (
"BsmtFinSF1",
"BsmtFinSF2",
"BsmtUnfSF",
"TotalBsmtSF",
"BsmtFullBath",
"BsmtHalfBath",
):
self.train_df[col] = self.train_df[col].fillna(0)
for col in (
"BsmtQual",
"BsmtCond",
"BsmtExposure",
"BsmtFinType1",
"BsmtFinType2",
):
self.train_df[col] = self.train_df[col].fillna("None")
self.train_df["MSZoning"] = self.train_df["MSZoning"].fillna(
self.train_df["MSZoning"].mode()[0]
)
self.train_df["MasVnrType"] = self.train_df["MasVnrType"].fillna("None")
self.train_df["MasVnrArea"] = self.train_df["MasVnrArea"].fillna(0)
self.train_df = self.train_df.drop(["Utilities"], axis=1)
self.train_df["Functional"] = self.train_df["Functional"].fillna("Typ")
self.train_df["Electrical"] = self.train_df["Electrical"].fillna(
self.train_df["Electrical"].mode()[0]
)
self.train_df["KitchenQual"] = self.train_df["KitchenQual"].fillna(
self.train_df["KitchenQual"].mode()[0]
)
self.train_df["Exterior1st"] = self.train_df["Exterior1st"].fillna(
self.train_df["Exterior1st"].mode()[0]
)
self.train_df["Exterior2nd"] = self.train_df["Exterior2nd"].fillna(
self.train_df["Exterior2nd"].mode()[0]
)
self.train_df["SaleType"] = self.train_df["SaleType"].fillna(
self.train_df["SaleType"].mode()[0]
)
self.train_df["MSSubClass"] = self.train_df["MSSubClass"].fillna("None")
no_nulls_in_dataset = not self.train_df.isnull().values.any()
if no_nulls_in_dataset:
LOG.info("No missing values")
LOG.info("data shape is %s", self.train_df.shape)
def hot_encoding(self) -> None:
"""Hot encoding of the categorical features."""
self.train_df: pd.DataFrame = pd.get_dummies(
self.train_df, dummy_na=True, drop_first=True
)
LOG.info("data shape is %s", self.train_df.shape)
def scaling(self) -> None:
"""Scales the features in minmax way and the process in log(1+x)."""
self.train_df = self.train_df.rename(columns={"SalePrice": "Y"})
self.train_df["Y"] = np.log1p(self.train_df["Y"])
scaler = MinMaxScaler()
cols = self.train_df.drop("Y", axis=1).columns
train = pd.DataFrame(
scaler.fit_transform(self.train_df.drop("Y", axis=1)), columns=cols
)
self.train_df[cols] = train
def preprocess_data(self) -> None:
"""Call methods that execute the preprocessing."""
self.train_df.drop("Id", axis=1, inplace=True)
self.fill_nan()
self.hot_encoding()
self.scaling()
def main() -> None:
"""Initialise and run the regression data preparation."""
logging.basicConfig(level=logging.DEBUG)
parser = argparse.ArgumentParser(description="Prepare data for regression")
parser.add_argument(
"--data-directory",
type=str,
help="path to the directory that contains the raw data",
)
parser.add_argument(
"--number-of-participants",
type=int,
help="number of participants into which the dataset will be split",
)
args = parser.parse_args()
regression_data = RegressionData(
args.data_directory,
"total_split",
args.number_of_participants,
)
regression_data.run()
================================================
FILE: bindings/python/examples/keras_house_prices/keras_house_prices/participant.py
================================================
"""Tensorflow Keras regression test case"""
import argparse
import logging
import os
import random
from typing import List, Optional, Tuple
from keras_house_prices.regressor import Regressor
import numpy as np
import pandas as pd
from tabulate import tabulate
from xaynet_sdk import ParticipantABC, spawn_participant
LOG = logging.getLogger(__name__)
class Participant( # pylint: disable=too-few-public-methods,too-many-instance-attributes
ParticipantABC
):
"""An example of a Keras implementation of a participant for federated
learning.
The attributes for the model and the datasets are only for
convenience, they might as well be loaded elsewhere.
Attributes:
regressor: The model to be trained.
trainset_x: A dataset for training.
trainset_y: Labels for training.
testset_x: A dataset for test.
testset_y: Labels for test.
number_samples: The number of samples in the training dataset.
performance_metrics: metrics collected after each round of training
"""
def __init__(self, dataset_dir: str) -> None:
"""Initialize a custom participant."""
super().__init__()
self.load_random_dataset(dataset_dir)
self.regressor = Regressor(len(self.trainset_x.columns))
self.performance_metrics: List[Tuple[float, float]] = []
def load_random_dataset(self, dataset_dir: str) -> None:
"""Load a random dataset from the data directory"""
i = random.randrange(0, 10, 1)
LOG.info("Train on sample number %d", i)
trainset_file_path = os.path.join(
dataset_dir, "split_data", f"data_part_{i}.csv"
)
trainset = pd.read_csv(trainset_file_path, index_col=None)
self.trainset_x = trainset.drop("Y", axis=1)
self.trainset_y = trainset["Y"]
self.number_of_samples = len(trainset)
testset_file_path = os.path.join(dataset_dir, "test.csv")
testset = pd.read_csv(testset_file_path, index_col=None)
testset_x = testset.drop("Y", axis=1)
self.testset_x: pd.DataFrame = testset_x.drop(testset_x.columns[0], axis=1)
self.testset_y = testset["Y"]
def train_round(self, training_input: Optional[np.ndarray]) -> np.ndarray:
"""Train a model in a federated learning round.
A model is given in terms of its weights and the model is
trained on the participant's dataset for a number of
epochs. The weights of the updated model are returned.
Args:
weights: The weights of the model to be trained.
Returns:
The updated model weights .
"""
if training_input is None:
# This is the first round: the coordinator doesn't have a
# global model yet, so we need to initialize the weights
self.regressor = Regressor(len(self.trainset_x.columns))
return self.regressor.get_weights()
weights = training_input
epochs = 10
self.regressor.set_weights(weights)
self.regressor.train_n_epochs(epochs, self.trainset_x, self.trainset_y)
loss: float
r_squared: float
loss, r_squared = self.regressor.evaluate_on_test(
self.testset_x, self.testset_y
)
LOG.info("loss = %f, R² = %f", loss, r_squared)
self.performance_metrics.append((loss, r_squared))
return self.regressor.get_weights()
def deserialize_training_input(self, global_model: list) -> np.ndarray:
return np.array(global_model)
def serialize_training_result(self, training_result: np.ndarray) -> list:
return training_result.tolist()
def on_stop(self) -> None:
table = tabulate(self.performance_metrics, headers=["Loss", "R²"])
print(table)
def main() -> None:
"""Entry point to start a participant."""
parser = argparse.ArgumentParser(description="Prepare data for regression")
parser.add_argument(
"--data-directory",
type=str,
help="path to the directory that contains the data",
)
parser.add_argument(
"--coordinator-url",
type=str,
required=True,
help="URL of the coordinator",
)
args = parser.parse_args()
# pylint: disable=invalid-name
logging.basicConfig(
format="%(asctime)s.%(msecs)03d %(levelname)8s %(message)s",
level=logging.DEBUG,
datefmt="%b %d %H:%M:%S",
)
participant = spawn_participant(
args.coordinator_url, Participant, args=(args.data_directory,)
)
try:
participant.join()
except KeyboardInterrupt:
participant.stop()
if __name__ == "__main__":
main()
================================================
FILE: bindings/python/examples/keras_house_prices/keras_house_prices/regressor.py
================================================
"""Wrapper for tensorflow regression neural network."""
from typing import List, Tuple
import numpy as np
import pandas as pd
from sklearn.metrics import r2_score
from tensorflow.keras import Sequential # pylint: disable=import-error
from tensorflow.keras.layers import Dense # pylint: disable=import-error
class Regressor:
"""Neural network class for the Boston pricing house problem.
Attributes:
model: Keras Sequential model
"""
def __init__(self, dim: int):
self.model = Sequential()
self.model.add(Dense(144, input_dim=dim, activation="relu"))
self.model.add(Dense(72, activation="relu"))
self.model.add(Dense(18, activation="relu"))
self.model.add(Dense(1, activation="linear"))
self.model.compile(optimizer="adam", loss="mean_squared_error")
def train_n_epochs(
self, n_epochs: int, x_train: pd.DataFrame, y_train: pd.DataFrame
) -> None:
"""Training function for the built in model.
Args:
n_epochs (int): Number of epochs to be trained.
x_train (~pd.dataframe): Features dataset for training.
y_train(~pd.dataframe): Labels for training.
"""
self.model.fit(x_train, y_train, epochs=n_epochs, verbose=0)
def evaluate_on_test(
self, x_test: pd.DataFrame, y_test: pd.DataFrame
) -> Tuple[float, float]:
"""Evaluating on testset.
Args:
x_test (dataframe): Feature set for evaluation.
y_test (dataframe): Dependent variable for evaluation.
Returns:
test_loss: Value of the testing loss.
r_squared: Value of R-squared,
to be shown as 'accuracy' metric to the Coordinator
"""
y_pred: np.ndarray = self.model.predict(x_test)
r_squared: float = r2_score(y_test, y_pred)
test_loss: float = self.model.evaluate(x_test, y_test)
return test_loss, r_squared
def get_shapes(self) -> List[Tuple[int, ...]]:
return [weight.shape for weight in self.model.get_weights()]
def get_weights(self) -> np.ndarray:
return np.concatenate(self.model.get_weights(), axis=None)
def set_weights(self, weights: np.ndarray) -> None:
shapes = self.get_shapes()
# expand the flat weights
indices: np.ndarray = np.cumsum([np.prod(shape) for shape in shapes])
tensorflow_weights: List[np.ndarray] = np.split(
weights, indices_or_sections=indices
)
tensorflow_weights = [
np.reshape(weight, newshape=shape)
for weight, shape in zip(tensorflow_weights, shapes)
]
# apply the weights to the tensorflow model
self.model.set_weights(tensorflow_weights)
================================================
FILE: bindings/python/examples/keras_house_prices/setup.py
================================================
# pylint: disable=invalid-name
from setuptools import find_packages, setup
setup(
name="keras_house_prices",
version="0.1",
author=["Xayn Engineering"],
author_email="engineering@xaynet.dev",
license="Apache License Version 2.0",
python_requires=">=3.7.1, <=3.8",
packages=find_packages(),
install_requires=[
"pandas==1.4.3",
"scikit-learn==1.1.2",
"tensorflow==2.9.1",
"numpy>=1.19.2,<1.24.0",
"tabulate~=0.8.7",
],
entry_points={
"console_scripts": [
"run-participant=keras_house_prices.participant:main",
"split-data=keras_house_prices.data_handlers.regression_data:main",
]
},
)
================================================
FILE: bindings/python/examples/multiple_participants.py
================================================
"""Spawn multiple `ParticipantABC`s in a single process"""
import json
import logging
import time
from typing import Optional
import xaynet_sdk
LOG = logging.getLogger(__name__)
class Participant(xaynet_sdk.ParticipantABC):
def __init__(self, p_id: int, model: list) -> None:
self.p_id = p_id
self.model = model
super().__init__()
def deserialize_training_input(self, global_model: list) -> list:
return global_model
def train_round(self, training_input: Optional[list]) -> list:
LOG.info("participant %s: start training", self.p_id)
time.sleep(5.0)
LOG.info("participant %s: training done", self.p_id)
return self.model
def serialize_training_result(self, training_result: list) -> list:
return training_result
def participate_in_update_task(self) -> bool:
return True
def on_new_global_model(self, global_model: Optional[list]) -> None:
if global_model is not None:
with open("global_model.bin", "w") as filehandle:
filehandle.write(json.dumps(global_model))
def main() -> None:
logging.basicConfig(
format="%(asctime)s.%(msecs)03d %(levelname)8s %(message)s",
level=logging.DEBUG,
datefmt="%b %d %H:%M:%S",
)
participant = xaynet_sdk.spawn_participant(
"http://127.0.0.1:8081",
Participant,
args=(
1,
[0.1, 0.2, 0.345, 0.3],
),
)
participant_2 = xaynet_sdk.spawn_participant(
"http://127.0.0.1:8081",
Participant,
args=(
2,
[0.3, 0.4, 0.45, 0.1],
),
)
participant_3 = xaynet_sdk.spawn_participant(
"http://127.0.0.1:8081",
Participant,
args=(
3,
[0.123, 0.1567, 0.123, 0.46],
),
)
try:
participant.join()
participant_2.join()
participant_3.join()
except KeyboardInterrupt:
participant.stop()
participant_2.stop()
participant_3.stop()
if __name__ == "__main__":
main()
================================================
FILE: bindings/python/examples/participate_in_update.py
================================================
"""Only train a model when there is enough battery left"""
import json
import logging
from random import randint
import time
from typing import Optional
import xaynet_sdk
LOG = logging.getLogger(__name__)
def get_battery_level():
return randint(1, 100)
class Participant(xaynet_sdk.ParticipantABC):
def __init__(self, model: list) -> None:
self.model = model
super().__init__()
def deserialize_training_input(self, global_model: list) -> list:
return global_model
def train_round(self, training_input: Optional[list]) -> list:
LOG.info("training")
time.sleep(3.0)
LOG.info("training done")
return self.model
def serialize_training_result(self, training_result: list) -> list:
return training_result
def participate_in_update_task(self) -> bool:
if get_battery_level() < 20:
LOG.info("low battery, skip training")
return False
LOG.info("enough battery, participate in update task")
return True
def on_new_global_model(self, global_model: Optional[list]) -> None:
if global_model is not None:
with open("global_model.bin", "w") as filehandle:
filehandle.write(json.dumps(global_model))
def main() -> None:
logging.basicConfig(
format="%(asctime)s.%(msecs)03d %(levelname)8s %(message)s",
level=logging.DEBUG,
datefmt="%b %d %H:%M:%S",
)
participant = xaynet_sdk.spawn_participant(
"http://127.0.0.1:8081", Participant, args=([0.1, 0.2, 0.345, 0.3],)
)
try:
participant.join()
except KeyboardInterrupt:
participant.stop()
if __name__ == "__main__":
main()
================================================
FILE: bindings/python/examples/restore.py
================================================
"""Save and restore the state of an `AsyncParticipant`"""
import json
import logging
import xaynet_sdk
LOG = logging.getLogger(__name__)
def main() -> None:
logging.basicConfig(
format="%(asctime)s.%(msecs)03d %(levelname)8s %(message)s",
level=logging.DEBUG,
datefmt="%b %d %H:%M:%S",
)
try:
with open("state.bin", "r") as filehandle:
restored_state = json.loads(filehandle.read())
except IOError:
LOG.info("no saved state available, initialize new participant")
restored_state = None
(participant, _) = xaynet_sdk.spawn_async_participant(
"http://127.0.0.1:8081", restored_state
)
state = participant.stop()
with open("state.bin", "w") as filehandle:
filehandle.write(json.dumps(state))
if __name__ == "__main__":
main()
================================================
FILE: bindings/python/migration_guide.md
================================================
# Migration from `v0.8.0` to `v.0.11.0`
To demonstrate the API changes from `v0.8.0` to `v.0.11.0`, we will use the keras example
which is available in both versions. For reasons of clarity, some parts of the code have
been removed.
## [`v0.8.0`](https://github.com/xaynetwork/xaynet/blob/v0.8.0/python/sdk/xain_sdk/participant.py#L24)
```bash
pip install xain-sdk
```
```python
from xain_sdk import ParticipantABC, configure_logging, run_participant
class Participant(ParticipantABC):
def train_round(
self, training_input: Optional[np.ndarray]
) -> Tuple[np.ndarray, int]:
if training_input is None:
self.regressor = Regressor(len(self.trainset_x.columns))
return (self.regressor.get_weights(), 0)
return (self.regressor.get_weights(), self.number_of_samples)
def deserialize_training_input(self, data: bytes) -> Optional[np.ndarray]:
if not data:
return None
reader = BytesIO(data)
return np.load(reader, allow_pickle=False)
def serialize_training_result(
self, training_result: Tuple[np.ndarray, int]
) -> bytes:
(weights, number_of_samples) = training_result
writer = BytesIO()
writer.write(number_of_samples.to_bytes(4, byteorder="big"))
np.save(writer, weights, allow_pickle=False)
return writer.getbuffer()[:]
def main() -> None:
participant = Participant(args.data_directory)
run_participant(
participant, args.coordinator_url, heartbeat_period=args.heartbeat_period
)
```
## [`v0.11.0`](https://github.com/xaynetwork/xaynet/blob/v0.11.0/bindings/python/xaynet_sdk/participant.py)
```bash
pip install xaynet-sdk-python
```
```python
# - renamed `run_participant` to `spawn_participant`
# - removed `configure_logging`
from xaynet_sdk import ParticipantABC, spawn_participant
class Participant(ParticipantABC):
# Returns:
# - returns a `np.ndarray` instead of `Tuple[np.ndarray, int]`
# The scalar has been moved to the `spawn_participant` function.
# This change is only temporary. In a future version it will again
# be possible to set the scalar in the `train_round` method.
def train_round(self, training_input: Optional[np.ndarray]) -> np.ndarray:
if training_input is None:
self.regressor = Regressor(len(self.trainset_x.columns))
return self.regressor.get_weights()
return self.regressor.get_weights()
# Args:
# - renamed `data` to `global_model`
# - provides a `list` instead of `Optional[bytes]`
# - `deserialize_training_input` is not called if `global_model` is `None`
# therefore the `None` case no longer needs to be handled.
#
# Returns:
# - returns a `np.ndarray` instead of `Optional[np.ndarray]`
def deserialize_training_input(self, global_model: list) -> np.ndarray:
return np.array(global_model)
# Args:
# - provides a `np.ndarray` instead of `Tuple[np.ndarray, int]`
#
# Returns:
# - returns a `list` instead of `bytes`
def serialize_training_result(self, training_result: np.ndarray) -> list:
return training_result.tolist()
def main() -> None:
# - `spawn_participant` spawns the participant in a separate thread instead of the main thread.
#
# Args:
# - removed `heartbeat_period`
# - `Participant` is instantiated in the participant thread instead of the main thread.
# This ensures that both the participant as well as the model of `Participant` live on
# the same thread. If they don't live on the same thread, it can cause problems with some
# of the ml frameworks.
participant = spawn_participant(
args.coordinator_url,
Participant,
args=(args.data_directory,)
scalar = 1 / number_of_samples
)
try:
participant.join()
except KeyboardInterrupt:
participant.stop()
```
================================================
FILE: bindings/python/src/lib.rs
================================================
pub mod python_ffi;
================================================
FILE: bindings/python/src/python_ffi.rs
================================================
use pyo3::create_exception;
use pyo3::exceptions::PyException;
use pyo3::types::PyList;
use pyo3::{prelude::*, wrap_pyfunction};
use tracing::debug;
use tracing_subscriber::{EnvFilter, FmtSubscriber};
use xaynet_core::mask::IntoPrimitives;
use xaynet_core::mask::{DataType, FromPrimitives, Model};
use xaynet_sdk::settings::MaxMessageSize;
use crate::from_primitives;
use crate::into_primitives;
create_exception!(xaynet_sdk, CryptoInit, PyException);
create_exception!(xaynet_sdk, ParticipantInit, PyException);
create_exception!(xaynet_sdk, ParticipantRestore, PyException);
create_exception!(xaynet_sdk, UninitializedParticipant, PyException);
create_exception!(xaynet_sdk, LocalModelLengthMisMatch, PyException);
create_exception!(xaynet_sdk, LocalModelDataTypeMisMatch, PyException);
create_exception!(xaynet_sdk, GlobalModelUnavailable, PyException);
create_exception!(xaynet_sdk, GlobalModelDataTypeMisMatch, PyException);
#[pymodule]
fn xaynet_sdk(py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<Participant>()?;
m.add_function(wrap_pyfunction!(init_logging, m)?)?;
m.add("CryptoInit", py.get_type::<CryptoInit>())?;
m.add("ParticipantInit", py.get_type::<ParticipantInit>())?;
m.add("ParticipantRestore", py.get_type::<ParticipantRestore>())?;
m.add(
"UninitializedParticipant",
py.get_type::<UninitializedParticipant>(),
)?;
m.add(
"LocalModelLengthMisMatch",
py.get_type::<LocalModelLengthMisMatch>(),
)?;
m.add(
"LocalModelDataTypeMisMatch",
py.get_type::<LocalModelDataTypeMisMatch>(),
)?;
m.add(
"GlobalModelUnavailable",
py.get_type::<GlobalModelUnavailable>(),
)?;
m.add(
"GlobalModelDataTypeMisMatch",
py.get_type::<GlobalModelDataTypeMisMatch>(),
)?;
Ok(())
}
#[pyclass]
#[text_signature = "(url, scalar, /)"]
struct Participant {
inner: Option<xaynet_mobile::Participant>,
}
#[pymethods]
impl Participant {
#[new]
pub fn new(url: String, scalar: f64, state: Option<Vec<u8>>) -> PyResult<Self> {
sodiumoxide::init()
.map_err(|_| CryptoInit::new_err("failed to initialize crypto library"))?;
let inner = if let Some(state) = state {
debug!("restore participant");
xaynet_mobile::Participant::restore(&state, &url).map_err(|err| {
ParticipantRestore::new_err(format!("failed to restore participant: {}", err))
})?
} else {
debug!("initialize participant");
let mut settings = xaynet_mobile::Settings::new();
settings.set_url(url);
settings.set_keys(xaynet_core::crypto::SigningKeyPair::generate());
settings.set_scalar(scalar);
settings.set_max_message_size(MaxMessageSize::unlimited());
xaynet_mobile::Participant::new(settings).map_err(|err| {
ParticipantInit::new_err(format!("failed to initialize participant: {}", err))
})?
};
Ok(Self { inner: Some(inner) })
}
#[text_signature = "($self)"]
pub fn tick(&mut self) -> PyResult<()> {
let inner = match self.inner {
Some(ref mut inner) => inner,
None => {
return Err(UninitializedParticipant::new_err(
"called 'tick' on an uninitialized participant. this is a bug.",
))
}
};
inner.tick();
Ok(())
}
#[text_signature = "($self, local_model)"]
pub fn set_model(&mut self, local_model: &PyList) -> PyResult<()> {
let inner = match self.inner {
Some(ref mut inner) => inner,
None => {
return Err(UninitializedParticipant::new_err(
"called 'set_model' on an uninitialized participant. this is a bug.",
))
}
};
let local_model_config = inner.local_model_config();
if local_model.len() != local_model_config.len {
return Err(LocalModelLengthMisMatch::new_err(format!(
"the local model length is incompatible with the model length of the current model configuration {} != {}",
local_model.len(),
local_model_config.len
)));
}
debug!(
"convert local model to {:?} datatype",
local_model_config.data_type
);
match local_model_config.data_type {
DataType::F32 => from_primitives!(inner, local_model, f32),
DataType::F64 => from_primitives!(inner, local_model, f64),
DataType::I32 => from_primitives!(inner, local_model, i32),
DataType::I64 => from_primitives!(inner, local_model, i64),
}
}
/// Check whether the participant internal state machine made progress while
/// executing the PET protocol. If so, the participant state likely changed.
#[text_signature = "($self)"]
pub fn made_progress(&self) -> PyResult<bool> {
let inner = match self.inner {
Some(ref inner) => inner,
None => {
return Err(UninitializedParticipant::new_err(
"called 'made_progress' on an uninitialized participant. this is a bug.",
))
}
};
Ok(inner.made_progress())
}
/// Check whether the participant internal state machine is waiting for the
/// participant to load its model into the store. If this method returns `true`, the
/// caller should make sure to call [`Participant::set_model()`] at some point.
#[text_signature = "($self)"]
pub fn should_set_model(&self) -> PyResult<bool> {
let inner = match self.inner {
Some(ref inner) => inner,
None => {
return Err(UninitializedParticipant::new_err(
"called 'should_set_model' on an uninitialized participant. this is a bug.",
))
}
};
Ok(inner.should_set_model())
}
#[text_signature = "($self)"]
pub fn task(&self) -> PyResult<u8> {
let inner = match self.inner {
Some(ref inner) => inner,
None => {
return Err(UninitializedParticipant::new_err(
"called 'task' on an uninitialized participant. this is a bug.",
))
}
};
// FIXME:
// Returning an enum is currently not supported: https://github.com/PyO3/pyo3/pull/1045
let task_as_u8 = match inner.task() {
xaynet_mobile::Task::None => 0,
xaynet_mobile::Task::Sum => 1,
xaynet_mobile::Task::Update => 2,
};
Ok(task_as_u8)
}
#[text_signature = "($self)"]
pub fn new_global_model(&self) -> PyResult<bool> {
let inner = match self.inner {
Some(ref inner) => inner,
None => {
return Err(UninitializedParticipant::new_err(
"called 'new_global_model' on an uninitialized participant. this is a bug.",
))
}
};
Ok(inner.new_global_model())
}
#[text_signature = "($self)"]
pub fn global_model(&mut self, py: Python) -> PyResult<Option<Py<PyList>>> {
let inner = match self.inner {
Some(ref mut inner) => inner,
None => {
return Err(UninitializedParticipant::new_err(
"called 'global_model' on an uninitialized participant. this is a bug.",
))
}
};
let global_model = inner
.global_model()
.map_err(|_| GlobalModelUnavailable::new_err("failed to fetch global model"))?;
let global_model = match global_model {
Some(global_model) => global_model,
None => return Ok(None),
};
match inner.local_model_config().data_type {
DataType::F32 => into_primitives!(py, global_model, f32),
DataType::F64 => into_primitives!(py, global_model, f64),
DataType::I32 => into_primitives!(py, global_model, i32),
DataType::I64 => into_primitives!(py, global_model, i64),
}
}
#[text_signature = "($self)"]
pub fn save(&mut self) -> PyResult<Vec<u8>> {
let inner = match self.inner.take() {
Some(inner) => inner,
None => {
return Err(UninitializedParticipant::new_err(
"called 'save' on an uninitialized participant. this is a bug.",
))
}
};
Ok(inner.save())
}
}
#[macro_export]
macro_rules! into_primitives {
($py:expr, $global_model:expr, $data_type:ty) => {
if let Ok(global_model) = $global_model
.into_primitives()
.collect::<Result<Vec<$data_type>, _>>()
{
let py_list = PyList::new($py, global_model.into_iter());
Ok(Some(py_list.into()))
} else {
Err(GlobalModelDataTypeMisMatch::new_err(
"the global model data type is incompatible with the data type of the current model configuration",
))
}
};
}
#[macro_export]
macro_rules! from_primitives {
($participant:expr, $local_model:expr, $data_type:ty) => {{
let model: Vec<$data_type> = $local_model.extract()
.map_err(|err| LocalModelDataTypeMisMatch::new_err(format!("{}", err)))?;
let converted_model = Model::from_primitives(model.into_iter());
if let Ok(converted_model) = converted_model {
$participant.set_model(converted_model);
Ok(())
} else {
Err(LocalModelDataTypeMisMatch::new_err(
"the local model data type is incompatible with the data type of the current model configuration"
))
}}
};
}
#[pyfunction]
fn init_logging() {
let env_filter = EnvFilter::try_from_env("XAYNET__CLIENT");
if let Ok(filter) = env_filter {
let _fmt_subscriber = FmtSubscriber::builder()
.with_env_filter(filter)
.with_ansi(true)
.try_init();
}
}
================================================
FILE: bindings/python/xaynet_sdk/__init__.py
================================================
import threading
from typing import List, Optional, Tuple
from .async_participant import *
from .participant import *
def spawn_participant(
coordinator_url: str,
participant: ParticipantABC,
args: Tuple = (),
kwargs: dict = {},
state: Optional[List[int]] = None,
scalar: float = 1.0,
):
"""
Spawns a `InternalParticipant` in a separate thread and returns a participant handle.
If a `state` is passed, this state is restored, otherwise a new `InternalParticipant`
is created.
Args:
coordinator_url: The url of the coordinator.
participant: A class that implements `ParticipantABC`.
args: The args that get passed to the constructor of the `participant` class.
kwargs: The kwargs that get passed to the constructor of the `participant` class.
state: A serialized participant state. Defaults to `None`.
scalar: The scalar used for masking. Defaults to `1.0`.
Note:
The `scalar` is used later when the models are aggregated in order to scale their weights.
It can be used when you want to weight the participants updates differently.
For example:
If not all participant updates should be weighted equally but proportionally to their
training samples, the scalar would be set to `scalar = 1 / number_of_samples`.
Returns:
The `InternalParticipant`.
Raises:
CryptoInit: If the initialization of the underling crypto library has failed.
ParticipantInit: If the participant cannot be initialized. This is most
likely caused by an invalid `coordinator_url`.
ParticipantRestore: If the participant cannot be restored due to invalid
serialized state. This exception can never be thrown if the `state` is `None`.
Exception: Any exception that can be thrown during the instantiation of `participant`.
"""
internal_participant = InternalParticipant(
coordinator_url, participant, args, kwargs, state, scalar
)
# spawns the internal participant in a thread.
# `start` calls the `run` method of `InternalParticipant`
# https://docs.python.org/3.8/library/threading.html#threading.Thread.start
# https://docs.python.org/3.8/library/threading.html#threading.Thread.run
internal_participant.start()
return internal_participant
def spawn_async_participant(
coordinator_url: str, state: Optional[List[int]] = None, scalar: float = 1.0
) -> (AsyncParticipant, threading.Event):
"""
Spawns a `AsyncParticipant` in a separate thread and returns a participant handle
together with a global model notifier. If a `state` is passed, this state is restored,
otherwise a new participant is created.
Args:
coordinator_url: The url of the coordinator.
state: A serialized participant state. Defaults to `None`.
scalar: The scalar used for masking. Defaults to `1.0`.
Note:
The `scalar` is used later when the models are aggregated in order to scale their weights.
It can be used when you want to weight the participants updates differently.
For example:
If not all participant updates should be weighted equally but proportionally to their
training samples, the scalar would be set to `scalar = 1 / number_of_samples`.
Returns:
A tuple which consists of an `AsyncParticipant` and a global model notifier.
Raises:
CryptoInit: If the initialization of the underling crypto library has failed.
ParticipantInit: If the participant cannot be initialized. This is most
likely caused by an invalid `coordinator_url`.
ParticipantRestore: If the participant cannot be restored due to invalid
serialized state. This exception can never be thrown if the `state` is `None`.
"""
notifier = threading.Event()
async_participant = AsyncParticipant(coordinator_url, notifier, state, scalar)
async_participant.start()
return (async_participant, notifier)
================================================
FILE: bindings/python/xaynet_sdk/async_participant.py
================================================
import logging
import threading
from typing import List, Optional
from justbackoff import Backoff
from xaynet_sdk import xaynet_sdk
# rust participant logging
xaynet_sdk.init_logging()
# python participant logging
LOG = logging.getLogger("participant")
class AsyncParticipant(threading.Thread):
def __init__(
self,
coordinator_url: str,
notifier,
state,
scalar,
):
# xaynet rust participant
self._xaynet_participant = xaynet_sdk.Participant(
coordinator_url, scalar, state
)
self._exit_event = threading.Event()
self._poll_period = Backoff(min_ms=100, max_ms=10000, factor=1.2, jitter=False)
# new global model notifier
self._notifier = notifier
# calls to an external lib are thread-safe https://stackoverflow.com/a/42023362
# however, if a user calls `stop` in the middle of the `_tick` call, the
# `save` method will be executed (which consumes the participant) and every following call
# will fail with a call on an uninitialized participant. Therefore we lock during `tick`.
self._tick_lock = threading.Lock()
super().__init__(daemon=True)
def run(self):
try:
self._run()
except Exception as err: # pylint: disable=broad-except
LOG.error("unrecoverable error: %s shut down participant", err)
self._exit_event.set()
def _notify(self):
if self._notifier.is_set() is False:
LOG.debug("notify that a new global model is available")
self._notifier.set()
def _run(self):
while not self._exit_event.is_set():
self._tick()
def _tick(self):
with self._tick_lock:
self._xaynet_participant.tick()
new_global_model = self._xaynet_participant.new_global_model()
made_progress = self._xaynet_participant.made_progress()
if new_global_model:
self._notify()
if made_progress:
self._poll_period.reset()
self._exit_event.wait(timeout=self._poll_period.duration())
else:
self._exit_event.wait(timeout=self._poll_period.duration())
def get_global_model(self) -> Optional[list]:
"""
Fetches the current global model. This method can be called at any time. If no global
model exists (usually in the first round), the method returns `None`.
Returns:
The current global model in the form of a list or `None`. The data type of the
elements match the data type defined in the coordinator configuration.
Raises:
GlobalModelUnavailable: If the participant cannot connect to the coordinator to get
the global model.
GlobalModelDataTypeMisMatch: If the data type of the global model does not match
the data type defined in the coordinator configuration.
"""
LOG.debug("get global model")
self._notifier.clear()
with self._tick_lock:
return self._xaynet_participant.global_model()
def set_local_model(self, local_model: list):
"""
Sets a local model. This method can be called at any time. Internally the
participant first caches the local model. As soon as the participant is selected as an
update participant, the currently cached local model is used. This means that the cache
is empty after this operation.
If a local model is already in the cache and `set_local_model` is called with a new local
model, the current cached local model will be replaced by the new one.
If the participant is an update participant and there is no local model in the cache,
the participant waits until a local model is set or until a new round has been started.
Args:
local_model: The local model in the form of a list. The data type of the
elements must match the data type defined in the coordinator configuration.
Raises:
LocalModelLengthMisMatch: If the length of the local model does not match the
length defined in the coordinator configuration.
LocalModelDataTypeMisMatch: If the data type of the local model does not match
the data type defined in the coordinator configuration.
"""
LOG.debug("set local model in model store")
with self._tick_lock:
self._xaynet_participant.set_model(local_model)
def stop(self) -> List[int]:
"""
Stops the execution of the participant and returns its serialized state.
The serialized state can be passed to the `spawn_async_participant` function
to restore a participant.
After calling `stop`, the participant is consumed. Every further method
call on the handle of `AsyncParticipant` leads to an `UninitializedParticipant`
exception.
Note:
The serialized state contains unencrypted **private key(s)**. If used
in production, it is important that the serialized state is securely saved.
Returns:
The serialized state of the participant.
"""
LOG.debug("stop participant")
self._exit_event.set()
self._notifier.clear()
with self._tick_lock:
return self._xaynet_participant.save()
================================================
FILE: bindings/python/xaynet_sdk/participant.py
================================================
from abc import ABC, abstractmethod
import logging
import threading
from typing import List, Optional, TypeVar
from justbackoff import Backoff
from xaynet_sdk import xaynet_sdk
# rust participant logging
xaynet_sdk.init_logging()
# python participant logging
LOG = logging.getLogger("participant")
TrainingResult = TypeVar("TrainingResult")
TrainingInput = TypeVar("TrainingInput")
class ParticipantABC(ABC):
@abstractmethod
def train_round(self, training_input: Optional[TrainingInput]) -> TrainingResult:
"""
Trains a model. `training_input` is the deserialized global model
(see `deserialize_training_input`). If no global model exists
(usually in the first round), `training_input` will be `None`.
In this case the weights of the model should be initialized and returned.
Args:
self: The participant.
training_input: The deserialized global model (weights of the global model) or None.
Returns:
The updated model weights (the local model).
"""
raise NotImplementedError()
@abstractmethod
def serialize_training_result(self, training_result: TrainingResult) -> list:
"""
Serializes the `training_result` into a `list`. The data type of the
elements must match the data type defined in the coordinator configuration.
Args:
self: The participant.
training_result: The `TrainingResult` of `train_round`.
Returns:
The `training_result` as a `list`.
"""
raise NotImplementedError()
@abstractmethod
def deserialize_training_input(self, global_model: list) -> TrainingInput:
"""
Deserializes the `global_model` from a `list` to the type of `TrainingInput`.
The data type of the elements matches the data type defined in the coordinator
configuration. If no global model exists (usually in the first round), the method will
not be called by the `InternalParticipant`.
Args:
self: The participant.
global_model: The global model.
Returns:
The `TrainingInput` for `train_round`.
"""
raise NotImplementedError()
def participate_in_update_task(self) -> bool:
"""
A callback used by the `InternalParticipant` to determine whether the
`train_round` method should be called. This callback is only called
if the participant is selected as an update participant. If `participate_in_update_task`
returns `False`, `train_round` will not be called by the `InternalParticipant`.
If the method is not overridden, it returns `True` by default.
Returns:
Whether the `train_round` method should be called when the participant
is an update participant.
"""
return True
def on_new_global_model(self, global_model: Optional[TrainingInput]) -> None:
"""
A callback that is called by the `InternalParticipant` once a new global model is
available. If no global model exists (usually in the first round), `global_model` will
be `None`. If a global model exists, `global_model` is already the deserialized
global model. (See `deserialize_training_input`)
If the method is not overridden, it does nothing by default.
Args:
self: The participant.
global_model: The deserialized global model or `None`.
"""
def on_stop(self) -> None:
"""
A callback that is called by the `InternalParticipant` before the `InternalParticipant`
thread is stopped.
This callback can be used, for example, to show performance values that have been
collected in the participant over the course of the training rounds.
If the method is not overridden, it does nothing by default.
Args:
self: The participant.
"""
class InternalParticipant(threading.Thread):
def __init__(
self,
coordinator_url: str,
participant,
p_args,
p_kwargs,
state,
scalar,
):
# xaynet rust participant
self._xaynet_participant = xaynet_sdk.Participant(
coordinator_url, scalar, state
)
# https://github.com/python/cpython/blob/3.9/Lib/multiprocessing/process.py#L80
# stores the Participant class with its args and kwargs
# the participant is created in the `run` method to ensure that the participant/ ml
# model is initialized on the participant thread otherwise the participant lives on the main
# thread which can created issues with some of the ml frameworks.
self._participant = participant
self._p_args = tuple(p_args)
self._p_kwargs = dict(p_kwargs)
self._exit_event = threading.Event()
self._poll_period = Backoff(min_ms=100, max_ms=10000, factor=1.2, jitter=False)
# global model cache
self._global_model = None
self._error_on_fetch_global_model = False
self._tick_lock = threading.Lock()
super().__init__(daemon=True)
def run(self):
self._participant = self._participant(*self._p_args, *self._p_kwargs)
try:
self._run()
except Exception as err: # pylint: disable=broad-except
LOG.error("unrecoverable error: %s shut down participant", err)
self._exit_event.set()
def _fetch_global_model(self):
LOG.debug("fetch global model")
try:
global_model = self._xaynet_participant.global_model()
except (
xaynet_sdk.GlobalModelUnavailable,
xaynet_sdk.GlobalModelDataTypeMisMatch,
) as err:
LOG.warning("failed to get global model: %s", err)
self._error_on_fetch_global_model = True
else:
if global_model is not None:
self._global_model = self._participant.deserialize_training_input(
global_model
)
else:
self._global_model = None
self._error_on_fetch_global_model = False
def _train(self):
LOG.debug("train model")
data = self._participant.train_round(self._global_model)
local_model = self._participant.serialize_training_result(data)
try:
self._xaynet_participant.set_model(local_model)
except (
xaynet_sdk.LocalModelLengthMisMatch,
xaynet_sdk.LocalModelDataTypeMisMatch,
) as err:
LOG.warning("failed to set local model: %s", err)
def _run(self):
while not self._exit_event.is_set():
self._tick()
def _tick(self):
with self._tick_lock:
self._xaynet_participant.tick()
if (
self._xaynet_participant.new_global_model()
or self._error_on_fetch_global_model
):
self._fetch_global_model()
if not self._error_on_fetch_global_model:
self._participant.on_new_global_model(self._global_model)
if (
self._xaynet_participant.should_set_model()
and self._participant.participate_in_update_task()
and not self._error_on_fetch_global_model
):
self._train()
made_progress = self._xaynet_participant.made_progress()
if made_progress:
self._poll_period.reset()
self._exit_event.wait(timeout=self._poll_period.duration())
else:
self._exit_event.wait(timeout=self._poll_period.duration())
def stop(self) -> List[int]:
"""
Stops the execution of the participant and returns its serialized state.
The serialized state can be passed to the `spawn_participant` function
to restore a participant.
After calling `stop`, the participant is consumed. Every further method
call on the handle of `InternalParticipant` leads to an `UninitializedParticipant`
exception.
Note:
The serialized state contains unencrypted **private key(s)**. If used
in production, it is important that the serialized state is securely saved.
Returns:
The serialized state of the participant.
"""
LOG.debug("stopping participant")
self._exit_event.set()
with self._tick_lock:
state = self._xaynet_participant.save()
LOG.debug("participant stopped")
self._participant.on_stop()
return state
================================================
FILE: configs/config.toml
================================================
[log]
filter = "xaynet=debug,http=warn,info"
[api]
bind_address = "127.0.0.1:8081"
tls_certificate = "/app/ssl/tls.pem"
tls_key = "/app/ssl/tls.key"
# tls_client_auth = "/app/ssl/trust_anchor.pem"
[pet.sum]
prob = 0.5
count = { min = 1, max = 100 }
time = { min = 5, max = 3600 }
[pet.update]
prob = 0.9
count = { min = 3, max = 10000 }
time = { min = 10, max = 3600 }
[pet.sum2]
count = { min = 1, max = 100 }
time = { min = 5, max = 3600 }
[mask]
group_type = "Prime"
data_type = "F32"
bound_type = "B0"
model_type = "M3"
[model]
length = 4
[metrics.influxdb]
url = "http://127.0.0.1:8086"
db = "metrics"
[redis]
url = "redis://127.0.0.1/"
[s3]
access_key = "minio"
secret_access_key = "minio123"
region = ["minio", "http://localhost:9000"]
[restore]
enable = true
================================================
FILE: configs/docker-dev.toml
================================================
[log]
filter = "xaynet=debug,http=warn,info"
[api]
bind_address = "0.0.0.0:8081"
tls_certificate = "/app/ssl/tls.pem"
tls_key = "/app/ssl/tls.key"
# tls_client_auth = "/app/ssl/trust_anchor.pem"
[pet.sum]
prob = 0.01
count = { min = 1, max = 100 }
time = { min = 5, max = 3600 }
[pet.update]
prob = 0.1
count = { min = 3, max = 10000 }
time = { min = 10, max = 3600 }
[pet.sum2]
count = { min = 1, max = 100 }
time = { min = 5, max = 3600 }
[mask]
group_type = "Prime"
data_type = "F32"
bound_type = "B0"
model_type = "M3"
[model]
length = 4
[metrics.influxdb]
url = "http://influxdb:8086"
db = "metrics"
[redis]
url = "redis://redis"
[s3]
access_key = "minio"
secret_access_key = "minio123"
region = ["minio", "http://minio:9000"]
[restore]
enable = true
================================================
FILE: docker/.dev.env
================================================
MINIO_ACCESS_KEY=minio
MINIO_SECRET_KEY=minio123
================================================
FILE: docker/Dockerfile
================================================
FROM buildpack-deps:stable-curl AS builder
RUN apt update
# Install Rust
ENV RUSTUP_HOME=/usr/local/rustup \
CARGO_HOME=/usr/local/cargo \
PATH=/usr/local/cargo/bin:$PATH
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal
# install build dependencies: libc, openssl
RUN apt install -y build-essential libssl-dev pkg-config
COPY rust/ /rust/
WORKDIR /rust/xaynet-server
# https://github.com/linkerd/linkerd2-proxy/blob/main/Dockerfile#L31
# Controls which profile the coordinator is compiled with.
# If set to RELEASE_BUILD=1, the coordinator is compiled using the release profile.
# Default is development profile.
ARG RELEASE_BUILD=0
# Controls which optional features the coordinator is compiled with.
# Syntax:
# default features: -
# single feature: COORDINATOR_FEATURES=tls
# multiple features: COORDINATOR_FEATURES=tls,metrics
# all features: COORDINATOR_FEATURES=full
ARG COORDINATOR_FEATURES
RUN mkdir -p /out && \
echo "RELEASE_BUILD=$RELEASE_BUILD COORDINATOR_FEATURES=$COORDINATOR_FEATURES" && \
if [ "$RELEASE_BUILD" -eq "0" ]; \
then \
cargo build --features="$COORDINATOR_FEATURES" && \
mv /rust/target/debug/coordinator /out/coordinator; \
else \
cargo build --features="$COORDINATOR_FEATURES" --release && \
mv /rust/target/release/coordinator /out/coordinator; \
fi
FROM ubuntu:20.04
RUN apt update && apt install -y --no-install-recommends libssl-dev
COPY --from=builder /out/coordinator /app/coordinator
ENTRYPOINT ["/app/coordinator", "-c", "/app/config.toml"]
================================================
FILE: docker/docker-compose.yml
================================================
version: "3.8"
services:
coordinator:
image: xaynetwork/xaynet:development
build:
context: ..
dockerfile: docker/Dockerfile
depends_on:
- minio
- redis
- influxdb
volumes:
- ${PWD}/configs/docker-dev.toml:/app/config.toml
networks:
- xaynet
ports:
- "8081:8081"
# temporary fix:
# The coordinator crashes if Redis is not ready or busy at startup
restart: unless-stopped
influxdb:
image: influxdb:1.8
hostname: influxdb
container_name: influxdb
environment:
INFLUXDB_DB: metrics
INFLUXDB_DATA_QUERY_LOG_ENABLED: 'false'
INFLUXDB_HTTP_LOG_ENABLED: 'false'
volumes:
- influxdb-data:/var/lib/influxdb
networks:
- xaynet
ports:
- "8086:8086"
minio:
image: minio/minio
hostname: minio
container_name: minio
env_file:
- .dev.env
command: server /data
volumes:
- minio-data:/data
networks:
- xaynet
ports:
- "9000:9000"
redis:
image: redis:6
hostname: redis
container_name: redis
entrypoint: /usr/local/bin/redis-server --appendonly yes --appendfsync everysec # using combination of RDB and AOF for persistence: https://redis.io/topics/persistence
volumes:
- redis-data:/data
networks:
- xaynet
ports:
- "6379:6379"
volumes:
minio-data:
redis-data:
influxdb-data:
networks:
xaynet:
================================================
FILE: k8s/coordinator/base/deployment.yaml
================================================
apiVersion: apps/v1
kind: Deployment
metadata:
name: coordinator-deployment
spec:
selector:
matchLabels:
app: coordinator
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: coordinator
spec:
containers:
- name: coordinator
image: coordinator
imagePullPolicy: Always
ports:
- containerPort: 8081
protocol: TCP
env:
- name: REDIS_AUTH
valueFrom:
secretKeyRef:
name: redis-auth
key: redis-password
- name: XAYNET__REDIS__URL
value: "redis://:$(REDIS_AUTH)@redis-master"
- name: XAYNET__S3__ACCESS_KEY
valueFrom:
secretKeyRef:
name: minio-auth
key: accesskey
- name: XAYNET__S3__SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: minio-auth
key: secretkey
================================================
FILE: k8s/coordinator/base/kustomization.yaml
================================================
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
commonLabels:
app.ku
gitextract_ecf7igk4/
├── .dockerignore
├── .github/
│ ├── codecov.yml
│ ├── dependabot.yml
│ └── workflows/
│ ├── dockercompose-validation.yml
│ ├── dockerfile-validation.yml
│ ├── dockerhub-cleanup.yml
│ ├── dockerhub-master.yml
│ ├── dockerhub-pr-with-parameters.yml
│ ├── dockerhub-release.yml
│ ├── kubernetes-manifests.yml
│ ├── rust-audit-cron.yml
│ ├── rust-next.yml
│ └── rust.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── README.tpl
├── ROADMAP.md
├── bindings/
│ └── python/
│ ├── .gitignore
│ ├── .isort.cfg
│ ├── .pylintrc
│ ├── Cargo.toml
│ ├── README.md
│ ├── examples/
│ │ ├── README.md
│ │ ├── download_global_model.py
│ │ ├── download_global_model_async.py
│ │ ├── hello_world.py
│ │ ├── hello_world_async.py
│ │ ├── keras_house_prices/
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── keras_house_prices/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── data_handlers/
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── data_handler.py
│ │ │ │ │ └── regression_data.py
│ │ │ │ ├── participant.py
│ │ │ │ └── regressor.py
│ │ │ └── setup.py
│ │ ├── multiple_participants.py
│ │ ├── participate_in_update.py
│ │ └── restore.py
│ ├── migration_guide.md
│ ├── src/
│ │ ├── lib.rs
│ │ └── python_ffi.rs
│ └── xaynet_sdk/
│ ├── __init__.py
│ ├── async_participant.py
│ └── participant.py
├── configs/
│ ├── config.toml
│ └── docker-dev.toml
├── docker/
│ ├── .dev.env
│ ├── Dockerfile
│ └── docker-compose.yml
├── k8s/
│ └── coordinator/
│ ├── base/
│ │ ├── deployment.yaml
│ │ ├── kustomization.yaml
│ │ └── service.yaml
│ └── development/
│ ├── cert-volume-mount.yaml
│ ├── config-volume-mount.yaml
│ ├── config.toml
│ ├── history-limit.yaml
│ ├── ingress.yaml
│ └── kustomization.yaml
├── rust/
│ ├── .gitignore
│ ├── Cargo.toml
│ ├── benches/
│ │ ├── Cargo.toml
│ │ ├── messages/
│ │ │ ├── sum.rs
│ │ │ └── update.rs
│ │ └── models/
│ │ ├── from_primitives.rs
│ │ └── to_primitives.rs
│ ├── examples/
│ │ ├── Cargo.toml
│ │ └── test-drive/
│ │ ├── main.rs
│ │ ├── participant.rs
│ │ └── settings.rs
│ ├── rustfmt.toml
│ ├── xaynet/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ └── lib.rs
│ ├── xaynet-analytics/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── controller.rs
│ │ ├── data_combination/
│ │ │ ├── data_combiner.rs
│ │ │ ├── data_points/
│ │ │ │ ├── data_point.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── screen_active_time.rs
│ │ │ │ ├── screen_enter_count.rs
│ │ │ │ ├── was_active_each_past_period.rs
│ │ │ │ └── was_active_past_n_days.rs
│ │ │ └── mod.rs
│ │ ├── database/
│ │ │ ├── analytics_event/
│ │ │ │ ├── adapter.rs
│ │ │ │ ├── data_model.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── repo.rs
│ │ │ ├── common.rs
│ │ │ ├── controller_data/
│ │ │ │ ├── adapter.rs
│ │ │ │ ├── data_model.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── repo.rs
│ │ │ ├── isar.rs
│ │ │ ├── mod.rs
│ │ │ └── screen_route/
│ │ │ ├── adapter.rs
│ │ │ ├── data_model.rs
│ │ │ ├── mod.rs
│ │ │ └── repo.rs
│ │ ├── lib.rs
│ │ └── sender.rs
│ ├── xaynet-core/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── common.rs
│ │ ├── crypto/
│ │ │ ├── encrypt.rs
│ │ │ ├── hash.rs
│ │ │ ├── mod.rs
│ │ │ ├── prng.rs
│ │ │ └── sign.rs
│ │ ├── lib.rs
│ │ ├── mask/
│ │ │ ├── config/
│ │ │ │ ├── mod.rs
│ │ │ │ └── serialization.rs
│ │ │ ├── masking.rs
│ │ │ ├── mod.rs
│ │ │ ├── model.rs
│ │ │ ├── object/
│ │ │ │ ├── mod.rs
│ │ │ │ └── serialization/
│ │ │ │ ├── mod.rs
│ │ │ │ ├── unit.rs
│ │ │ │ └── vect.rs
│ │ │ ├── scalar.rs
│ │ │ └── seed.rs
│ │ ├── message/
│ │ │ ├── message.rs
│ │ │ ├── mod.rs
│ │ │ ├── payload/
│ │ │ │ ├── chunk.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── sum.rs
│ │ │ │ ├── sum2.rs
│ │ │ │ └── update.rs
│ │ │ ├── traits.rs
│ │ │ └── utils/
│ │ │ ├── chunkable_iterator.rs
│ │ │ └── mod.rs
│ │ └── testutils/
│ │ ├── messages.rs
│ │ ├── mod.rs
│ │ └── multipart.rs
│ ├── xaynet-mobile/
│ │ ├── .cargo/
│ │ │ └── config.toml
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ ├── build.rs
│ │ ├── cbindgen.toml
│ │ ├── src/
│ │ │ ├── ffi/
│ │ │ │ ├── config.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── participant.rs
│ │ │ │ └── settings.rs
│ │ │ ├── lib.rs
│ │ │ ├── participant.rs
│ │ │ ├── reqwest_client.rs
│ │ │ └── settings.rs
│ │ ├── tests/
│ │ │ ├── ffi_test.c
│ │ │ └── minunit.h
│ │ └── xaynet_ffi.h
│ ├── xaynet-sdk/
│ │ ├── Cargo.toml
│ │ └── src/
│ │ ├── client.rs
│ │ ├── lib.rs
│ │ ├── message_encoder/
│ │ │ ├── chunker.rs
│ │ │ ├── encoder.rs
│ │ │ └── mod.rs
│ │ ├── settings/
│ │ │ ├── max_message_size.rs
│ │ │ └── mod.rs
│ │ ├── state_machine/
│ │ │ ├── io.rs
│ │ │ ├── mod.rs
│ │ │ ├── phase.rs
│ │ │ ├── phases/
│ │ │ │ ├── awaiting.rs
│ │ │ │ ├── mod.rs
│ │ │ │ ├── new_round.rs
│ │ │ │ ├── sending.rs
│ │ │ │ ├── sum.rs
│ │ │ │ ├── sum2.rs
│ │ │ │ └── update.rs
│ │ │ ├── state_machine.rs
│ │ │ └── tests/
│ │ │ ├── mod.rs
│ │ │ ├── phases/
│ │ │ │ ├── mod.rs
│ │ │ │ ├── new_round.rs
│ │ │ │ ├── sum.rs
│ │ │ │ ├── sum2.rs
│ │ │ │ └── update.rs
│ │ │ └── utils.rs
│ │ ├── traits.rs
│ │ └── utils/
│ │ ├── concurrent_futures.rs
│ │ └── mod.rs
│ └── xaynet-server/
│ ├── Cargo.toml
│ └── src/
│ ├── bin/
│ │ └── main.rs
│ ├── examples.rs
│ ├── lib.rs
│ ├── metrics/
│ │ ├── mod.rs
│ │ └── recorders/
│ │ ├── influxdb/
│ │ │ ├── dispatcher.rs
│ │ │ ├── mod.rs
│ │ │ ├── models.rs
│ │ │ ├── recorder.rs
│ │ │ └── service.rs
│ │ └── mod.rs
│ ├── rest.rs
│ ├── services/
│ │ ├── fetchers/
│ │ │ ├── mod.rs
│ │ │ ├── model.rs
│ │ │ ├── round_parameters.rs
│ │ │ ├── seed_dict.rs
│ │ │ └── sum_dict.rs
│ │ ├── messages/
│ │ │ ├── decryptor.rs
│ │ │ ├── error.rs
│ │ │ ├── message_parser.rs
│ │ │ ├── mod.rs
│ │ │ ├── multipart/
│ │ │ │ ├── buffer.rs
│ │ │ │ ├── mod.rs
│ │ │ │ └── service.rs
│ │ │ ├── state_machine.rs
│ │ │ └── task_validator.rs
│ │ ├── mod.rs
│ │ └── tests/
│ │ ├── fetchers.rs
│ │ ├── mod.rs
│ │ └── utils.rs
│ ├── settings/
│ │ ├── mod.rs
│ │ └── s3.rs
│ ├── state_machine/
│ │ ├── coordinator.rs
│ │ ├── events.rs
│ │ ├── initializer.rs
│ │ ├── mod.rs
│ │ ├── phases/
│ │ │ ├── failure.rs
│ │ │ ├── handler.rs
│ │ │ ├── idle.rs
│ │ │ ├── mod.rs
│ │ │ ├── phase.rs
│ │ │ ├── shutdown.rs
│ │ │ ├── sum.rs
│ │ │ ├── sum2.rs
│ │ │ ├── unmask.rs
│ │ │ └── update.rs
│ │ ├── requests.rs
│ │ └── tests/
│ │ ├── coordinator_state.rs
│ │ ├── event_bus.rs
│ │ ├── impls.rs
│ │ ├── initializer.rs
│ │ ├── mod.rs
│ │ └── utils.rs
│ └── storage/
│ ├── coordinator_storage/
│ │ ├── mod.rs
│ │ └── redis/
│ │ ├── impls.rs
│ │ └── mod.rs
│ ├── mod.rs
│ ├── model_storage/
│ │ ├── mod.rs
│ │ ├── noop.rs
│ │ └── s3.rs
│ ├── store.rs
│ ├── tests/
│ │ ├── mod.rs
│ │ └── utils.rs
│ ├── traits.rs
│ └── trust_anchor/
│ ├── mod.rs
│ └── noop.rs
└── scripts/
└── bump_version.sh
SYMBOL INDEX (2131 symbols across 154 files)
FILE: bindings/python/examples/download_global_model.py
class Participant (line 12) | class Participant(xaynet_sdk.ParticipantABC):
method __init__ (line 13) | def __init__(self, model: list) -> None:
method deserialize_training_input (line 17) | def deserialize_training_input(self, global_model: list) -> list:
method train_round (line 20) | def train_round(self, training_input: Optional[list]) -> list:
method serialize_training_result (line 23) | def serialize_training_result(self, training_result: list) -> list:
method participate_in_update_task (line 26) | def participate_in_update_task(self) -> bool:
method on_new_global_model (line 29) | def on_new_global_model(self, global_model: Optional[list]) -> None:
function main (line 36) | def main() -> None:
FILE: bindings/python/examples/download_global_model_async.py
function main (line 11) | def main() -> None:
FILE: bindings/python/examples/hello_world.py
class Participant (line 13) | class Participant(xaynet_sdk.ParticipantABC):
method __init__ (line 14) | def __init__(self, model: list) -> None:
method deserialize_training_input (line 18) | def deserialize_training_input(self, global_model: list) -> list:
method train_round (line 21) | def train_round(self, training_input: Optional[list]) -> list:
method serialize_training_result (line 27) | def serialize_training_result(self, training_result: list) -> list:
method participate_in_update_task (line 30) | def participate_in_update_task(self) -> bool:
method on_new_global_model (line 33) | def on_new_global_model(self, global_model: Optional[list]) -> None:
function main (line 39) | def main() -> None:
FILE: bindings/python/examples/hello_world_async.py
function training (line 11) | def training():
function main (line 17) | def main() -> None:
FILE: bindings/python/examples/keras_house_prices/keras_house_prices/data_handlers/data_handler.py
class DataHandler (line 14) | class DataHandler(ABC): # pylint: disable=too-many-instance-attributes
method __init__ (line 49) | def __init__(
method read_data (line 72) | def read_data(self) -> None:
method preprocess_data (line 77) | def preprocess_data(self) -> None:
method create_testset (line 84) | def create_testset(self) -> None:
method make_discrete_y (line 98) | def make_discrete_y(self) -> pd.Series:
method make_iid_split (line 117) | def make_iid_split(
method split_lists (line 149) | def split_lists(
method make_total_split (line 189) | def make_total_split(
method make_intermediate_split (line 232) | def make_intermediate_split(
method split_data (line 273) | def split_data(self) -> None:
method run (line 326) | def run(self) -> None:
FILE: bindings/python/examples/keras_house_prices/keras_house_prices/data_handlers/regression_data.py
class RegressionData (line 14) | class RegressionData(DataHandler):
method __init__ (line 17) | def __init__(
method fill_nan (line 24) | def fill_nan(self) -> None:
method hot_encoding (line 86) | def hot_encoding(self) -> None:
method scaling (line 94) | def scaling(self) -> None:
method preprocess_data (line 106) | def preprocess_data(self) -> None:
function main (line 114) | def main() -> None:
FILE: bindings/python/examples/keras_house_prices/keras_house_prices/participant.py
class Participant (line 19) | class Participant( # pylint: disable=too-few-public-methods,too-many-in...
method __init__ (line 40) | def __init__(self, dataset_dir: str) -> None:
method load_random_dataset (line 47) | def load_random_dataset(self, dataset_dir: str) -> None:
method train_round (line 67) | def train_round(self, training_input: Optional[np.ndarray]) -> np.ndar...
method deserialize_training_input (line 103) | def deserialize_training_input(self, global_model: list) -> np.ndarray:
method serialize_training_result (line 106) | def serialize_training_result(self, training_result: np.ndarray) -> list:
method on_stop (line 109) | def on_stop(self) -> None:
function main (line 114) | def main() -> None:
FILE: bindings/python/examples/keras_house_prices/keras_house_prices/regressor.py
class Regressor (line 11) | class Regressor:
method __init__ (line 18) | def __init__(self, dim: int):
method train_n_epochs (line 27) | def train_n_epochs(
method evaluate_on_test (line 40) | def evaluate_on_test(
method get_shapes (line 60) | def get_shapes(self) -> List[Tuple[int, ...]]:
method get_weights (line 63) | def get_weights(self) -> np.ndarray:
method set_weights (line 66) | def set_weights(self, weights: np.ndarray) -> None:
FILE: bindings/python/examples/multiple_participants.py
class Participant (line 13) | class Participant(xaynet_sdk.ParticipantABC):
method __init__ (line 14) | def __init__(self, p_id: int, model: list) -> None:
method deserialize_training_input (line 19) | def deserialize_training_input(self, global_model: list) -> list:
method train_round (line 22) | def train_round(self, training_input: Optional[list]) -> list:
method serialize_training_result (line 28) | def serialize_training_result(self, training_result: list) -> list:
method participate_in_update_task (line 31) | def participate_in_update_task(self) -> bool:
method on_new_global_model (line 34) | def on_new_global_model(self, global_model: Optional[list]) -> None:
function main (line 40) | def main() -> None:
FILE: bindings/python/examples/participate_in_update.py
function get_battery_level (line 14) | def get_battery_level():
class Participant (line 18) | class Participant(xaynet_sdk.ParticipantABC):
method __init__ (line 19) | def __init__(self, model: list) -> None:
method deserialize_training_input (line 23) | def deserialize_training_input(self, global_model: list) -> list:
method train_round (line 26) | def train_round(self, training_input: Optional[list]) -> list:
method serialize_training_result (line 32) | def serialize_training_result(self, training_result: list) -> list:
method participate_in_update_task (line 35) | def participate_in_update_task(self) -> bool:
method on_new_global_model (line 42) | def on_new_global_model(self, global_model: Optional[list]) -> None:
function main (line 48) | def main() -> None:
FILE: bindings/python/examples/restore.py
function main (line 11) | def main() -> None:
FILE: bindings/python/src/python_ffi.rs
function xaynet_sdk (line 25) | fn xaynet_sdk(py: Python, m: &PyModule) -> PyResult<()> {
type Participant (line 58) | struct Participant {
method new (line 65) | pub fn new(url: String, scalar: f64, state: Option<Vec<u8>>) -> PyResu...
method tick (line 91) | pub fn tick(&mut self) -> PyResult<()> {
method set_model (line 106) | pub fn set_model(&mut self, local_model: &PyList) -> PyResult<()> {
method made_progress (line 142) | pub fn made_progress(&self) -> PyResult<bool> {
method should_set_model (line 159) | pub fn should_set_model(&self) -> PyResult<bool> {
method task (line 173) | pub fn task(&self) -> PyResult<u8> {
method new_global_model (line 195) | pub fn new_global_model(&self) -> PyResult<bool> {
method global_model (line 209) | pub fn global_model(&mut self, py: Python) -> PyResult<Option<Py<PyLis...
method save (line 237) | pub fn save(&mut self) -> PyResult<Vec<u8>> {
function init_logging (line 286) | fn init_logging() {
FILE: bindings/python/xaynet_sdk/__init__.py
function spawn_participant (line 8) | def spawn_participant(
function spawn_async_participant (line 59) | def spawn_async_participant(
FILE: bindings/python/xaynet_sdk/async_participant.py
class AsyncParticipant (line 15) | class AsyncParticipant(threading.Thread):
method __init__ (line 16) | def __init__(
method run (line 42) | def run(self):
method _notify (line 49) | def _notify(self):
method _run (line 54) | def _run(self):
method _tick (line 58) | def _tick(self):
method get_global_model (line 73) | def get_global_model(self) -> Optional[list]:
method set_local_model (line 93) | def set_local_model(self, local_model: list):
method stop (line 119) | def stop(self) -> List[int]:
FILE: bindings/python/xaynet_sdk/participant.py
class ParticipantABC (line 19) | class ParticipantABC(ABC):
method train_round (line 21) | def train_round(self, training_input: Optional[TrainingInput]) -> Trai...
method serialize_training_result (line 38) | def serialize_training_result(self, training_result: TrainingResult) -...
method deserialize_training_input (line 53) | def deserialize_training_input(self, global_model: list) -> TrainingIn...
method participate_in_update_task (line 69) | def participate_in_update_task(self) -> bool:
method on_new_global_model (line 84) | def on_new_global_model(self, global_model: Optional[TrainingInput]) -...
method on_stop (line 98) | def on_stop(self) -> None:
class InternalParticipant (line 113) | class InternalParticipant(threading.Thread):
method __init__ (line 114) | def __init__(
method run (line 148) | def run(self):
method _fetch_global_model (line 157) | def _fetch_global_model(self):
method _train (line 176) | def _train(self):
method _run (line 188) | def _run(self):
method _tick (line 192) | def _tick(self):
method stop (line 220) | def stop(self) -> List[int]:
FILE: rust/benches/messages/sum.rs
function participant_sk (line 14) | fn participant_sk() -> SecretSigningKey {
function to_bytes (line 18) | fn to_bytes(crit: &mut Criterion) {
function from_bytes (line 47) | fn from_bytes(crit: &mut Criterion) {
FILE: rust/benches/messages/update.rs
function make_update (line 9) | fn make_update(dict_len: usize, mask_len: usize, total_expected_len: usi...
FILE: rust/benches/models/from_primitives.rs
function make_vector (line 8) | fn make_vector(bytes_size: usize) -> Vec<i32> {
FILE: rust/benches/models/to_primitives.rs
function make_model (line 9) | fn make_model(bytes_size: usize) -> Model {
FILE: rust/examples/test-drive/main.rs
function main (line 21) | async fn main() -> Result<(), ClientError> {
function generate_agent_config (line 41) | fn generate_agent_config() -> PetSettings {
function build_http_client (line 46) | fn build_http_client(settings: &settings::Opt) -> reqwest::Client {
function spawn_participant (line 70) | fn spawn_participant(
FILE: rust/examples/test-drive/participant.rs
type Event (line 18) | enum Event {
type Participant (line 25) | pub struct Participant {
method new (line 66) | pub fn new(
method run (line 81) | pub async fn run(mut self) {
type Agent (line 35) | pub struct Agent(StateMachine);
method new (line 38) | fn new<X, M, N>(settings: PetSettings, xaynet_client: X, model_store: ...
method run (line 52) | pub async fn run(mut self, tick: Duration) {
type Notifier (line 109) | struct Notifier(mpsc::Sender<Event>);
method new_round (line 112) | fn new_round(&mut self) {
method sum (line 118) | fn sum(&mut self) {
method update (line 124) | fn update(&mut self) {
method idle (line 130) | fn idle(&mut self) {
type LocalModel (line 137) | pub struct LocalModel(Arc<Model>);
type Model (line 141) | type Model = Arc<Model>;
type Error (line 142) | type Error = std::convert::Infallible;
method load_model (line 144) | async fn load_model(&mut self) -> Result<Option<Self::Model>, Self::Erro...
FILE: rust/examples/test-drive/settings.rs
type Opt (line 7) | pub struct Opt {
FILE: rust/xaynet-analytics/src/controller.rs
type AnalyticsController (line 36) | struct AnalyticsController {
constant MAX_SEND_FREQUENCY_HOURS (line 49) | const MAX_SEND_FREQUENCY_HOURS: u8 = 24;
method init (line 51) | pub fn init(
method dispose (line 77) | pub fn dispose(self) -> Result<(), Error> {
method save_analytics_event (line 81) | pub fn save_analytics_event(
method change_connectivity_status (line 96) | pub fn change_connectivity_status(&mut self) {
method change_state_of_charge (line 100) | pub fn change_state_of_charge(&mut self) {
method maybe_send_data (line 104) | pub fn maybe_send_data(&mut self) -> Result<(), Error> {
method db (line 113) | fn db(&self) -> &IsarDb {
method validate_send_frequency (line 120) | fn validate_send_frequency(input_send_frequency_hours: Option<u8>) -> ...
method should_send_data (line 133) | fn should_send_data(&self) -> bool {
method add_screen_route_if_new (line 141) | fn add_screen_route_if_new(
method get_last_time_data_sent (line 162) | fn get_last_time_data_sent(db: &IsarDb) -> Result<Option<DateTime<Utc>...
method did_send_already_in_this_period (line 189) | fn did_send_already_in_this_period(&self) -> bool {
method send_data (line 210) | fn send_data(&mut self) -> Result<(), Error> {
function get_path (line 230) | fn get_path(test_name: &str) -> PathBuf {
function get_controller (line 235) | fn get_controller(
function remove_dir (line 247) | fn remove_dir(test_name: &str) {
function cleanup (line 252) | fn cleanup(controller: AnalyticsController, test_name: &str) {
function test_dispose (line 258) | fn test_dispose() {
function test_save_analytics_event_no_screen_route (line 266) | fn test_save_analytics_event_no_screen_route() {
function test_save_analytics_event_with_screen_route (line 291) | fn test_save_analytics_event_with_screen_route() {
function test_change_connectivity_status (line 315) | fn test_change_connectivity_status() {
function test_change_state_of_charge (line 326) | fn test_change_state_of_charge() {
function test_validate_send_data_frequency_when_none (line 337) | fn test_validate_send_data_frequency_when_none() {
function test_validate_send_data_frequency_when_more_than_24 (line 345) | fn test_validate_send_data_frequency_when_more_than_24() {
function test_validate_send_data_frequency_when_less_than_24 (line 350) | fn test_validate_send_data_frequency_when_less_than_24() {
function test_validate_send_data_frequency_when_0 (line 358) | fn test_validate_send_data_frequency_when_0() {
function test_add_screen_route_if_new_with_new_route (line 366) | fn test_add_screen_route_if_new_with_new_route() {
function test_add_screen_route_if_new_without_new_route (line 393) | fn test_add_screen_route_if_new_without_new_route() {
function test_get_last_time_data_sent (line 426) | fn test_get_last_time_data_sent() {
function test_did_send_already_in_this_period_never_sent_before (line 453) | fn test_did_send_already_in_this_period_never_sent_before() {
function test_did_send_already_in_this_period_inside_24h (line 462) | fn test_did_send_already_in_this_period_inside_24h() {
function test_did_send_already_in_this_period_outside_24h (line 481) | fn test_did_send_already_in_this_period_outside_24h() {
function test_did_send_already_in_this_period_inside_12h (line 500) | fn test_did_send_already_in_this_period_inside_12h() {
function test_did_send_already_in_this_period_outside_12h (line 519) | fn test_did_send_already_in_this_period_outside_12h() {
function test_did_send_already_in_this_period_inside_6h (line 538) | fn test_did_send_already_in_this_period_inside_6h() {
function test_did_send_already_in_this_period_outside_6h (line 557) | fn test_did_send_already_in_this_period_outside_6h() {
function test_did_send_already_in_this_period_outside_twice_6h (line 576) | fn test_did_send_already_in_this_period_outside_twice_6h() {
function test_did_send_already_in_this_period_outside_thrice_6h (line 595) | fn test_did_send_already_in_this_period_outside_thrice_6h() {
FILE: rust/xaynet-analytics/src/data_combination/data_combiner.rs
type DataCombiner (line 32) | pub struct DataCombiner;
method init_data_points (line 35) | pub fn init_data_points(
method init_screen_active_time_vars (line 78) | fn init_screen_active_time_vars(
method init_screen_enter_count_vars (line 101) | fn init_screen_enter_count_vars(
method init_was_active_each_past_period_vars (line 119) | fn init_was_active_each_past_period_vars(
method init_was_active_past_n_days_vars (line 139) | fn init_was_active_past_n_days_vars(
method filter_events_in_this_period (line 156) | fn filter_events_in_this_period(
method get_start_of_period (line 168) | fn get_start_of_period(
method filter_events_before_end_of_period (line 190) | fn filter_events_before_end_of_period(
method get_events_single_route (line 203) | fn get_events_single_route(
function get_midnight (line 215) | fn get_midnight(timestamp: DateTime<Utc>) -> DateTime<Utc> {
function test_init_screen_active_time_vars (line 247) | fn test_init_screen_active_time_vars() {
function test_init_screen_enter_count_vars (line 278) | fn test_init_screen_enter_count_vars() {
function test_init_was_active_each_past_period_vars (line 300) | fn test_init_was_active_each_past_period_vars() {
function test_init_was_active_past_n_days_vars (line 321) | fn test_init_was_active_past_n_days_vars() {
function test_filter_events_in_this_period (line 341) | fn test_filter_events_in_this_period() {
function test_get_start_of_period_one_day (line 371) | fn test_get_start_of_period_one_day() {
function test_get_start_of_period_one_day_with_override (line 382) | fn test_get_start_of_period_one_day_with_override() {
function test_get_start_of_period_one_week (line 393) | fn test_get_start_of_period_one_week() {
function test_get_start_of_period_one_month (line 404) | fn test_get_start_of_period_one_month() {
function text_filter_events_before_end_of_period (line 415) | fn text_filter_events_before_end_of_period() {
function test_get_events_single_route (line 437) | fn test_get_events_single_route() {
function test_get_midnight (line 460) | fn test_get_midnight() {
FILE: rust/xaynet-analytics/src/data_combination/data_points/data_point.rs
type PeriodUnit (line 8) | pub enum PeriodUnit {
type Period (line 17) | pub struct Period {
method new (line 23) | pub fn new(unit: PeriodUnit, n: u32) -> Self {
type DataPointMetadata (line 32) | pub struct DataPointMetadata {
method new (line 38) | pub fn new(period: Period, end: DateTime<Utc>) -> Self {
type CalculateDataPoints (line 43) | pub trait CalculateDataPoints {
method metadata (line 44) | fn metadata(&self) -> DataPointMetadata;
method calculate (line 46) | fn calculate(&self) -> Vec<u32>;
type DataPoint (line 59) | pub enum DataPoint {
method calculate (line 69) | fn calculate(&self) -> Vec<u32> {
type CalcScreenActiveTime (line 81) | pub struct CalcScreenActiveTime {
type CalcScreenEnterCount (line 88) | pub struct CalcScreenEnterCount {
type CalcWasActiveEachPastPeriod (line 95) | pub struct CalcWasActiveEachPastPeriod {
type CalcWasActivePastNDays (line 103) | pub struct CalcWasActivePastNDays {
FILE: rust/xaynet-analytics/src/data_combination/data_points/screen_active_time.rs
method new (line 13) | pub fn new(metadata: DataPointMetadata, events: Vec<AnalyticsEvent>) -> ...
method get_screen_and_app_events (line 18) | fn get_screen_and_app_events(&self) -> Vec<AnalyticsEvent> {
method metadata (line 33) | fn metadata(&self) -> DataPointMetadata {
method calculate (line 37) | fn calculate(&self) -> Vec<u32> {
function test_get_screen_and_app_events (line 74) | fn test_get_screen_and_app_events() {
function test_calculate_when_no_events (line 115) | fn test_calculate_when_no_events() {
function test_calculate_when_one_screen_enter_event (line 122) | fn test_calculate_when_one_screen_enter_event() {
function test_calculate_when_two_screen_enter_events (line 139) | fn test_calculate_when_two_screen_enter_events() {
function test_calculate_when_mixed_type_events (line 169) | fn test_calculate_when_mixed_type_events() {
FILE: rust/xaynet-analytics/src/data_combination/data_points/screen_enter_count.rs
method new (line 11) | pub fn new(metadata: DataPointMetadata, events: Vec<AnalyticsEvent>) -> ...
method metadata (line 17) | fn metadata(&self) -> DataPointMetadata {
method calculate (line 21) | fn calculate(&self) -> Vec<u32> {
function test_calculate_when_no_events (line 42) | fn test_calculate_when_no_events() {
function test_calculate_when_one_event (line 49) | fn test_calculate_when_one_event() {
function test_calculate_when_two_events (line 66) | fn test_calculate_when_two_events() {
FILE: rust/xaynet-analytics/src/data_combination/data_points/was_active_each_past_period.rs
method new (line 14) | pub fn new(
method group_timestamps_by_period_threshold (line 27) | fn group_timestamps_by_period_threshold(&self) -> BTreeMap<DateTime<Utc>...
method metadata (line 49) | fn metadata(&self) -> DataPointMetadata {
method calculate (line 53) | fn calculate(&self) -> Vec<u32> {
function test_calculate_no_events_in_a_period (line 75) | fn test_calculate_no_events_in_a_period() {
function test_calculate_one_event_in_a_period (line 87) | fn test_calculate_one_event_in_a_period() {
function test_calculate_no_events_in_two_periods (line 105) | fn test_calculate_no_events_in_two_periods() {
function test_calculate_one_event_in_one_period_zero_in_another (line 121) | fn test_calculate_one_event_in_one_period_zero_in_another() {
function test_calculate_two_events_in_one_period_zero_in_another (line 143) | fn test_calculate_two_events_in_one_period_zero_in_another() {
function test_calculate_two_periods_with_one_event_each (line 173) | fn test_calculate_two_periods_with_one_event_each() {
FILE: rust/xaynet-analytics/src/data_combination/data_points/was_active_past_n_days.rs
method new (line 11) | pub fn new(metadata: DataPointMetadata, events: Vec<AnalyticsEvent>) -> ...
method metadata (line 17) | fn metadata(&self) -> DataPointMetadata {
method calculate (line 21) | fn calculate(&self) -> Vec<u32> {
function test_calculate_without_events (line 37) | fn test_calculate_without_events() {
function test_calculate_with_events (line 44) | fn test_calculate_with_events() {
FILE: rust/xaynet-analytics/src/database/analytics_event/adapter.rs
type AnalyticsEventAdapter (line 21) | pub struct AnalyticsEventAdapter {
method new (line 29) | pub fn new<N: Into<String>>(
method get_oid (line 45) | fn get_oid(&self) -> String {
method into_field_properties (line 49) | fn into_field_properties() -> IntoIter<FieldProperty> {
method write_with_object_builder (line 60) | fn write_with_object_builder(&self, object_builder: &mut ObjectBuilder) {
method read (line 68) | fn read(
type AnalyticsEventRelationalAdapter (line 105) | pub struct AnalyticsEventRelationalAdapter {
method new (line 113) | pub fn new(adapter: AnalyticsEventAdapter, db: &IsarDb) -> Result<Self...
FILE: rust/xaynet-analytics/src/database/analytics_event/data_model.rs
type AnalyticsEventType (line 21) | pub enum AnalyticsEventType {
type Error (line 29) | type Error = anyhow::Error;
method try_from (line 31) | fn try_from(v: i32) -> Result<Self, Self::Error> {
type AnalyticsEvent (line 53) | pub struct AnalyticsEvent {
method new (line 61) | pub fn new<N: Into<String>>(
type Error (line 77) | type Error = anyhow::Error;
method try_from (line 79) | fn try_from(adapter: AnalyticsEventRelationalAdapter) -> Result<Self, ...
method from (line 94) | fn from(ae: AnalyticsEvent) -> Self {
function test_analytics_event_type_try_from_valid_i32 (line 110) | fn test_analytics_event_type_try_from_valid_i32() {
function test_analytics_event_type_invalid_i32 (line 130) | fn test_analytics_event_type_invalid_i32() {
function test_analytics_event_try_from_relational_adapter_without_screen_route (line 135) | fn test_analytics_event_try_from_relational_adapter_without_screen_route...
function test_analytics_event_try_from_relational_adapter_with_screen_route (line 158) | fn test_analytics_event_try_from_relational_adapter_with_screen_route() {
function test_analytics_event_try_into_adapter_without_screen_route (line 183) | fn test_analytics_event_try_into_adapter_without_screen_route() {
function test_analytics_event_try_into_adapter_with_screen_route (line 202) | fn test_analytics_event_try_into_adapter_with_screen_route() {
FILE: rust/xaynet-analytics/src/database/analytics_event/repo.rs
method save (line 19) | fn save(self, db: &'db IsarDb, collection_name: &str) -> Result<(), Erro...
method get_all (line 27) | fn get_all(db: &'db IsarDb, collection_name: &str) -> Result<Vec<Self>, ...
method get (line 37) | fn get(oid: &str, db: &'db IsarDb, collection_name: &str) -> Result<Self...
FILE: rust/xaynet-analytics/src/database/common.rs
type IsarAdapter (line 29) | pub trait IsarAdapter<'object>: Sized {
method get_oid (line 30) | fn get_oid(&self) -> String;
method into_field_properties (line 32) | fn into_field_properties() -> IntoIter<FieldProperty>;
method write_with_object_builder (line 34) | fn write_with_object_builder(&self, object_builder: &mut ObjectBuilder);
method read (line 36) | fn read(
method find_property_by_name (line 41) | fn find_property_by_name(
type Repo (line 58) | pub trait Repo<'db, M>
method save (line 62) | fn save(self, db: &'db IsarDb, collection_name: &str) -> Result<(), Er...
method get_all (line 64) | fn get_all(db: &'db IsarDb, collection_name: &str) -> Result<Vec<M>, E...
method get (line 66) | fn get(object_id: &str, db: &'db IsarDb, collection_name: &str) -> Res...
type FieldProperty (line 70) | pub struct FieldProperty {
method new (line 80) | pub fn new<N: Into<String>>(name: N, data_type: DataType, is_oid: bool...
type SchemaGenerator (line 97) | pub trait SchemaGenerator<'object, A>
method get_schema (line 101) | fn get_schema(name: &str) -> Result<CollectionSchema, Error> {
type RelationalField (line 129) | pub struct RelationalField {
type Error (line 137) | type Error = anyhow::Error;
method try_from (line 139) | fn try_from(data: &str) -> Result<Self, Error> {
method from (line 156) | fn from(rf: RelationalField) -> String {
type CollectionNames (line 163) | pub struct CollectionNames;
constant ANALYTICS_EVENTS (line 166) | pub const ANALYTICS_EVENTS: &'static str = "analytics_events";
constant CONTROLLER_DATA (line 167) | pub const CONTROLLER_DATA: &'static str = "controller_data";
constant SCREEN_ROUTES (line 168) | pub const SCREEN_ROUTES: &'static str = "screen_routes";
FILE: rust/xaynet-analytics/src/database/controller_data/adapter.rs
type ControllerDataAdapter (line 16) | pub struct ControllerDataAdapter {
method new (line 21) | pub fn new<T: Into<String>>(time_data_sent: T) -> Self {
method get_oid (line 29) | fn get_oid(&self) -> String {
method into_field_properties (line 33) | fn into_field_properties() -> IntoIter<FieldProperty> {
method write_with_object_builder (line 41) | fn write_with_object_builder(&self, object_builder: &mut ObjectBuilder) {
method read (line 46) | fn read(
FILE: rust/xaynet-analytics/src/database/controller_data/data_model.rs
type ControllerData (line 12) | pub struct ControllerData {
method new (line 17) | pub fn new(time_data_sent: DateTime<Utc>) -> Self {
type Error (line 23) | type Error = anyhow::Error;
method try_from (line 25) | fn try_from(adapter: ControllerDataAdapter) -> Result<Self, Self::Erro...
method from (line 33) | fn from(cd: ControllerData) -> Self {
function test_controller_data_try_from_adapter (line 43) | fn test_controller_data_try_from_adapter() {
function test_adapter_into_controller_data (line 54) | fn test_adapter_into_controller_data() {
FILE: rust/xaynet-analytics/src/database/controller_data/repo.rs
method save (line 13) | fn save(self, db: &'db IsarDb, collection_name: &str) -> Result<(), Erro...
method get_all (line 21) | fn get_all(db: &'db IsarDb, collection_name: &str) -> Result<Vec<Self>, ...
method get (line 30) | fn get(oid: &str, db: &'db IsarDb, collection_name: &str) -> Result<Self...
FILE: rust/xaynet-analytics/src/database/isar.rs
type IsarDb (line 19) | pub struct IsarDb {
constant MAX_SIZE (line 24) | const MAX_SIZE: usize = 10000000;
method new (line 30) | pub fn new(path: &str, collection_schemas: Vec<CollectionSchema>) -> R...
method get_all_isar_objects (line 40) | pub fn get_all_isar_objects(
method get_read_transaction (line 60) | pub fn get_read_transaction(&self) -> Result<IsarTxn, Error> {
method get_isar_object_by_id (line 64) | pub fn get_isar_object_by_id<'txn>(
method put (line 75) | pub fn put(&self, collection_name: &str, object: &[u8]) -> Result<(), ...
method get_object_builder (line 90) | pub fn get_object_builder(&self, collection_name: &str) -> Result<Obje...
method get_object_id_from_str (line 97) | pub fn get_object_id_from_str(
method get_collection_properties (line 109) | pub fn get_collection_properties(
method dispose (line 116) | pub fn dispose(self) -> Result<(), Error> {
method get_schema (line 125) | fn get_schema(collection_schemas: Vec<CollectionSchema>) -> Result<Sch...
method get_collection (line 134) | fn get_collection(&self, collection_name: &str) -> Result<&IsarCollect...
method begin_txn (line 141) | fn begin_txn(&self, is_write: bool) -> Result<IsarTxn, Error> {
FILE: rust/xaynet-analytics/src/database/screen_route/adapter.rs
type ScreenRouteAdapter (line 16) | pub struct ScreenRouteAdapter {
method new (line 22) | pub fn new<S: Into<String>>(name: S, created_at: S) -> Self {
method get_oid (line 31) | fn get_oid(&self) -> String {
method into_field_properties (line 35) | fn into_field_properties() -> IntoIter<FieldProperty> {
method write_with_object_builder (line 44) | fn write_with_object_builder(&self, object_builder: &mut ObjectBuilder) {
method read (line 50) | fn read(
FILE: rust/xaynet-analytics/src/database/screen_route/data_model.rs
type ScreenRoute (line 14) | pub struct ScreenRoute {
method new (line 20) | pub fn new<N: Into<String>>(name: N, created_at: DateTime<Utc>) -> Self {
type Error (line 29) | type Error = anyhow::Error;
method try_from (line 31) | fn try_from(adapter: ScreenRouteAdapter) -> Result<Self, Self::Error> {
method from (line 40) | fn from(sr: ScreenRoute) -> Self {
method from (line 46) | fn from(screen_route: ScreenRoute) -> Self {
function test_screen_route_try_from_adapter (line 59) | fn test_screen_route_try_from_adapter() {
function test_adapter_into_screen_route (line 70) | fn test_adapter_into_screen_route() {
function test_screen_route_from_relational_field (line 82) | fn test_screen_route_from_relational_field() {
FILE: rust/xaynet-analytics/src/database/screen_route/repo.rs
method save (line 13) | fn save(self, db: &'db IsarDb, collection_name: &str) -> Result<(), Erro...
method get_all (line 21) | fn get_all(db: &'db IsarDb, collection_name: &str) -> Result<Vec<Self>, ...
method get (line 30) | fn get(oid: &str, db: &'db IsarDb, collection_name: &str) -> Result<Self...
FILE: rust/xaynet-analytics/src/sender.rs
type Sender (line 15) | pub struct Sender;
method send (line 18) | pub fn send(&self, _data_points: Vec<DataPoint>) -> Result<(), Error> {
FILE: rust/xaynet-core/src/common.rs
type RoundParameters (line 8) | pub struct RoundParameters {
type RoundSeed (line 25) | pub struct RoundSeed(box_::Seed);
constant LENGTH (line 28) | const LENGTH: usize = box_::SEEDBYTES;
method from_slice (line 34) | fn from_slice(bytes: &[u8]) -> Option<Self> {
method zeroed (line 39) | fn zeroed() -> Self {
method as_slice (line 44) | fn as_slice(&self) -> &[u8] {
FILE: rust/xaynet-core/src/crypto/encrypt.rs
constant SEALBYTES (line 15) | pub const SEALBYTES: usize = sealedbox::SEALBYTES;
type EncryptKeyPair (line 19) | pub struct EncryptKeyPair {
method generate (line 28) | pub fn generate() -> Self {
method derive_from_seed (line 37) | pub fn derive_from_seed(seed: &EncryptKeySeed) -> Self {
type PublicEncryptKey (line 62) | pub struct PublicEncryptKey(box_::PublicKey);
method encrypt (line 88) | pub fn encrypt(&self, m: &[u8]) -> Vec<u8> {
constant LENGTH (line 65) | const LENGTH: usize = box_::PUBLICKEYBYTES;
method zeroed (line 67) | fn zeroed() -> Self {
method as_slice (line 71) | fn as_slice(&self) -> &[u8] {
method from_slice (line 75) | fn from_slice(bytes: &[u8]) -> Option<Self> {
type DecryptionError (line 96) | pub struct DecryptionError;
type SecretEncryptKey (line 102) | pub struct SecretEncryptKey(box_::SecretKey);
method decrypt (line 110) | pub fn decrypt(&self, c: &[u8], pk: &PublicEncryptKey) -> Result<Vec<u...
method public_key (line 115) | pub fn public_key(&self) -> PublicEncryptKey {
constant LENGTH (line 121) | const LENGTH: usize = box_::SECRETKEYBYTES;
method zeroed (line 123) | fn zeroed() -> Self {
method as_slice (line 127) | fn as_slice(&self) -> &[u8] {
method from_slice (line 131) | fn from_slice(bytes: &[u8]) -> Option<Self> {
type EncryptKeySeed (line 140) | pub struct EncryptKeySeed(box_::Seed);
method derive_encrypt_key_pair (line 144) | pub fn derive_encrypt_key_pair(&self) -> (PublicEncryptKey, SecretEncr...
constant LENGTH (line 151) | const LENGTH: usize = box_::SEEDBYTES;
method from_slice (line 153) | fn from_slice(bytes: &[u8]) -> Option<Self> {
method zeroed (line 157) | fn zeroed() -> Self {
method as_slice (line 161) | fn as_slice(&self) -> &[u8] {
FILE: rust/xaynet-core/src/crypto/hash.rs
type Sha256 (line 30) | pub struct Sha256(sha256::Digest);
method hash (line 50) | pub fn hash(m: &[u8]) -> Self {
constant LENGTH (line 33) | const LENGTH: usize = sha256::DIGESTBYTES;
method zeroed (line 35) | fn zeroed() -> Self {
method as_slice (line 39) | fn as_slice(&self) -> &[u8] {
method from_slice (line 43) | fn from_slice(bytes: &[u8]) -> Option<Self> {
FILE: rust/xaynet-core/src/crypto/mod.rs
type ByteObject (line 44) | pub trait ByteObject: Sized {
constant LENGTH (line 46) | const LENGTH: usize;
method zeroed (line 49) | fn zeroed() -> Self;
method as_slice (line 52) | fn as_slice(&self) -> &[u8];
method from_slice (line 58) | fn from_slice(bytes: &[u8]) -> Option<Self>;
method from_slice_unchecked (line 64) | fn from_slice_unchecked(bytes: &[u8]) -> Self {
method generate (line 69) | fn generate() -> Self {
method fill_with (line 75) | fn fill_with(value: u8) -> Self {
FILE: rust/xaynet-core/src/crypto/prng.rs
function generate_integer (line 16) | pub fn generate_integer(prng: &mut ChaCha20Rng, max_int: &BigUint) -> Bi...
function test_generate_integer (line 37) | fn test_generate_integer() {
FILE: rust/xaynet-core/src/crypto/sign.rs
type SigningKeyPair (line 22) | pub struct SigningKeyPair {
method generate (line 31) | pub fn generate() -> Self {
method derive_from_seed (line 39) | pub fn derive_from_seed(seed: &SigningKeySeed) -> Self {
type PublicSigningKey (line 64) | pub struct PublicSigningKey(sign::PublicKey);
method verify_detached (line 70) | pub fn verify_detached(&self, s: &Signature, m: &[u8]) -> bool {
constant LENGTH (line 76) | const LENGTH: usize = sign::PUBLICKEYBYTES;
method zeroed (line 78) | fn zeroed() -> Self {
method as_slice (line 82) | fn as_slice(&self) -> &[u8] {
method from_slice (line 86) | fn from_slice(bytes: &[u8]) -> Option<Self> {
type SecretSigningKey (line 95) | pub struct SecretSigningKey(sign::SecretKey);
method sign_detached (line 99) | pub fn sign_detached(&self, m: &[u8]) -> Signature {
method public_key (line 104) | pub fn public_key(&self) -> PublicSigningKey {
constant LENGTH (line 110) | const LENGTH: usize = sign::SECRETKEYBYTES;
method zeroed (line 112) | fn zeroed() -> Self {
method as_slice (line 116) | fn as_slice(&self) -> &[u8] {
method from_slice (line 120) | fn from_slice(bytes: &[u8]) -> Option<Self> {
type Signature (line 127) | pub struct Signature(sign::Signature);
method deserialize (line 148) | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
method is_eligible (line 186) | pub fn is_eligible(&self, threshold: f64) -> bool {
method serialize (line 139) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
constant LENGTH (line 165) | const LENGTH: usize = sign::SIGNATUREBYTES;
method zeroed (line 167) | fn zeroed() -> Self {
method as_slice (line 171) | fn as_slice(&self) -> &[u8] {
method from_slice (line 175) | fn from_slice(bytes: &[u8]) -> Option<Self> {
type SigningKeySeed (line 208) | pub struct SigningKeySeed(sign::Seed);
method derive_signing_key_pair (line 212) | pub fn derive_signing_key_pair(&self) -> (PublicSigningKey, SecretSign...
constant LENGTH (line 219) | const LENGTH: usize = sign::SEEDBYTES;
method from_slice (line 221) | fn from_slice(bytes: &[u8]) -> Option<Self> {
method zeroed (line 225) | fn zeroed() -> Self {
method as_slice (line 229) | fn as_slice(&self) -> &[u8] {
function test_signature_is_eligible (line 239) | fn test_signature_is_eligible() {
FILE: rust/xaynet-core/src/lib.rs
type InitError (line 38) | pub struct InitError;
type CoordinatorPublicKey (line 41) | pub type CoordinatorPublicKey = PublicEncryptKey;
type CoordinatorSecretKey (line 45) | pub type CoordinatorSecretKey = SecretEncryptKey;
type ParticipantPublicKey (line 48) | pub type ParticipantPublicKey = PublicSigningKey;
type ParticipantSecretKey (line 52) | pub type ParticipantSecretKey = SecretSigningKey;
type SumParticipantPublicKey (line 55) | pub type SumParticipantPublicKey = ParticipantPublicKey;
type SumParticipantSecretKey (line 59) | pub type SumParticipantSecretKey = ParticipantSecretKey;
type SumParticipantEphemeralPublicKey (line 64) | pub type SumParticipantEphemeralPublicKey = PublicEncryptKey;
type SumParticipantEphemeralSecretKey (line 67) | pub type SumParticipantEphemeralSecretKey = SecretEncryptKey;
type UpdateParticipantPublicKey (line 70) | pub type UpdateParticipantPublicKey = ParticipantPublicKey;
type UpdateParticipantSecretKey (line 74) | pub type UpdateParticipantSecretKey = ParticipantSecretKey;
type ParticipantTaskSignature (line 77) | pub type ParticipantTaskSignature = Signature;
type SumDict (line 81) | pub type SumDict = HashMap<SumParticipantPublicKey, SumParticipantEpheme...
type LocalSeedDict (line 85) | pub type LocalSeedDict = HashMap<SumParticipantPublicKey, mask::seed::En...
type SeedDict (line 90) | pub type SeedDict = HashMap<SumParticipantPublicKey, UpdateSeedDict>;
type UpdateSeedDict (line 93) | pub type UpdateSeedDict = HashMap<UpdateParticipantPublicKey, mask::seed...
FILE: rust/xaynet-core/src/mask/config/mod.rs
constant MAX_BPN (line 21) | const MAX_BPN: u64 = u16::MAX as u64;
constant MAX_BPN (line 23) | const MAX_BPN: u64 = u32::MAX as u64;
type InvalidMaskConfigError (line 27) | pub enum InvalidMaskConfigError {
type GroupType (line 41) | pub enum GroupType {
type Error (line 51) | type Error = InvalidMaskConfigError;
method try_from (line 53) | fn try_from(byte: u8) -> Result<Self, Self::Error> {
type DataType (line 66) | pub enum DataType {
type Error (line 78) | type Error = InvalidMaskConfigError;
method try_from (line 80) | fn try_from(byte: u8) -> Result<Self, Self::Error> {
type BoundType (line 97) | pub enum BoundType {
type Error (line 112) | type Error = InvalidMaskConfigError;
method try_from (line 114) | fn try_from(byte: u8) -> Result<Self, Self::Error> {
type ModelType (line 129) | pub enum ModelType {
method max_nb_models (line 142) | pub fn max_nb_models(&self) -> usize {
type Error (line 148) | type Error = InvalidMaskConfigError;
method try_from (line 150) | fn try_from(byte: u8) -> Result<Self, Self::Error> {
type MaskConfig (line 165) | pub struct MaskConfig {
method bytes_per_number (line 181) | pub(crate) fn bytes_per_number(&self) -> usize {
method add_shift (line 196) | pub fn add_shift(&self) -> Ratio<BigInt> {
method exp_shift (line 216) | pub fn exp_shift(&self) -> BigInt {
method order (line 234) | pub fn order(&self) -> BigUint {
type MaskConfigPair (line 642) | pub struct MaskConfigPair {
method from (line 649) | fn from(config: MaskConfig) -> Self {
FILE: rust/xaynet-core/src/mask/config/serialization.rs
constant GROUP_TYPE_FIELD (line 19) | const GROUP_TYPE_FIELD: usize = 0;
constant DATA_TYPE_FIELD (line 20) | const DATA_TYPE_FIELD: usize = 1;
constant BOUND_TYPE_FIELD (line 21) | const BOUND_TYPE_FIELD: usize = 2;
constant MODEL_TYPE_FIELD (line 22) | const MODEL_TYPE_FIELD: usize = 3;
constant MASK_CONFIG_BUFFER_LEN (line 23) | pub(crate) const MASK_CONFIG_BUFFER_LEN: usize = 4;
type MaskConfigBuffer (line 26) | pub struct MaskConfigBuffer<T> {
function new (line 35) | pub fn new(bytes: T) -> Result<Self, DecodeError> {
function new_unchecked (line 44) | pub fn new_unchecked(bytes: T) -> Self {
function check_buffer_length (line 52) | pub fn check_buffer_length(&self) -> Result<(), DecodeError> {
function group_type (line 68) | pub fn group_type(&self) -> u8 {
function data_type (line 76) | pub fn data_type(&self) -> u8 {
function bound_type (line 84) | pub fn bound_type(&self) -> u8 {
function model_type (line 92) | pub fn model_type(&self) -> u8 {
function set_group_type (line 102) | pub fn set_group_type(&mut self, value: u8) {
function set_data_type (line 110) | pub fn set_data_type(&mut self, value: u8) {
function set_bound_type (line 118) | pub fn set_bound_type(&mut self, value: u8) {
function set_model_type (line 126) | pub fn set_model_type(&mut self, value: u8) {
method buffer_length (line 132) | fn buffer_length(&self) -> usize {
method to_bytes (line 136) | fn to_bytes<T: AsMut<[u8]>>(&self, buffer: &mut T) {
method from_byte_slice (line 146) | fn from_byte_slice<T: AsRef<[u8]>>(buffer: &T) -> Result<Self, DecodeErr...
method from_byte_stream (line 168) | fn from_byte_stream<I: Iterator<Item = u8> + ExactSizeIterator>(
function serialize (line 182) | fn serialize() {
function deserialize (line 196) | fn deserialize() {
function stream_deserialize (line 211) | fn stream_deserialize() {
FILE: rust/xaynet-core/src/mask/masking.rs
type UnmaskingError (line 32) | pub enum UnmaskingError {
type AggregationError (line 54) | pub enum AggregationError {
type Aggregation (line 74) | pub struct Aggregation {
method from (line 81) | fn from(object: MaskObject) -> Self {
method new (line 99) | pub fn new(config: MaskConfigPair, object_size: usize) -> Self {
method len (line 108) | pub fn len(&self) -> usize {
method config (line 113) | pub fn config(&self) -> MaskConfigPair {
method validate_unmasking (line 142) | pub fn validate_unmasking(&self, mask: &MaskObject) -> Result<(), Unma...
method unmask (line 190) | pub fn unmask(self, mask_obj: MaskObject) -> Model {
method validate_aggregation (line 253) | pub fn validate_aggregation(&self, object: &MaskObject) -> Result<(), ...
method aggregate (line 292) | pub fn aggregate(&mut self, object: MaskObject) {
method from (line 91) | fn from(aggr: Aggregation) -> Self {
type Masker (line 320) | pub struct Masker {
method new (line 327) | pub fn new(config: MaskConfigPair) -> Self {
method with_seed (line 335) | pub fn with_seed(config: MaskConfigPair, seed: MaskSeed) -> Self {
method mask (line 358) | pub fn mask(self, scalar: Scalar, model: &Model) -> (MaskSeed, MaskObj...
method random_ints (line 410) | fn random_ints(&self) -> (BigUint, impl Iterator<Item = BigUint>) {
FILE: rust/xaynet-core/src/mask/model.rs
type Model (line 25) | pub struct Model(Vec<Ratio<BigInt>>);
method as_ref (line 28) | fn as_ref(&self) -> &Model {
method len (line 36) | pub fn len(&self) -> usize {
method iter (line 41) | pub fn iter(&self) -> Iter<Ratio<BigInt>> {
method iter_mut (line 46) | pub fn iter_mut(&mut self) -> IterMut<Ratio<BigInt>> {
method from_iter (line 52) | fn from_iter<I: IntoIterator<Item = Ratio<BigInt>>>(iter: I) -> Self {
method into_primitives (line 140) | fn into_primitives(self) -> Box<dyn Iterator<Item = Result<i32, ModelC...
method to_primitives (line 149) | fn to_primitives(&self) -> Box<dyn Iterator<Item = Result<i32, ModelCa...
method from_primitives (line 161) | fn from_primitives<I: Iterator<Item = i32>>(iter: I) -> Result<Self, P...
method from_primitives_bounded (line 165) | fn from_primitives_bounded<I: Iterator<Item = i32>>(iter: I) -> Self {
method into_primitives (line 171) | fn into_primitives(self) -> Box<dyn Iterator<Item = Result<i64, ModelC...
method to_primitives (line 180) | fn to_primitives(&self) -> Box<dyn Iterator<Item = Result<i64, ModelCa...
method from_primitives (line 192) | fn from_primitives<I: Iterator<Item = i64>>(iter: I) -> Result<Self, P...
method from_primitives_bounded (line 196) | fn from_primitives_bounded<I: Iterator<Item = i64>>(iter: I) -> Self {
method into_primitives (line 202) | fn into_primitives(self) -> Box<dyn Iterator<Item = Result<f32, ModelC...
method to_primitives (line 212) | fn to_primitives(&self) -> Box<dyn Iterator<Item = Result<f32, ModelCa...
method from_primitives (line 225) | fn from_primitives<I: Iterator<Item = f32>>(iter: I) -> Result<Self, P...
method from_primitives_bounded (line 230) | fn from_primitives_bounded<I: Iterator<Item = f32>>(iter: I) -> Self {
method into_primitives (line 236) | fn into_primitives(self) -> Box<dyn Iterator<Item = Result<f64, ModelC...
method to_primitives (line 246) | fn to_primitives(&self) -> Box<dyn Iterator<Item = Result<f64, ModelCa...
method from_primitives (line 259) | fn from_primitives<I: Iterator<Item = f64>>(iter: I) -> Result<Self, P...
method from_primitives_bounded (line 264) | fn from_primitives_bounded<I: Iterator<Item = f64>>(iter: I) -> Self {
type Item (line 59) | type Item = Ratio<BigInt>;
type IntoIter (line 60) | type IntoIter = std::vec::IntoIter<Self::Item>;
method into_iter (line 62) | fn into_iter(self) -> Self::IntoIter {
type PrimitiveType (line 69) | pub(crate) enum PrimitiveType {
type ModelCastError (line 79) | pub struct ModelCastError {
type PrimitiveCastError (line 87) | pub struct PrimitiveCastError<P: Debug>(pub(crate) P);
type IntoPrimitives (line 94) | pub trait IntoPrimitives<P: 'static>: Sized {
method into_primitives (line 99) | fn into_primitives(self) -> Box<dyn Iterator<Item = Result<P, ModelCas...
method to_primitives (line 105) | fn to_primitives(&self) -> Box<dyn Iterator<Item = Result<P, ModelCast...
method into_primitives_unchecked (line 111) | fn into_primitives_unchecked(self) -> Box<dyn Iterator<Item = P>> {
type FromPrimitives (line 124) | pub trait FromPrimitives<P: Debug>: Sized {
method from_primitives (line 130) | fn from_primitives<I: Iterator<Item = P>>(iter: I) -> Result<Self, Pri...
method from_primitives_bounded (line 136) | fn from_primitives_bounded<I: Iterator<Item = P>>(iter: I) -> Self;
function ratio_to_float (line 273) | pub(crate) fn ratio_to_float<F: FloatCore>(ratio: &Ratio<BigInt>) -> Opt...
function float_to_ratio_bounded (line 303) | pub(crate) fn float_to_ratio_bounded<F: FloatCore>(f: F) -> Ratio<BigInt> {
type R (line 318) | type R = Ratio<BigInt>;
function test_model_f32 (line 321) | fn test_model_f32() {
function test_model_f64 (line 340) | fn test_model_f64() {
function test_model_f32_from_weird_primitives (line 359) | fn test_model_f32_from_weird_primitives() {
function test_model_f64_from_weird_primitives (line 383) | fn test_model_f64_from_weird_primitives() {
function test_model_i32 (line 407) | fn test_model_i32() {
function test_model_i64 (line 426) | fn test_model_i64() {
function test_ratio_to_float (line 446) | fn test_ratio_to_float() {
FILE: rust/xaynet-core/src/mask/object/mod.rs
type InvalidMaskObjectError (line 20) | pub struct InvalidMaskObjectError;
type MaskVect (line 24) | pub struct MaskVect {
method new_unchecked (line 31) | pub fn new_unchecked(config: MaskConfig, data: Vec<BigUint>) -> Self {
method new (line 39) | pub fn new(config: MaskConfig, data: Vec<BigUint>) -> Result<Self, Inv...
method empty (line 49) | pub fn empty(config: MaskConfig, size: usize) -> Self {
method is_valid (line 57) | pub fn is_valid(&self) -> bool {
method from (line 71) | fn from(mask_unit: &MaskUnit) -> Self {
method from (line 77) | fn from(mask_unit: MaskUnit) -> Self {
type MaskUnit (line 65) | pub struct MaskUnit {
method new_unchecked (line 84) | pub fn new_unchecked(config: MaskConfig, data: BigUint) -> Self {
method new (line 92) | pub fn new(config: MaskConfig, data: BigUint) -> Result<Self, InvalidM...
method default (line 102) | pub fn default(config: MaskConfig) -> Self {
method is_valid (line 110) | pub fn is_valid(&self) -> bool {
type MaskObject (line 117) | pub struct MaskObject {
method new_unchecked (line 124) | pub fn new_unchecked(vect: MaskVect, unit: MaskUnit) -> Self {
method new (line 129) | pub fn new(
method empty (line 140) | pub fn empty(config: MaskConfigPair, size: usize) -> Self {
method is_valid (line 148) | pub fn is_valid(&self) -> bool {
FILE: rust/xaynet-core/src/mask/object/serialization/mod.rs
constant MAX_NB (line 27) | const MAX_NB: u32 = u16::MAX as u32;
type MaskObjectBuffer (line 30) | pub struct MaskObjectBuffer<T> {
function new (line 39) | pub fn new(bytes: T) -> Result<Self, DecodeError> {
function new_unchecked (line 48) | pub fn new_unchecked(bytes: T) -> Self {
function check_buffer_length (line 56) | pub fn check_buffer_length(&self) -> Result<(), DecodeError> {
function vect (line 69) | pub fn vect(&self) -> &[u8] {
function unit_offset (line 75) | pub fn unit_offset(&self) -> usize {
function unit (line 84) | pub fn unit(&self) -> &[u8] {
function len (line 93) | pub fn len(&self) -> usize {
function vect_mut (line 105) | pub fn vect_mut(&mut self) -> &mut [u8] {
function unit_mut (line 113) | pub fn unit_mut(&mut self) -> &mut [u8] {
method buffer_length (line 120) | fn buffer_length(&self) -> usize {
method to_bytes (line 124) | fn to_bytes<T: AsMut<[u8]> + AsRef<[u8]>>(&self, buffer: &mut T) {
method from_byte_slice (line 132) | fn from_byte_slice<T: AsRef<[u8]>>(buffer: &T) -> Result<Self, DecodeErr...
method from_byte_stream (line 139) | fn from_byte_stream<I: Iterator<Item = u8> + ExactSizeIterator>(
function mask_config (line 157) | pub fn mask_config() -> (MaskConfig, Vec<u8>) {
function mask_object (line 170) | pub fn mask_object() -> (MaskObject, Vec<u8>) {
function serialize_mask_object (line 180) | fn serialize_mask_object() {
function deserialize_mask_object (line 188) | fn deserialize_mask_object() {
function deserialize_mask_object_from_stream (line 194) | fn deserialize_mask_object_from_stream() {
FILE: rust/xaynet-core/src/mask/object/serialization/unit.rs
constant MASK_CONFIG_FIELD (line 24) | const MASK_CONFIG_FIELD: Range<usize> = range(0, MASK_CONFIG_BUFFER_LEN);
type MaskUnitBuffer (line 27) | pub struct MaskUnitBuffer<T> {
function new (line 36) | pub fn new(bytes: T) -> Result<Self, DecodeError> {
function new_unchecked (line 45) | pub fn new_unchecked(bytes: T) -> Self {
function check_buffer_length (line 53) | pub fn check_buffer_length(&self) -> Result<(), DecodeError> {
function try_len (line 79) | pub fn try_len(&self) -> Result<usize, DecodeError> {
function len (line 90) | pub fn len(&self) -> usize {
function config (line 100) | pub fn config(&self) -> &[u8] {
function data (line 108) | pub fn data(&self) -> &[u8] {
function config_mut (line 118) | pub fn config_mut(&mut self) -> &mut [u8] {
function data_mut (line 126) | pub fn data_mut(&mut self) -> &mut [u8] {
method buffer_length (line 133) | fn buffer_length(&self) -> usize {
method to_bytes (line 137) | fn to_bytes<T: AsMut<[u8]> + AsRef<[u8]>>(&self, buffer: &mut T) {
method from_byte_slice (line 161) | fn from_byte_slice<T: AsRef<[u8]>>(buffer: &T) -> Result<Self, DecodeErr...
method from_byte_stream (line 169) | fn from_byte_stream<I: Iterator<Item = u8> + ExactSizeIterator>(
function mask_unit (line 200) | pub fn mask_unit() -> (MaskUnit, Vec<u8>) {
function serialize_mask_unit (line 213) | fn serialize_mask_unit() {
function deserialize_mask_unit (line 221) | fn deserialize_mask_unit() {
function deserialize_mask_unit_from_stream (line 227) | fn deserialize_mask_unit_from_stream() {
FILE: rust/xaynet-core/src/mask/object/serialization/vect.rs
constant MASK_CONFIG_FIELD (line 24) | const MASK_CONFIG_FIELD: Range<usize> = range(0, MASK_CONFIG_BUFFER_LEN);
constant NUMBERS_FIELD (line 25) | const NUMBERS_FIELD: Range<usize> = range(MASK_CONFIG_FIELD.end, 4);
constant MAX_NB (line 29) | const MAX_NB: u32 = u16::MAX as u32;
type MaskVectBuffer (line 32) | pub struct MaskVectBuffer<T> {
function new (line 42) | pub fn new(bytes: T) -> Result<Self, DecodeError> {
function new_unchecked (line 51) | pub fn new_unchecked(bytes: T) -> Self {
function check_buffer_length (line 59) | pub fn check_buffer_length(&self) -> Result<(), DecodeError> {
function try_len (line 85) | fn try_len(&self) -> Result<usize, DecodeError> {
function len (line 102) | pub fn len(&self) -> usize {
function numbers (line 115) | pub fn numbers(&self) -> usize {
function config (line 132) | pub fn config(&self) -> &[u8] {
function data (line 140) | pub fn data(&self) -> &[u8] {
function set_numbers (line 150) | pub fn set_numbers(&mut self, value: u32) {
function config_mut (line 158) | pub fn config_mut(&mut self) -> &mut [u8] {
function data_mut (line 166) | pub fn data_mut(&mut self) -> &mut [u8] {
method buffer_length (line 173) | fn buffer_length(&self) -> usize {
method to_bytes (line 177) | fn to_bytes<T: AsMut<[u8]>>(&self, buffer: &mut T) {
method from_byte_slice (line 203) | fn from_byte_slice<T: AsRef<[u8]>>(buffer: &T) -> Result<Self, DecodeErr...
method from_byte_stream (line 216) | fn from_byte_stream<I: Iterator<Item = u8> + ExactSizeIterator>(
function mask_vect (line 255) | pub fn mask_vect() -> (MaskVect, Vec<u8>) {
function serialize_mask_vect (line 278) | fn serialize_mask_vect() {
function deserialize_mask_vect (line 286) | fn deserialize_mask_vect() {
function deserialize_mask_vect_from_stream (line 292) | fn deserialize_mask_vect_from_stream() {
FILE: rust/xaynet-core/src/mask/scalar.rs
type Scalar (line 31) | pub struct Scalar(Ratio<BigUint>);
type Error (line 41) | type Error = <BigUint as TryFrom<BigInt>>::Error;
method try_from (line 43) | fn try_from(ratio: Ratio<BigInt>) -> Result<Self, Self::Error> {
method new (line 51) | pub fn new<U>(numer: U, denom: U) -> Self
method from_integer (line 59) | pub fn from_integer<U>(u: U) -> Self
method unit (line 67) | pub fn unit() -> Self {
method to_ratio (line 72) | pub(crate) fn to_ratio(&self) -> Ratio<BigInt> {
method from_float_bounded (line 79) | pub(crate) fn from_float_bounded<F: FloatCore>(f: F) -> Self {
method into_primitive (line 147) | fn into_primitive(self) -> Result<i32, ScalarCastError> {
method to_primitive (line 155) | fn to_primitive(&self) -> Result<i32, ScalarCastError> {
method from_primitive (line 161) | fn from_primitive(prim: i32) -> Result<Self, PrimitiveCastError<i32>> {
method from_primitive_bounded (line 166) | fn from_primitive_bounded(prim: i32) -> Self {
method into_primitive (line 172) | fn into_primitive(self) -> Result<i64, ScalarCastError> {
method to_primitive (line 180) | fn to_primitive(&self) -> Result<i64, ScalarCastError> {
method from_primitive (line 186) | fn from_primitive(prim: i64) -> Result<Self, PrimitiveCastError<i64>> {
method from_primitive_bounded (line 191) | fn from_primitive_bounded(prim: i64) -> Self {
method into_primitive (line 197) | fn into_primitive(self) -> Result<f32, ScalarCastError> {
method to_primitive (line 205) | fn to_primitive(&self) -> Result<f32, ScalarCastError> {
method from_primitive (line 211) | fn from_primitive(prim: f32) -> Result<Self, PrimitiveCastError<f32>> {
method from_primitive_bounded (line 216) | fn from_primitive_bounded(prim: f32) -> Self {
method into_primitive (line 222) | fn into_primitive(self) -> Result<f64, ScalarCastError> {
method to_primitive (line 230) | fn to_primitive(&self) -> Result<f64, ScalarCastError> {
method from_primitive (line 236) | fn from_primitive(prim: f64) -> Result<Self, PrimitiveCastError<f64>> {
method from_primitive_bounded (line 241) | fn from_primitive_bounded(prim: f64) -> Self {
function from (line 34) | fn from(scalar: Scalar) -> Self {
type ScalarCastError (line 95) | pub struct ScalarCastError {
type IntoPrimitive (line 105) | pub trait IntoPrimitive<P>: Sized {
method into_primitive (line 110) | fn into_primitive(self) -> Result<P, ScalarCastError>;
method to_primitive (line 116) | fn to_primitive(&self) -> Result<P, ScalarCastError>;
method into_primitive_unchecked (line 122) | fn into_primitive_unchecked(self) -> P {
type FromPrimitive (line 133) | pub trait FromPrimitive<P: Debug>: Sized {
method from_primitive (line 138) | fn from_primitive(prim: P) -> Result<Self, PrimitiveCastError<P>>;
method from_primitive_bounded (line 143) | fn from_primitive_bounded(prim: P) -> Self;
function test_ratio_conversion (line 251) | fn test_ratio_conversion() {
function test_ratio_conversion_ok (line 259) | fn test_ratio_conversion_ok() {
function test_ratio_conversion_err (line 268) | fn test_ratio_conversion_err() {
function test_scalar_f32 (line 276) | fn test_scalar_f32() {
function test_scalar_f32_from_weird_prims (line 296) | fn test_scalar_f32_from_weird_prims() {
function test_scalar_f64 (line 315) | fn test_scalar_f64() {
function test_scalar_f64_from_weird_prims (line 335) | fn test_scalar_f64_from_weird_prims() {
function test_scalar_i32 (line 353) | fn test_scalar_i32() {
function test_scalar_i64 (line 372) | fn test_scalar_i64() {
FILE: rust/xaynet-core/src/mask/seed.rs
type MaskSeed (line 30) | pub struct MaskSeed(box_::Seed);
method as_array (line 50) | pub fn as_array(&self) -> [u8; Self::LENGTH] {
method encrypt (line 55) | pub fn encrypt(&self, pk: &SumParticipantEphemeralPublicKey) -> Encryp...
method derive_mask (line 61) | pub fn derive_mask(&self, len: usize, config: MaskConfigPair) -> MaskO...
constant LENGTH (line 33) | const LENGTH: usize = box_::SEEDBYTES;
method from_slice (line 35) | fn from_slice(bytes: &[u8]) -> Option<Self> {
method zeroed (line 39) | fn zeroed() -> Self {
method as_slice (line 43) | fn as_slice(&self) -> &[u8] {
type EncryptedMaskSeed (line 83) | pub struct EncryptedMaskSeed(Vec<u8>);
method from (line 86) | fn from(value: Vec<u8>) -> Self {
method decrypt (line 124) | pub fn decrypt(
constant LENGTH (line 92) | const LENGTH: usize = SEALBYTES + MaskSeed::LENGTH;
method from_slice (line 94) | fn from_slice(bytes: &[u8]) -> Option<Self> {
method zeroed (line 102) | fn zeroed() -> Self {
method as_slice (line 106) | fn as_slice(&self) -> &[u8] {
type InvalidMaskSeed (line 112) | pub enum InvalidMaskSeed {
function test_constants (line 147) | fn test_constants() {
function test_derive_mask (line 161) | fn test_derive_mask() {
function test_encryption (line 179) | fn test_encryption() {
FILE: rust/xaynet-core/src/message/message.rs
constant SUM_COUNT_MIN (line 18) | pub const SUM_COUNT_MIN: u64 = 1;
constant UPDATE_COUNT_MIN (line 21) | pub const UPDATE_COUNT_MIN: u64 = 3;
constant SIGNATURE (line 31) | pub const SIGNATURE: Range<usize> = range(0, Signature::LENGTH);
constant PARTICIPANT_PK (line 34) | pub const PARTICIPANT_PK: Range<usize> = range(SIGNATURE.end, PublicSign...
constant COORDINATOR_PK (line 37) | pub const COORDINATOR_PK: Range<usize> = range(PARTICIPANT_PK.end, Publi...
constant LENGTH (line 39) | pub const LENGTH: Range<usize> = range(COORDINATOR_PK.end, 4);
constant TAG (line 41) | pub const TAG: usize = LENGTH.end;
constant FLAGS (line 43) | pub const FLAGS: usize = TAG + 1;
constant RESERVED (line 45) | pub const RESERVED: Range<usize> = range(FLAGS + 1, 2);
constant HEADER_LENGTH (line 49) | pub const HEADER_LENGTH: usize = ranges::RESERVED.end;
type MessageBuffer (line 218) | pub struct MessageBuffer<T> {
function inner (line 223) | pub fn inner(&self) -> &T {
function as_ref (line 227) | pub fn as_ref(&self) -> MessageBuffer<&T> {
function new (line 235) | pub fn new(bytes: T) -> Result<Self, DecodeError> {
function new_unchecked (line 247) | pub fn new_unchecked(bytes: T) -> Self {
function check_buffer_length (line 253) | pub fn check_buffer_length(&self) -> Result<(), DecodeError> {
function tag (line 278) | pub fn tag(&self) -> u8 {
function flags (line 286) | pub fn flags(&self) -> Flags {
function length (line 294) | pub fn length(&self) -> u32 {
function signature (line 306) | pub fn signature(&self) -> &'a [u8] {
function participant_pk (line 314) | pub fn participant_pk(&self) -> &'a [u8] {
function coordinator_pk (line 322) | pub fn coordinator_pk(&self) -> &'a [u8] {
function payload (line 330) | pub fn payload(&self) -> &'a [u8] {
function check_signature (line 336) | pub fn check_signature(&self) -> Result<(), DecodeError> {
function signed_data (line 355) | pub fn signed_data(&self) -> &'a [u8] {
function set_tag (line 366) | pub fn set_tag(&mut self, value: u8) {
function set_flags (line 374) | pub fn set_flags(&mut self, value: Flags) {
function set_length (line 382) | pub fn set_length(&mut self, value: u32) {
function signature_mut (line 391) | pub fn signature_mut(&mut self) -> &mut [u8] {
function participant_pk_mut (line 399) | pub fn participant_pk_mut(&mut self) -> &mut [u8] {
function coordinator_pk_mut (line 407) | pub fn coordinator_pk_mut(&mut self) -> &mut [u8] {
function payload_mut (line 415) | pub fn payload_mut(&mut self) -> &mut [u8] {
function signed_data_mut (line 425) | pub fn signed_data_mut(&mut self) -> &mut [u8] {
type Tag (line 441) | pub enum Tag {
type Error (line 451) | type Error = DecodeError;
method try_from (line 453) | fn try_from(value: u8) -> Result<Self, Self::Error> {
function from (line 464) | fn from(tag: Tag) -> Self {
type Message (line 475) | pub struct Message {
method new_sum (line 499) | pub fn new_sum(
method new_sum2 (line 516) | pub fn new_sum2(
method new_update (line 533) | pub fn new_update(
method new_multipart (line 550) | pub fn new_multipart(
method from_byte_slice (line 569) | pub fn from_byte_slice<T: AsRef<[u8]>>(buffer: &T) -> Result<Self, Dec...
method to_bytes (line 610) | pub fn to_bytes<T: AsMut<[u8]> + AsRef<[u8]> + ?Sized>(
method buffer_length (line 647) | pub fn buffer_length(&self) -> usize {
function sum_message (line 662) | fn sum_message() -> (Message, Vec<u8>) {
function buffer_read (line 667) | fn buffer_read() {
function buffer_write (line 685) | fn buffer_write() {
FILE: rust/xaynet-core/src/message/mod.rs
type DecodeError (line 56) | pub type DecodeError = anyhow::Error;
FILE: rust/xaynet-core/src/message/payload/chunk.rs
constant ID (line 15) | pub const ID: Range<usize> = range(0, 2);
constant MESSAGE_ID (line 17) | pub const MESSAGE_ID: Range<usize> = range(ID.end, 2);
constant FLAGS (line 19) | pub const FLAGS: usize = MESSAGE_ID.end;
constant RESERVED (line 21) | pub const RESERVED: Range<usize> = range(FLAGS + 1, 3);
constant HEADER_LENGTH (line 25) | const HEADER_LENGTH: usize = ranges::RESERVED.end;
type Chunk (line 29) | pub struct Chunk {
type ChunkBuffer (line 66) | pub struct ChunkBuffer<T> {
function new (line 76) | pub fn new(bytes: T) -> Result<Self, DecodeError> {
function new_unchecked (line 88) | pub fn new_unchecked(bytes: T) -> Self {
function check_buffer_length (line 94) | pub fn check_buffer_length(&self) -> Result<(), DecodeError> {
function flags (line 110) | pub fn flags(&self) -> Flags {
function id (line 118) | pub fn id(&self) -> u16 {
function message_id (line 128) | pub fn message_id(&self) -> u16 {
function payload (line 140) | pub fn payload(&self) -> &'a [u8] {
function set_flags (line 150) | pub fn set_flags(&mut self, value: Flags) {
function set_id (line 158) | pub fn set_id(&mut self, value: u16) {
function set_message_id (line 167) | pub fn set_message_id(&mut self, value: u16) {
function payload_mut (line 176) | pub fn payload_mut(&mut self) -> &mut [u8] {
method from_byte_slice (line 182) | fn from_byte_slice<T: AsRef<[u8]>>(buffer: &T) -> Result<Self, DecodeErr...
method from_byte_stream (line 192) | fn from_byte_stream<I: Iterator<Item = u8> + ExactSizeIterator>(
method buffer_length (line 212) | fn buffer_length(&self) -> usize {
method to_bytes (line 216) | fn to_bytes<T: AsMut<[u8]> + AsRef<[u8]>>(&self, buffer: &mut T) {
function flags (line 234) | fn flags() -> (u8, Flags) {
function id (line 239) | fn id() -> (Vec<u8>, u16) {
function message_id (line 244) | fn message_id() -> (Vec<u8>, u16) {
function data (line 249) | fn data() -> Vec<u8> {
function chunk (line 253) | fn chunk() -> (Vec<u8>, Chunk) {
function buffer_read (line 271) | fn buffer_read() {
function stream_parse (line 281) | fn stream_parse() {
function buffer_write (line 288) | fn buffer_write() {
FILE: rust/xaynet-core/src/message/payload/mod.rs
type Payload (line 23) | pub enum Payload {
method is_sum (line 35) | pub fn is_sum(&self) -> bool {
method is_update (line 39) | pub fn is_update(&self) -> bool {
method is_sum2 (line 43) | pub fn is_sum2(&self) -> bool {
method is_chunk (line 47) | pub fn is_chunk(&self) -> bool {
method buffer_length (line 53) | fn buffer_length(&self) -> usize {
method to_bytes (line 62) | fn to_bytes<T: AsMut<[u8]> + AsRef<[u8]>>(&self, buffer: &mut T) {
FILE: rust/xaynet-core/src/message/payload/sum.rs
constant SUM_SIGNATURE_RANGE (line 22) | const SUM_SIGNATURE_RANGE: Range<usize> = range(0, ParticipantTaskSignat...
constant EPHM_PK_RANGE (line 23) | const EPHM_PK_RANGE: Range<usize> = range(
type SumBuffer (line 61) | pub struct SumBuffer<T> {
function new (line 71) | pub fn new(bytes: T) -> Result<Self, DecodeError> {
function new_unchecked (line 82) | pub fn new_unchecked(bytes: T) -> Self {
function check_buffer_length (line 87) | pub fn check_buffer_length(&self) -> Result<(), DecodeError> {
function ephm_pk_mut (line 106) | pub fn ephm_pk_mut(&mut self) -> &mut [u8] {
function sum_signature_mut (line 114) | pub fn sum_signature_mut(&mut self) -> &mut [u8] {
function ephm_pk (line 124) | pub fn ephm_pk(&self) -> &'a [u8] {
function sum_signature (line 132) | pub fn sum_signature(&self) -> &'a [u8] {
type Sum (line 176) | pub struct Sum {
method buffer_length (line 186) | fn buffer_length(&self) -> usize {
method to_bytes (line 190) | fn to_bytes<T: AsMut<[u8]> + AsRef<[u8]>>(&self, buffer: &mut T) {
method from_byte_slice (line 198) | fn from_byte_slice<T: AsRef<[u8]>>(buffer: &T) -> Result<Self, DecodeErr...
method from_byte_stream (line 213) | fn from_byte_stream<I: Iterator<Item = u8> + ExactSizeIterator>(
function buffer_read (line 234) | fn buffer_read() {
function buffer_read_invalid (line 242) | fn buffer_read_invalid() {
function buffer_write (line 247) | fn buffer_write() {
function encode (line 259) | fn encode() {
function decode (line 269) | fn decode() {
function stream_parse (line 276) | fn stream_parse() {
FILE: rust/xaynet-core/src/message/payload/sum2.rs
constant SUM_SIGNATURE_RANGE (line 22) | const SUM_SIGNATURE_RANGE: Range<usize> = range(0, ParticipantTaskSignat...
type Sum2Buffer (line 28) | pub struct Sum2Buffer<T> {
function new (line 38) | pub fn new(bytes: T) -> Result<Self, DecodeError> {
function new_unchecked (line 49) | pub fn new_unchecked(bytes: T) -> Self {
function check_buffer_length (line 54) | pub fn check_buffer_length(&self) -> Result<(), DecodeError> {
function model_mask_offset (line 72) | fn model_mask_offset(&self) -> usize {
function sum_signature_mut (line 82) | pub fn sum_signature_mut(&mut self) -> &mut [u8] {
function model_mask_mut (line 90) | pub fn model_mask_mut(&mut self) -> &mut [u8] {
function sum_signature (line 101) | pub fn sum_signature(&self) -> &'a [u8] {
function model_mask (line 109) | pub fn model_mask(&self) -> &'a [u8] {
type Sum2 (line 119) | pub struct Sum2 {
method buffer_length (line 130) | fn buffer_length(&self) -> usize {
method to_bytes (line 134) | fn to_bytes<T: AsMut<[u8]> + AsRef<[u8]>>(&self, buffer: &mut T) {
method from_byte_slice (line 142) | fn from_byte_slice<T: AsRef<[u8]>>(buffer: &T) -> Result<Self, DecodeErr...
method from_byte_stream (line 152) | fn from_byte_stream<I: Iterator<Item = u8> + ExactSizeIterator>(
function buffer_read (line 170) | fn buffer_read() {
function buffer_write (line 182) | fn buffer_write() {
function encode (line 197) | fn encode() {
function decode (line 207) | fn decode() {
function stream_parse (line 214) | fn stream_parse() {
FILE: rust/xaynet-core/src/message/payload/update.rs
constant SUM_SIGNATURE_RANGE (line 23) | const SUM_SIGNATURE_RANGE: Range<usize> = range(0, ParticipantTaskSignat...
constant UPDATE_SIGNATURE_RANGE (line 24) | const UPDATE_SIGNATURE_RANGE: Range<usize> =
type UpdateBuffer (line 31) | pub struct UpdateBuffer<T> {
function new (line 41) | pub fn new(bytes: T) -> Result<Self, DecodeError> {
function new_unchecked (line 52) | pub fn new_unchecked(bytes: T) -> Self {
function check_buffer_length (line 57) | pub fn check_buffer_length(&self) -> Result<(), DecodeError> {
function masked_model_offset (line 81) | fn masked_model_offset(&self) -> usize {
function local_seed_dict_offset (line 89) | fn local_seed_dict_offset(&self) -> usize {
function sum_signature (line 101) | pub fn sum_signature(&self) -> &'a [u8] {
function update_signature (line 109) | pub fn update_signature(&self) -> &'a [u8] {
function masked_model (line 117) | pub fn masked_model(&self) -> &'a [u8] {
function local_seed_dict (line 126) | pub fn local_seed_dict(&self) -> &'a [u8] {
function sum_signature_mut (line 137) | pub fn sum_signature_mut(&mut self) -> &mut [u8] {
function update_signature_mut (line 145) | pub fn update_signature_mut(&mut self) -> &mut [u8] {
function masked_model_mut (line 153) | pub fn masked_model_mut(&mut self) -> &mut [u8] {
function local_seed_dict_mut (line 162) | pub fn local_seed_dict_mut(&mut self) -> &mut [u8] {
type Update (line 172) | pub struct Update {
method buffer_length (line 192) | fn buffer_length(&self) -> usize {
method to_bytes (line 198) | fn to_bytes<T: AsMut<[u8]> + AsRef<[u8]>>(&self, buffer: &mut T) {
method from_byte_slice (line 210) | fn from_byte_slice<T: AsRef<[u8]>>(buffer: &T) -> Result<Self, DecodeErr...
method from_byte_stream (line 224) | fn from_byte_stream<I: Iterator<Item = u8> + ExactSizeIterator>(
function buffer_read (line 245) | fn buffer_read() {
function decode_invalid_seed_dict (line 262) | fn decode_invalid_seed_dict() {
function decode (line 281) | fn decode() {
function stream_parse (line 288) | fn stream_parse() {
function encode (line 295) | fn encode() {
FILE: rust/xaynet-core/src/message/traits.rs
type ToBytes (line 27) | pub trait ToBytes {
method buffer_length (line 29) | fn buffer_length(&self) -> usize;
method to_bytes (line 38) | fn to_bytes<T: AsMut<[u8]> + AsRef<[u8]>>(&self, buffer: &mut T);
method buffer_length (line 77) | fn buffer_length(&self) -> usize {
method to_bytes (line 81) | fn to_bytes<U: AsMut<[u8]> + AsRef<[u8]>>(&self, buffer: &mut U) {
method buffer_length (line 280) | fn buffer_length(&self) -> usize {
method to_bytes (line 284) | fn to_bytes<T: AsMut<[u8]> + AsRef<[u8]>>(&self, buffer: &mut T) {
type FromBytes (line 44) | pub trait FromBytes: Sized {
method from_byte_slice (line 49) | fn from_byte_slice<T: AsRef<[u8]>>(buffer: &T) -> Result<Self, DecodeE...
method from_byte_stream (line 51) | fn from_byte_stream<I: Iterator<Item = u8> + ExactSizeIterator>(
method from_byte_slice (line 60) | fn from_byte_slice<U: AsRef<[u8]>>(buffer: &U) -> Result<Self, DecodeE...
method from_byte_stream (line 65) | fn from_byte_stream<I: Iterator<Item = u8> + ExactSizeIterator>(
method from_byte_slice (line 296) | fn from_byte_slice<T: AsRef<[u8]>>(buffer: &T) -> Result<Self, DecodeE...
method from_byte_stream (line 317) | fn from_byte_stream<I: Iterator<Item = u8> + ExactSizeIterator>(
method from_byte_slice (line 356) | fn from_byte_slice<T: AsRef<[u8]>>(buffer: &T) -> Result<Self, DecodeE...
method from_byte_stream (line 365) | fn from_byte_stream<I: Iterator<Item = u8> + ExactSizeIterator>(
method from_byte_slice (line 378) | fn from_byte_slice<T: AsRef<[u8]>>(buffer: &T) -> Result<Self, DecodeE...
method from_byte_stream (line 387) | fn from_byte_stream<I: Iterator<Item = u8> + ExactSizeIterator>(
type LengthValueBuffer (line 126) | pub struct LengthValueBuffer<T> {
constant LENGTH_FIELD (line 131) | const LENGTH_FIELD: Range<usize> = 0..4;
function new (line 164) | pub fn new(bytes: T) -> Result<Self, DecodeError> {
function new_unchecked (line 173) | pub fn new_unchecked(bytes: T) -> Self {
function check_buffer_length (line 178) | pub fn check_buffer_length(&self) -> Result<(), DecodeError> {
function length (line 211) | pub fn length(&self) -> u32 {
function value_length (line 217) | pub fn value_length(&self) -> usize {
function value_range (line 222) | fn value_range(&self) -> Range<usize> {
function set_length (line 234) | pub fn set_length(&mut self, value: u32) {
function value_mut (line 244) | pub fn value_mut(&mut self) -> &mut [u8] {
function bytes_mut (line 253) | pub fn bytes_mut(&mut self) -> &mut [u8] {
function value (line 263) | pub fn value(&self) -> &'a [u8] {
function bytes (line 271) | pub fn bytes(self) -> &'a [u8] {
constant ENTRY_LENGTH (line 277) | const ENTRY_LENGTH: usize = SumParticipantPublicKey::LENGTH + EncryptedM...
function decode_length_value_buffer (line 406) | fn decode_length_value_buffer() {
function decode_empty_value (line 419) | fn decode_empty_value() {
function decode_length_value_buffer_buffer_exhausted (line 427) | fn decode_length_value_buffer_buffer_exhausted() {
function decode_length_value_buffer_invalid_length (line 436) | fn decode_length_value_buffer_invalid_length() {
function encode_length_value_buffer (line 446) | fn encode_length_value_buffer() {
function encode_length_value_buffer_emty (line 461) | fn encode_length_value_buffer_emty() {
function parse_u16 (line 475) | fn parse_u16() {
FILE: rust/xaynet-core/src/message/utils/chunkable_iterator.rs
type ChunkableIterator (line 17) | pub trait ChunkableIterator: Iterator + Sized {
method chunks (line 81) | fn chunks(self, size: usize) -> IntoChunks<Self>;
method chunks (line 88) | fn chunks(self, size: usize) -> IntoChunks<Self> {
type Inner (line 93) | struct Inner<I>
function fmt (line 113) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
function remaining (line 128) | fn remaining(&self) -> usize {
function new (line 138) | fn new(mut iter: I, chunk_size: usize) -> Self {
function get (line 153) | fn get(&mut self, index: usize) -> Option<I::Item> {
type IntoChunks (line 173) | pub struct IntoChunks<I>
function fmt (line 186) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
function new (line 198) | pub fn new(iter: I, chunk_size: usize) -> Self {
function next_chunk_range (line 205) | fn next_chunk_range(&self) -> Range<usize> {
function exhausted (line 212) | fn exhausted(&self) -> bool {
function get (line 236) | pub fn get(&self, index: usize) -> Option<I::Item> {
function remaining (line 246) | fn remaining(&self) -> usize {
type Item (line 255) | type Item = Chunk<'a, I>;
type IntoIter (line 256) | type IntoIter = Chunks<'a, I>;
method into_iter (line 258) | fn into_iter(self) -> Self::IntoIter {
type Chunks (line 264) | pub struct Chunks<'a, I>
function fmt (line 276) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
type Item (line 287) | type Item = Chunk<'a, I>;
method next (line 289) | fn next(&mut self) -> Option<Chunk<'a, I>> {
type Chunk (line 304) | pub struct Chunk<'a, I>
function fmt (line 317) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
type Item (line 329) | type Item = I::Item;
method next (line 331) | fn next(&mut self) -> Option<Self::Item> {
method len (line 352) | fn len(&self) -> usize {
function full_chunks_1 (line 362) | fn full_chunks_1() {
function full_chunks_2 (line 388) | fn full_chunks_2() {
function partial_chunk (line 421) | fn partial_chunk() {
function chunks_consumed_out_of_order (line 443) | fn chunks_consumed_out_of_order() {
function weird (line 465) | fn weird() {
FILE: rust/xaynet-core/src/message/utils/mod.rs
function range (line 13) | pub(crate) const fn range(start: usize, length: usize) -> Range<usize> {
FILE: rust/xaynet-core/src/testutils/messages.rs
constant HEADER_LENGTH (line 24) | pub const HEADER_LENGTH: usize = 136;
function signature (line 26) | pub fn signature() -> (Signature, Vec<u8>) {
function participant_pk (line 32) | pub fn participant_pk() -> (PublicSigningKey, Vec<u8>) {
function coordinator_pk (line 38) | pub fn coordinator_pk() -> (PublicEncryptKey, Vec<u8>) {
function message (line 44) | pub fn message<F, P>(f: F) -> (Message, Vec<u8>)
function sum_task_signature (line 84) | pub fn sum_task_signature() -> (Signature, Vec<u8>) {
function ephm_pk (line 91) | pub fn ephm_pk() -> (PublicEncryptKey, Vec<u8>) {
function payload (line 98) | pub fn payload() -> (Sum, Vec<u8>) {
function update_task_signature (line 118) | pub fn update_task_signature() -> (Signature, Vec<u8>) {
function local_seed_dict (line 126) | pub fn local_seed_dict() -> (LocalSeedDict, Vec<u8>) {
function payload (line 152) | pub fn payload() -> (Update, Vec<u8>) {
function payload (line 176) | pub fn payload() -> (Sum2, Vec<u8>) {
function mask_config (line 205) | pub fn mask_config() -> (MaskConfig, Vec<u8>) {
function mask_vect (line 219) | pub fn mask_vect() -> (MaskVect, Vec<u8>) {
function mask_unit (line 242) | pub fn mask_unit() -> (MaskUnit, Vec<u8>) {
function mask_object (line 255) | pub fn mask_object() -> (MaskObject, Vec<u8>) {
function check_object_lengths (line 272) | fn check_object_lengths() {
FILE: rust/xaynet-core/src/testutils/multipart.rs
function local_seed_dict (line 23) | pub fn local_seed_dict(len: usize) -> LocalSeedDict {
function mask_object (line 46) | pub fn mask_object(len: usize) -> MaskObject {
function mask_config (line 84) | pub fn mask_config() -> MaskConfig {
function task_signatures (line 95) | pub fn task_signatures() -> (Signature, Signature) {
function update (line 111) | pub fn update(dict_len: usize, mask_obj_len: usize) -> Update {
function message (line 144) | pub fn message(dict_len: usize, mask_obj_len: usize) -> Message {
FILE: rust/xaynet-mobile/build.rs
function cargo_rerun_if_changed (line 11) | fn cargo_rerun_if_changed(entry: impl AsRef<Path>) {
function main (line 22) | fn main() {
FILE: rust/xaynet-mobile/src/ffi/config.rs
function xaynet_ffi_local_model_config_destroy (line 33) | pub unsafe extern "C" fn xaynet_ffi_local_model_config_destroy(
type LocalModelConfig (line 47) | pub struct LocalModelConfig {
method from (line 55) | fn from(lmc: xaynet_sdk::LocalModelConfig) -> Self {
type ModelDataType (line 65) | pub enum ModelDataType {
method from (line 77) | fn from(dt: DataType) -> Self {
FILE: rust/xaynet-mobile/src/ffi/mod.rs
function xaynet_ffi_byte_buffer_destroy (line 40) | pub unsafe extern "C" fn xaynet_ffi_byte_buffer_destroy(
function xaynet_ffi_crypto_init (line 70) | pub unsafe extern "C" fn xaynet_ffi_crypto_init() -> c_int {
constant OK (line 79) | pub const OK: c_int = 0;
constant ERR_NULLPTR (line 81) | pub const ERR_NULLPTR: c_int = 1;
constant ERR_INVALID_URL (line 83) | pub const ERR_INVALID_URL: c_int = 2;
constant ERR_SETTINGS_URL (line 85) | pub const ERR_SETTINGS_URL: c_int = 3;
constant ERR_SETTINGS_KEYS (line 87) | pub const ERR_SETTINGS_KEYS: c_int = 4;
constant ERR_SETTINGS_SCALAR (line 89) | pub const ERR_SETTINGS_SCALAR: c_int = 5;
constant ERR_SETMODEL_MODEL (line 91) | pub const ERR_SETMODEL_MODEL: c_int = 6;
constant ERR_SETMODEL_DATATYPE (line 93) | pub const ERR_SETMODEL_DATATYPE: c_int = 7;
constant ERR_CRYPTO_INIT (line 95) | pub const ERR_CRYPTO_INIT: c_int = 8;
constant ERR_CRYPTO_SECRET_KEY (line 97) | pub const ERR_CRYPTO_SECRET_KEY: c_int = 9;
constant ERR_CRYPTO_PUBLIC_KEY (line 99) | pub const ERR_CRYPTO_PUBLIC_KEY: c_int = 10;
constant GLOBALMODEL_NONE (line 101) | pub const GLOBALMODEL_NONE: c_int = 11;
constant ERR_GLOBALMODEL_IO (line 103) | pub const ERR_GLOBALMODEL_IO: c_int = 12;
constant ERR_GLOBALMODEL_DATATYPE (line 105) | pub const ERR_GLOBALMODEL_DATATYPE: c_int = 13;
constant ERR_GLOBALMODEL_LEN (line 107) | pub const ERR_GLOBALMODEL_LEN: c_int = 14;
constant ERR_GLOBALMODEL_CONVERT (line 109) | pub const ERR_GLOBALMODEL_CONVERT: c_int = 15;
FILE: rust/xaynet-mobile/src/ffi/participant.rs
function xaynet_ffi_participant_destroy (line 53) | pub unsafe extern "C" fn xaynet_ffi_participant_destroy(participant: *mu...
constant PARTICIPANT_TASK_NONE (line 62) | pub const PARTICIPANT_TASK_NONE: c_int = 1;
constant PARTICIPANT_TASK_SUM (line 64) | pub const PARTICIPANT_TASK_SUM: c_int = 1 << 1;
constant PARTICIPANT_TASK_UPDATE (line 66) | pub const PARTICIPANT_TASK_UPDATE: c_int = 1 << 2;
constant PARTICIPANT_SHOULD_SET_MODEL (line 68) | pub const PARTICIPANT_SHOULD_SET_MODEL: c_int = 1 << 3;
constant PARTICIPANT_MADE_PROGRESS (line 70) | pub const PARTICIPANT_MADE_PROGRESS: c_int = 1 << 4;
constant PARTICIPANT_NEW_GLOBALMODEL (line 72) | pub const PARTICIPANT_NEW_GLOBALMODEL: c_int = 1 << 5;
function xaynet_ffi_participant_new (line 97) | pub unsafe extern "C" fn xaynet_ffi_participant_new(settings: *const Set...
function xaynet_ffi_participant_tick (line 154) | pub unsafe extern "C" fn xaynet_ffi_participant_tick(participant: *mut P...
function xaynet_ffi_participant_save (line 215) | pub unsafe extern "C" fn xaynet_ffi_participant_save(
function xaynet_ffi_participant_restore (line 265) | pub unsafe extern "C" fn xaynet_ffi_participant_restore(
function xaynet_ffi_participant_set_model (line 316) | pub unsafe extern "C" fn xaynet_ffi_participant_set_model(
function xaynet_ffi_participant_global_model (line 402) | pub unsafe extern "C" fn xaynet_ffi_participant_global_model(
function xaynet_ffi_participant_local_model_config (line 470) | pub unsafe extern "C" fn xaynet_ffi_participant_local_model_config(
FILE: rust/xaynet-mobile/src/ffi/settings.rs
function xaynet_ffi_settings_destroy (line 46) | pub unsafe extern "C" fn xaynet_ffi_settings_destroy(settings: *mut Sett...
function xaynet_ffi_settings_new (line 62) | pub unsafe extern "C" fn xaynet_ffi_settings_new() -> *mut Settings {
function xaynet_ffi_settings_set_scalar (line 84) | pub unsafe extern "C" fn xaynet_ffi_settings_set_scalar(
function xaynet_ffi_settings_set_url (line 116) | pub unsafe extern "C" fn xaynet_ffi_settings_set_url(
type KeyPair (line 135) | pub struct KeyPair {
function xaynet_ffi_generate_key_pair (line 155) | pub unsafe extern "C" fn xaynet_ffi_generate_key_pair() -> *const KeyPair {
function xaynet_ffi_forget_key_pair (line 188) | pub unsafe extern "C" fn xaynet_ffi_forget_key_pair(key_pair: *const Key...
function xaynet_ffi_settings_set_keys (line 221) | pub unsafe extern "C" fn xaynet_ffi_settings_set_keys(
function xaynet_ffi_check_settings (line 274) | pub unsafe extern "C" fn xaynet_ffi_check_settings(settings: *const Sett...
FILE: rust/xaynet-mobile/src/participant.rs
type Event (line 30) | pub enum Event {
type Notifier (line 46) | pub struct Notifier(mpsc::Sender<Event>);
method notify (line 48) | fn notify(&mut self, event: Event) {
type Events (line 56) | pub struct Events(mpsc::Receiver<Event>);
method new (line 60) | fn new() -> (Self, Notifier) {
method next (line 66) | fn next(&mut self) -> Option<Event> {
method new_round (line 87) | fn new_round(&mut self) {
method sum (line 90) | fn sum(&mut self) {
method update (line 93) | fn update(&mut self) {
method load_model (line 96) | fn load_model(&mut self) {
method idle (line 99) | fn idle(&mut self) {
type Store (line 108) | struct Store(Arc<Mutex<Option<Model>>>);
method new (line 112) | fn new() -> Self {
type Model (line 119) | type Model = Model;
type Error (line 120) | type Error = std::convert::Infallible;
method load_model (line 122) | async fn load_model(&mut self) -> Result<Option<Self::Model>, Self::Erro...
type Task (line 129) | pub enum Task {
type Participant (line 142) | pub struct Participant {
method new (line 185) | pub fn new(settings: Settings) -> Result<Self, InitError> {
method restore (line 198) | pub fn restore(state: &[u8], url: &str) -> Result<Self, InitError> {
method init (line 207) | fn init(
method runtime (line 228) | fn runtime() -> Result<Runtime, InitError> {
method save (line 236) | pub fn save(self) -> Vec<u8> {
method tick (line 252) | pub fn tick(&mut self) {
method process_events (line 271) | fn process_events(&mut self) {
method made_progress (line 297) | pub fn made_progress(&self) -> bool {
method should_set_model (line 304) | pub fn should_set_model(&self) -> bool {
method new_global_model (line 310) | pub fn new_global_model(&self) -> bool {
method task (line 315) | pub fn task(&self) -> Task {
method set_model (line 321) | pub fn set_model(&mut self, model: Model) {
method global_model (line 336) | pub fn global_model(&mut self) -> Result<Option<Model>, GetGlobalModel...
method local_model_config (line 353) | pub fn local_model_config(&self) -> LocalModelConfig {
type InitError (line 168) | pub enum InitError {
type GetGlobalModelError (line 181) | pub struct GetGlobalModelError(xaynet_sdk::client::ClientError);
FILE: rust/xaynet-mobile/src/reqwest_client.rs
type ClientError (line 9) | pub enum ClientError {
method trust_anchor (line 21) | fn trust_anchor<E: std::error::Error>(path: String, e: E) -> Self {
method client_cert (line 25) | fn client_cert<E: std::error::Error>(path: String, e: E) -> Self {
method other (line 29) | fn other<E: std::error::Error>(e: E) -> Self {
function new_client (line 43) | pub fn new_client(
FILE: rust/xaynet-mobile/src/settings.rs
type Settings (line 15) | pub struct Settings {
method new (line 34) | pub fn new() -> Self {
method set_keys (line 44) | pub fn set_keys(&mut self, keys: SigningKeyPair) {
method set_scalar (line 49) | pub fn set_scalar(&mut self, scalar: f64) {
method set_url (line 54) | pub fn set_url(&mut self, url: String) {
method set_max_message_size (line 59) | pub fn set_max_message_size(&mut self, size: MaxMessageSize) {
method check (line 64) | pub fn check(&self) -> Result<(), SettingsError> {
type Error (line 89) | type Error = SettingsError;
method try_into (line 91) | fn try_into(self) -> Result<(String, PetSettings), Self::Error> {
method default (line 27) | fn default() -> Self {
type SettingsError (line 79) | pub enum SettingsError {
FILE: rust/xaynet-mobile/tests/ffi_test.c
function with_keys (line 49) | void with_keys(Settings *settings) {
function with_url (line 56) | void with_url(Settings *settings) {
function main (line 187) | int main(int argc, char **argv) {
FILE: rust/xaynet-mobile/xaynet_ffi.h
type ModelDataType (line 123) | enum ModelDataType {
type ModelDataType (line 141) | typedef uint8_t ModelDataType;
type KeyPair (line 146) | typedef struct KeyPair KeyPair;
type Participant (line 154) | typedef struct Participant Participant;
type Settings (line 159) | typedef struct Settings Settings;
type ByteBuffer (line 242) | typedef struct ByteBuffer {
type LocalModelConfig (line 299) | typedef struct LocalModelConfig {
type ByteBuffer (line 336) | struct ByteBuffer
type Participant (line 378) | struct Participant
type Participant (line 404) | struct Participant
type Settings (line 404) | struct Settings
type Participant (line 452) | struct Participant
type ByteBuffer (line 490) | struct ByteBuffer
type Participant (line 490) | struct Participant
type Participant (line 532) | struct Participant
type ByteBuffer (line 532) | struct ByteBuffer
type Participant (line 565) | struct Participant
type Participant (line 608) | struct Participant
type LocalModelConfig (line 627) | struct LocalModelConfig
type Participant (line 627) | struct Participant
type Settings (line 652) | struct Settings
type Settings (line 663) | struct Settings
type Settings (line 684) | struct Settings
type Settings (line 706) | struct Settings
type KeyPair (line 723) | struct KeyPair
type KeyPair (line 745) | struct KeyPair
type Settings (line 768) | struct Settings
type KeyPair (line 768) | struct KeyPair
type Settings (line 794) | struct Settings
type LocalModelConfig (line 820) | struct LocalModelConfig
FILE: rust/xaynet-sdk/src/client.rs
type ClientError (line 16) | pub enum ClientError {
method http_error (line 41) | fn http_error<E: std::error::Error>(e: E) -> Self {
method from (line 47) | fn from(e: bincode::Error) -> Self {
method from (line 53) | fn from(e: std::num::ParseIntError) -> Self {
type XaynetHttpClient (line 60) | pub trait XaynetHttpClient {
method get (line 70) | async fn get(&mut self, url: &str) -> Result<Option<Self::GetResponse>...
method post (line 73) | async fn post(&mut self, url: &str, body: Vec<u8>) -> Result<(), Clien...
type Error (line 184) | type Error = reqwest::Error;
type GetResponse (line 185) | type GetResponse = bytes::Bytes;
method get (line 187) | async fn get(&mut self, url: &str) -> Result<Option<Self::GetResponse>...
method post (line 203) | async fn post(&mut self, url: &str, body: Vec<u8>) -> Result<(), Clien...
type Client (line 78) | pub struct Client<C> {
type InvalidBaseUrl (line 89) | pub struct InvalidBaseUrl(String);
function new (line 106) | pub fn new(http_client: C, base_url: &str) -> Result<Self, InvalidBaseUr...
function url (line 118) | fn url(&self, segment: &str) -> Url {
function get (line 124) | async fn get<T>(&mut self, url: &Url) -> Result<Option<T>, ClientError>
function post (line 134) | async fn post(&mut self, url: &Url, data: Vec<u8>) -> Result<(), ClientE...
type Error (line 144) | type Error = ClientError;
method get_round_params (line 146) | async fn get_round_params(&mut self) -> Result<RoundParameters, Self::Er...
method get_sums (line 154) | async fn get_sums(&mut self) -> Result<Option<SumDict>, Self::Error> {
method get_seeds (line 159) | async fn get_seeds(
method get_model (line 169) | async fn get_model(&mut self) -> Result<Option<Model>, Self::Error> {
method send_message (line 174) | async fn send_message(&mut self, msg: Vec<u8>) -> Result<(), Self::Error> {
FILE: rust/xaynet-sdk/src/message_encoder/chunker.rs
constant DEFAULT_CHUNK_SIZE (line 6) | pub const DEFAULT_CHUNK_SIZE: usize = 4096;
type Chunker (line 9) | pub struct Chunker<'a, T: AsRef<[u8]>> {
function new (line 21) | pub fn new(data: &'a T, max_chunk_size: usize) -> Self {
function nb_chunks (line 34) | pub fn nb_chunks(&self) -> usize {
function get_chunk (line 44) | pub fn get_chunk(&self, id: usize) -> &'a [u8] {
function ceiling_div (line 60) | fn ceiling_div(n: usize, d: usize) -> usize {
function test_0 (line 70) | fn test_0() {
function test_1 (line 79) | fn test_1() {
function test_2 (line 93) | fn test_2() {
function test_3 (line 107) | fn test_3() {
function test_4 (line 120) | fn test_4() {
function test_5 (line 130) | fn test_5() {
FILE: rust/xaynet-sdk/src/message_encoder/encoder.rs
type MultipartEncoder (line 14) | pub struct MultipartEncoder {
constant CHUNK_OVERHEAD (line 33) | pub const CHUNK_OVERHEAD: usize = 8;
constant MIN_PAYLOAD_SIZE (line 34) | pub const MIN_PAYLOAD_SIZE: usize = CHUNK_OVERHEAD + 1;
type Item (line 37) | type Item = Vec<u8>;
method next (line 39) | fn next(&mut self) -> Option<Self::Item> {
type MessageEncoder (line 74) | pub enum MessageEncoder {
method new (line 115) | pub fn new(
method new_simple (line 143) | fn new_simple(
method new_multipart (line 161) | fn new_multipart(
method get_tag_from_payload (line 181) | fn get_tag_from_payload(payload: &Payload) -> Tag {
type Item (line 83) | type Item = Vec<u8>;
method next (line 85) | fn next(&mut self) -> Option<Self::Item> {
type InvalidEncodingInput (line 94) | pub enum InvalidEncodingInput {
function participant_keys (line 201) | fn participant_keys() -> SigningKeyPair {
function coordinator_keys (line 206) | fn coordinator_keys() -> EncryptKeyPair {
function message (line 211) | fn message(dict_len: usize, mask_obj_len: usize) -> Message {
function small_message (line 223) | fn small_message() -> Message {
function no_chunk (line 235) | fn no_chunk() {
function two_chunks (line 254) | fn two_chunks() {
function extract_chunk (line 296) | fn extract_chunk(message: Message) -> Chunk {
function extract_update (line 304) | fn extract_update(message: Message) -> Update {
function serialize_message (line 313) | fn serialize_message(message: &Message, sk: &SecretSigningKey) -> Vec<u8> {
FILE: rust/xaynet-sdk/src/settings/max_message_size.rs
constant MINIMUM_PAYLOAD_SIZE (line 7) | pub const MINIMUM_PAYLOAD_SIZE: usize = 1;
constant ENCRYPTION_HEADER_LENGTH (line 9) | pub const ENCRYPTION_HEADER_LENGTH: usize = xaynet_core::crypto::SEALBYTES;
constant MIN_MESSAGE_SIZE (line 11) | pub const MIN_MESSAGE_SIZE: usize =
type InvalidMaxMessageSize (line 17) | pub struct InvalidMaxMessageSize;
type MaxMessageSize (line 24) | pub struct MaxMessageSize(#[serde(deserialize_with = "deserialize")] Opt...
method unlimited (line 37) | pub fn unlimited() -> Self {
method capped (line 47) | pub fn capped(size: usize) -> Result<Self, InvalidMaxMessageSize> {
method max_payload_size (line 57) | pub fn max_payload_size(&self) -> Option<usize> {
method default (line 27) | fn default() -> Self {
function deserialize (line 63) | fn deserialize<'de, D>(deserializer: D) -> Result<Option<usize>, D::Error>
function max_message_size_deserialization_capped (line 90) | fn max_message_size_deserialization_capped() {
function max_message_size_deserialization_unlimited (line 98) | fn max_message_size_deserialization_unlimited() {
function max_message_size_deserialization_err (line 106) | fn max_message_size_deserialization_err() {
function max_message_size_serialization_capped (line 121) | fn max_message_size_serialization_capped() {
function max_message_size_serialization_unlimited (line 129) | fn max_message_size_serialization_unlimited() {
FILE: rust/xaynet-sdk/src/settings/mod.rs
type PetSettings (line 9) | pub struct PetSettings {
method new (line 16) | pub fn new(keys: SigningKeyPair) -> Self {
FILE: rust/xaynet-sdk/src/state_machine/io.rs
function boxed_io (line 16) | pub(crate) fn boxed_io<X, M, N>(
type DynModel (line 30) | type DynModel = Box<(dyn std::convert::AsRef<xaynet_core::mask::Model> +...
type IO (line 47) | pub(crate) trait IO: Send + 'static {
method load_model (line 51) | async fn load_model(&mut self) -> Result<Option<Self::Model>, Box<dyn ...
method get_round_params (line 54) | async fn get_round_params(&mut self) -> Result<RoundParameters, Box<dy...
method get_sums (line 56) | async fn get_sums(&mut self) -> Result<Option<SumDict>, Box<dyn Error>>;
method get_seeds (line 58) | async fn get_seeds(
method get_model (line 63) | async fn get_model(&mut self) -> Result<Option<Model>, Box<dyn Error>>;
method send_message (line 65) | async fn send_message(&mut self, msg: Vec<u8>) -> Result<(), Box<dyn E...
method notify_new_round (line 68) | fn notify_new_round(&mut self);
method notify_sum (line 71) | fn notify_sum(&mut self);
method notify_update (line 74) | fn notify_update(&mut self);
method notify_idle (line 77) | fn notify_idle(&mut self);
method notify_load_model (line 80) | fn notify_load_model(&mut self);
type Model (line 109) | type Model = Box<dyn AsRef<Model> + Send>;
method load_model (line 111) | async fn load_model(&mut self) -> Result<Option<Self::Model>, Box<dyn ...
method get_round_params (line 119) | async fn get_round_params(&mut self) -> Result<RoundParameters, Box<dy...
method get_sums (line 126) | async fn get_sums(&mut self) -> Result<Option<SumDict>, Box<dyn Error>> {
method get_seeds (line 133) | async fn get_seeds(
method get_model (line 143) | async fn get_model(&mut self) -> Result<Option<Model>, Box<dyn Error>> {
method send_message (line 150) | async fn send_message(&mut self, msg: Vec<u8>) -> Result<(), Box<dyn E...
method notify_new_round (line 157) | fn notify_new_round(&mut self) {
method notify_sum (line 161) | fn notify_sum(&mut self) {
method notify_update (line 165) | fn notify_update(&mut self) {
method notify_idle (line 169) | fn notify_idle(&mut self) {
method notify_load_model (line 173) | fn notify_load_model(&mut self) {
type Model (line 180) | type Model = Box<dyn AsRef<Model> + Send>;
method load_model (line 182) | async fn load_model(&mut self) -> Result<Option<Self::Model>, Box<dyn ...
method get_round_params (line 186) | async fn get_round_params(&mut self) -> Result<RoundParameters, Box<dy...
method get_sums (line 190) | async fn get_sums(&mut self) -> Result<Option<SumDict>, Box<dyn Error>> {
method get_seeds (line 194) | async fn get_seeds(
method get_model (line 201) | async fn get_model(&mut self) -> Result<Option<Model>, Box<dyn Error>> {
method send_message (line 205) | async fn send_message(&mut self, msg: Vec<u8>) -> Result<(), Box<dyn E...
method notify_new_round (line 209) | fn notify_new_round(&mut self) {
method notify_sum (line 213) | fn notify_sum(&mut self) {
method notify_update (line 217) | fn notify_update(&mut self) {
method notify_idle (line 221) | fn notify_idle(&mut self) {
method notify_load_model (line 225) | fn notify_load_model(&mut self) {
type StateMachineIO (line 85) | struct StateMachineIO<X, M, N> {
function new (line 93) | pub fn new(xaynet_client: X, model_store: M, notifier: N) -> Self {
FILE: rust/xaynet-sdk/src/state_machine/phase.rs
type State (line 22) | pub struct State<P> {
function new (line 31) | pub fn new(shared: Box<SharedState>, private: Box<P>) -> Self {
type PhaseIo (line 37) | pub(crate) type PhaseIo = Box<dyn IO<Model = Box<dyn AsRef<Model> + Send...
type Phase (line 40) | pub struct Phase<P> {
function fmt (line 52) | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
type SharedState (line 62) | pub struct SharedState {
method new (line 97) | pub fn new(settings: PetSettings) -> Self {
function dummy_round_parameters (line 79) | fn dummy_round_parameters() -> RoundParameters {
type Step (line 110) | pub trait Step {
method step (line 115) | async fn step(mut self) -> TransitionOutcome;
type Progress (line 135) | pub enum Progress<P> {
function step (line 160) | pub async fn step(mut self) -> TransitionOutcome {
function check_round_freshness (line 183) | async fn check_round_freshness(&mut self) -> RoundFreshness {
type IntoPhase (line 209) | pub(crate) trait IntoPhase<P> {
method into_phase (line 211) | fn into_phase(self, io: PhaseIo) -> Phase<P>;
function new (line 217) | pub(crate) fn new(state: State<P>, io: PhaseIo) -> Self {
function message_encoder (line 225) | pub fn message_encoder(&self, payload: Payload) -> MessageEncoder {
function local_model_config (line 243) | pub fn local_model_config(&self) -> LocalModelConfig {
function with_io_mock (line 251) | pub(crate) fn with_io_mock<F>(&mut self, f: F)
function check_io_mock (line 261) | pub(crate) fn check_io_mock(&mut self) {
type LocalModelConfig (line 271) | pub struct LocalModelConfig {
type SendMessageError (line 283) | pub struct SendMessageError;
type RoundFreshness (line 286) | pub enum RoundFreshness {
type SerializableState (line 304) | pub enum SerializableState {
method from (line 319) | fn from(phase: Phase<P>) -> Self {
FILE: rust/xaynet-sdk/src/state_machine/phases/awaiting.rs
type Awaiting (line 8) | pub struct Awaiting;
method step (line 12) | async fn step(mut self) -> TransitionOutcome {
function into_phase (line 19) | fn into_phase(self, mut io: PhaseIo) -> Phase<Awaiting> {
FILE: rust/xaynet-sdk/src/state_machine/phases/new_round.rs
type NewRound (line 19) | pub struct NewRound;
function into_phase (line 22) | fn into_phase(self, mut io: PhaseIo) -> Phase<NewRound> {
method step (line 30) | async fn step(mut self) -> TransitionOutcome {
function from (line 56) | fn from(new_round: Phase<NewRound>) -> Self {
function sign (line 62) | fn sign(&self, data: &[u8]) -> Signature {
function into_sum (line 68) | fn into_sum(self, sum_signature: Signature) -> Phase<Sum> {
function into_update (line 74) | fn into_update(self, sum_signature: Signature, update_signature: Signatu...
FILE: rust/xaynet-sdk/src/state_machine/phases/sum.rs
type Sum (line 18) | pub struct Sum {
method new (line 29) | pub fn new(sum_signature: Signature) -> Self {
function into_phase (line 38) | fn into_phase(self, mut io: PhaseIo) -> Phase<Sum> {
method step (line 46) | async fn step(mut self) -> TransitionOutcome {
function from (line 54) | fn from(sum: Phase<Sum>) -> Self {
function from (line 67) | fn from(sum: Phase<Sum>) -> Self {
function compose_message (line 74) | pub fn compose_message(&self) -> MessageEncoder {
FILE: rust/xaynet-sdk/src/state_machine/phases/sum2.rs
type Sum2 (line 30) | pub struct Sum2 {
method new (line 49) | pub fn new(ephm_keys: EncryptKeyPair, sum_signature: Signature) -> Self {
method has_fetched_seed_dict (line 60) | fn has_fetched_seed_dict(&self) -> bool {
method has_decrypted_seeds (line 65) | fn has_decrypted_seeds(&self) -> bool {
method has_aggregated_masks (line 70) | fn has_aggregated_masks(&self) -> bool {
function into_phase (line 76) | fn into_phase(self, io: PhaseIo) -> Phase<Sum2> {
method step (line 83) | async fn step(mut self) -> TransitionOutcome {
function from (line 94) | fn from(mut sum2: Phase<Sum2>) -> Self {
function from (line 106) | fn from(sum2: Phase<Sum2>) -> Self {
function fetch_seed_dict (line 113) | pub(crate) async fn fetch_seed_dict(mut self) -> Progress<Sum2> {
function decrypt_seeds (line 135) | pub(crate) fn decrypt_seeds(mut self) -> Progress<Sum2> {
function aggregate_masks (line 170) | pub(crate) fn aggregate_masks(mut self) -> Progress<Sum2> {
function compose_message (line 196) | pub fn compose_message(&mut self) -> MessageEncoder {
FILE: rust/xaynet-sdk/src/state_machine/phases/update.rs
type LocalModel (line 34) | pub enum LocalModel {
method fmt (line 40) | fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
method as_ref (line 51) | fn as_ref(&self) -> &Model {
method serialize (line 60) | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
method deserialize (line 72) | fn deserialize<D>(deserializer: D) -> Result<LocalModel, D::Error>
type Update (line 83) | pub struct Update {
method new (line 94) | pub fn new(sum_signature: Signature, update_signature: Signature) -> S...
method has_fetched_sum_dict (line 105) | fn has_fetched_sum_dict(&self) -> bool {
method has_loaded_model (line 109) | fn has_loaded_model(&self) -> bool {
method has_masked_model (line 113) | fn has_masked_model(&self) -> bool {
method has_built_seed_dict (line 117) | fn has_built_seed_dict(&self) -> bool {
function into_phase (line 123) | fn into_phase(self, mut io: PhaseIo) -> Phase<Update> {
method step (line 134) | async fn step(mut self) -> TransitionOutcome {
function from (line 145) | fn from(mut update: Phase<Update>) -> Self {
function from (line 157) | fn from(update: Phase<Update>) -> Self {
function fetch_sum_dict (line 163) | pub(crate) async fn fetch_sum_dict(mut self) -> Progress<Update> {
function load_model (line 185) | pub(crate) async fn load_model(mut self) -> Progress<Update> {
function mask_model (line 209) | pub(crate) fn mask_model(mut self) -> Progress<Update> {
function build_seed_dict (line 225) | pub(crate) fn build_seed_dict(mut self) -> Progress<Update> {
function compose_message (line 247) | pub fn compose_message(&mut self) -> MessageEncoder {
FILE: rust/xaynet-sdk/src/state_machine/state_machine.rs
type TransitionOutcome (line 24) | pub enum TransitionOutcome {
type StateMachine (line 34) | pub enum StateMachine {
method transition (line 55) | pub async fn transition(self) -> TransitionOutcome {
method save (line 70) | pub fn save(self) -> SerializableState {
method local_model_config (line 84) | pub fn local_model_config(&self) -> LocalModelConfig {
method new (line 108) | pub fn new<X, M, N>(
method restore (line 125) | pub fn restore<X, M, N>(
FILE: rust/xaynet-sdk/src/state_machine/tests/phases/new_round.rs
function test_selected_for_sum (line 14) | async fn test_selected_for_sum() {
function test_selected_for_update (line 22) | async fn test_selected_for_update() {
function test_not_selected (line 31) | async fn test_not_selected() {
function make_phase (line 47) | fn make_phase(task: SelectFor, io: MockIO) -> Phase<NewRound> {
FILE: rust/xaynet-sdk/src/state_machine/tests/phases/sum.rs
function make_phase (line 18) | fn make_phase(io: MockIO) -> Phase<Sum> {
function make_sum (line 33) | fn make_sum(shared: &SharedState) -> Box<Sum> {
function test_phase (line 45) | async fn test_phase() {
type DummyErr (line 53) | struct DummyErr;
FILE: rust/xaynet-sdk/src/state_machine/tests/phases/sum2.rs
function make_phase (line 24) | fn make_phase() -> Phase<Sum2> {
function make_sum2 (line 36) | fn make_sum2(shared: &SharedState) -> Box<Sum2> {
function make_seed_dict (line 50) | fn make_seed_dict(mask_config: MaskConfigPair, ephm_pk: PublicEncryptKey...
function make_model (line 61) | fn make_model() -> Model {
function make_masked_model (line 65) | fn make_masked_model(mask_config: MaskConfigPair) -> (MaskSeed, MaskObje...
function step1_fetch_seed_dict (line 72) | async fn step1_fetch_seed_dict(mut phase: Phase<Sum2>) -> Phase<Sum2> {
function step2_decrypt_seeds (line 103) | async fn step2_decrypt_seeds(phase: Phase<Sum2>) -> Phase<Sum2> {
function step3_aggregate_masks (line 111) | async fn step3_aggregate_masks(phase: Phase<Sum2>) -> Phase<Sum2> {
function step4_into_sending_phase (line 119) | async fn step4_into_sending_phase(phase: Phase<Sum2>) -> Phase<SendingSu...
function test_phase (line 125) | async fn test_phase() {
FILE: rust/xaynet-sdk/src/state_machine/tests/phases/update.rs
function make_phase (line 25) | fn make_phase() -> Phase<Update> {
function make_update (line 39) | fn make_update(shared: &SharedState) -> Box<Update> {
function make_model (line 54) | fn make_model() -> Model {
function make_sum_dict (line 59) | fn make_sum_dict() -> SumDict {
function step1_fetch_sum_dict (line 71) | async fn step1_fetch_sum_dict(mut phase: Phase<Update>) -> Phase<Update> {
function step2_load_model (line 100) | async fn step2_load_model(mut phase: Phase<Update>) -> Phase<Update> {
function step3_mask_model (line 129) | async fn step3_mask_model(phase: Phase<Update>) -> Phase<Update> {
function step4_build_seed_dict (line 136) | async fn step4_build_seed_dict(phase: Phase<Update>) -> Phase<Update> {
function step5_into_sending_phase (line 143) | async fn step5_into_sending_phase(phase: Phase<Update>) -> Phase<Sending...
function test_update_phase (line 149) | async fn test_update_phase() {
function test_save_and_restore (line 159) | async fn test_save_and_restore() {
FILE: rust/xaynet-sdk/src/state_machine/tests/utils.rs
type SelectFor (line 125) | pub enum SelectFor {
function mask_config (line 134) | pub fn mask_config() -> MaskConfig {
function round_params (line 143) | pub fn round_params(task: SelectFor) -> RoundParameters {
function shared_state (line 154) | pub fn shared_state(task: SelectFor) -> Box<SharedState> {
type EncryptKeyGenerator (line 163) | pub struct EncryptKeyGenerator(EncryptKeySeed);
method new (line 166) | pub fn new() -> Self {
method incr_seed (line 170) | fn incr_seed(&mut self) {
method next (line 181) | pub fn next(&mut self) -> EncryptKeyPair {
type SigningKeyGenerator (line 188) | pub struct SigningKeyGenerator(SigningKeySeed);
method new (line 191) | pub fn new() -> Self {
method incr_seed (line 195) | fn incr_seed(&mut self) {
method next (line 206) | pub fn next(&mut self) -> SigningKeyPair {
FILE: rust/xaynet-sdk/src/traits.rs
type Notify (line 15) | pub trait Notify {
method new_round (line 18) | fn new_round(&mut self) {}
method sum (line 21) | fn sum(&mut self) {}
method update (line 24) | fn update(&mut self) {}
method idle (line 27) | fn idle(&mut self) {}
method load_model (line 30) | fn load_model(&mut self) {}
type ModelStore (line 38) | pub trait ModelStore {
method load_model (line 44) | async fn load_model(&mut self) -> Result<Option<Self::Model>, Self::Er...
type XaynetClient (line 52) | pub trait XaynetClient {
method get_round_params (line 56) | async fn get_round_params(&mut self) -> Result<RoundParameters, Self::...
method get_sums (line 59) | async fn get_sums(&mut self) -> Result<Option<SumDict>, Self::Error>;
method get_seeds (line 63) | async fn get_seeds(
method get_model (line 69) | async fn get_model(&mut self) -> Result<Option<Model>, Self::Error>;
method send_message (line 72) | async fn send_message(&mut self, msg: Vec<u8>) -> Result<(), Self::Err...
FILE: rust/xaynet-sdk/src/utils/concurrent_futures.rs
type ConcurrentFutures (line 18) | pub struct ConcurrentFutures<T>
function new (line 36) | pub fn new(max_in_flight: usize) -> Self {
function push (line 44) | pub fn push(&mut self, task: T) {
type Item (line 61) | type Item = Result<T::Output, JoinError>;
method poll_next (line 62) | fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self...
function test (line 87) | async fn test() {
FILE: rust/xaynet-server/src/bin/main.rs
type Opt (line 23) | struct Opt {
function main (line 30) | async fn main() {
function init_tracing (line 98) | fn init_tracing(settings: LoggingSettings) {
function init_metrics (line 106) | fn init_metrics(settings: InfluxSettings) {
function init_store (line 113) | async fn init_store(
FILE: rust/xaynet-server/src/metrics/mod.rs
type GlobalRecorder (line 12) | pub struct GlobalRecorder;
method global (line 19) | pub fn global() -> Option<&'static Recorder> {
method install (line 26) | pub fn install(recorder: Recorder) -> Result<(), Recorder> {
FILE: rust/xaynet-server/src/metrics/recorders/influxdb/dispatcher.rs
type Request (line 10) | pub(in crate::metrics) enum Request {
method from (line 16) | fn from(req: Request) -> Self {
type Dispatcher (line 25) | pub(in crate::metrics) struct Dispatcher {
method new (line 30) | pub fn new(url: impl Into<String>, database: impl Into<String>) -> Self {
type Response (line 37) | type Response = ();
type Error (line 38) | type Error = anyhow::Error;
type Future (line 39) | type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
method poll_ready (line 41) | fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Sel...
method call (line 45) | fn call(&mut self, req: Request) -> Self::Future {
function influx_settings (line 74) | fn influx_settings() -> InfluxSettings {
function integration_dispatch_metric (line 83) | async fn integration_dispatch_metric() {
function integration_dispatch_event (line 95) | async fn integration_dispatch_event() {
function integration_wrong_url (line 107) | async fn integration_wrong_url() {
FILE: rust/xaynet-server/src/metrics/recorders/influxdb/models.rs
type Measurement (line 7) | pub enum Measurement {
function from (line 19) | fn from(measurement: Measurement) -> &'static str {
method from (line 34) | fn from(measurement: Measurement) -> Self {
type Tags (line 40) | pub struct Tags(Vec<(String, Type)>);
method new (line 44) | pub fn new() -> Self {
method add (line 49) | pub fn add(&mut self, tag: impl Into<String>, value: impl Into<Type>) {
method default (line 55) | fn default() -> Self {
type Item (line 61) | type Item = <Vec<(String, Type)> as IntoIterator>::Item;
type IntoIter (line 62) | type IntoIter = <Vec<(String, Type)> as IntoIterator>::IntoIter;
method into_iter (line 64) | fn into_iter(self) -> Self::IntoIter {
type Metric (line 70) | pub(in crate::metrics) struct Metric {
method new (line 78) | pub(in crate::metrics) fn new(measurement: Measurement, value: impl In...
method with_tags (line 87) | pub(in crate::metrics) fn with_tags<T, I>(mut self, tags: T) -> Self
method from (line 102) | fn from(metric: Metric) -> Self {
type Event (line 117) | pub(in crate::metrics) struct Event {
method new (line 126) | pub(in crate::metrics) fn new(title: impl Into<String>) -> Self {
method with_description (line 136) | pub(in crate::metrics) fn with_description<D, S>(mut self, description...
method with_tags (line 145) | pub(in crate::metrics) fn with_tags<T, A, B>(mut self, tags: T) -> Self
method from (line 161) | fn from(event: Event) -> Self {
function test_basic_metric (line 197) | fn test_basic_metric() {
function test_metric_with_tag (line 207) | fn test_metric_with_tag() {
function test_metric_with_tags (line 217) | fn test_metric_with_tags() {
function test_basic_event (line 231) | fn test_basic_event() {
function test_event_with_description (line 241) | fn test_event_with_description() {
function test_event_with_description_and_tag (line 251) | fn test_event_with_description_and_tag() {
function test_event_with_description_and_tags (line 263) | fn test_event_with_description_and_tags() {
function test_event_with_tag (line 275) | fn test_event_with_tag() {
FILE: rust/xaynet-server/src/metrics/recorders/influxdb/recorder.rs
type Recorder (line 12) | pub struct Recorder {
method new (line 19) | pub fn new(settings: InfluxSettings) -> Self {
method metric (line 27) | pub fn metric<V, T, I>(&self, measurement: Measurement, value: V, tags...
method event (line 38) | pub fn event<H, D, S, T, A, B>(&self, title: H, description: D, tags: T)
method call (line 53) | fn call(&self, req: Request) {
FILE: rust/xaynet-server/src/metrics/recorders/influxdb/service.rs
type InfluxDbService (line 4) | pub(in crate::metrics) struct InfluxDbService(
method new (line 9) | pub fn new(dispatcher: Dispatcher) -> Self {
FILE: rust/xaynet-server/src/rest.rs
type SeedDictQuery (line 26) | struct SeedDictQuery {
function serve (line 40) | pub async fn serve<F>(
function handle_message (line 93) | async fn handle_message(
function handle_sums (line 104) | async fn handle_sums<F: Fetcher>(mut fetcher: F) -> Result<impl warp::Re...
function handle_seeds (line 129) | async fn handle_seeds<F: Fetcher>(
function handle_model (line 157) | async fn handle_model<F: Fetcher>(mut fetcher: F) -> Result<impl warp::R...
function handle_params (line 178) | async fn handle_params<F: Fetcher>(mut fetcher: F) -> Result<impl warp::...
function with_message_handler (line 195) | fn with_message_handler(
function with_fetcher (line 202) | fn with_fetcher<F: Fetcher + Sync + Send + 'static + Clone>(
function part_pk (line 209) | async fn part_pk(query: SeedDictQuery) -> Result<ParticipantPublicKey, w...
type InvalidPublicKey (line 223) | struct InvalidPublicKey;
function handle_reject (line 228) | async fn handle_reject(err: warp::Rejection) -> Result<impl warp::Reply,...
type RestError (line 243) | pub enum RestError {
method from (line 249) | fn from(infallible: Infallible) -> RestError {
function configure_tls (line 259) | fn configure_tls<F>(
function run_http (line 287) | async fn run_http<F>(filter: F, api_settings: ApiSettings) -> Result<(),...
function run_https (line 301) | async fn run_https<F>(filter: F, api_settings: ApiSettings) -> Result<()...
FILE: rust/xaynet-server/src/services/fetchers/mod.rs
type Fetcher (line 27) | pub trait Fetcher {
method round_params (line 29) | async fn round_params(&mut self) -> Result<RoundParamsResponse, FetchE...
method model (line 32) | async fn model(&mut self) -> Result<ModelResponse, FetchError>;
method seed_dict (line 36) | async fn seed_dict(&mut self) -> Result<SeedDictResponse, FetchError>;
method sum_dict (line 41) | async fn sum_dict(&mut self) -> Result<SumDictResponse, FetchError>;
method round_params (line 79) | async fn round_params(&mut self) -> Result<RoundParamsResponse, FetchE...
method model (line 93) | async fn model(&mut self) -> Result<ModelResponse, FetchError> {
method seed_dict (line 104) | async fn seed_dict(&mut self) -> Result<SeedDictResponse, FetchError> {
method sum_dict (line 115) | async fn sum_dict(&mut self) -> Result<SumDictResponse, FetchError> {
type FetchError (line 45) | pub type FetchError = anyhow::Error;
function into_fetch_error (line 47) | fn into_fetch_error<E: Into<Box<dyn std::error::Error + 'static + Sync +...
type FetcherService (line 127) | pub(in crate::services) struct FetcherService<S>(S);
type Response (line 133) | type Response = S::Response;
type Error (line 134) | type Error = S::Error;
type Future (line 135) | type Future = S::Future;
function poll_ready (line 137) | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::...
function call (line 141) | fn call(&mut self, req: R) -> Self::Future {
type FetcherLayer (line 146) | pub(in crate::services) struct FetcherLayer;
type Service (line 149) | type Service = FetcherService<S>;
method layer (line 151) | fn layer(&self, service: S) -> Self::Service {
type Fetchers (line 157) | pub struct Fetchers<RoundParams, SumDict, SeedDict, Model> {
function new (line 165) | pub fn new(
function fetcher (line 181) | pub fn fetcher(event_subscriber: &EventSubscriber) -> impl Fetcher + Syn...
FILE: rust/xaynet-server/src/services/fetchers/model.rs
type ModelRequest (line 16) | pub struct ModelRequest;
type ModelResponse (line 21) | pub type ModelResponse = Option<Arc<Model>>;
type ModelService (line 24) | pub struct ModelService(EventListener<ModelUpdate>);
method new (line 27) | pub fn new(events: &EventSubscriber) -> Self {
type Response (line 33) | type Response = ModelResponse;
type Error (line 34) | type Error = std::convert::Infallible;
type Future (line 35) | type Future = Instrumented<Ready<Result<Self::Response, Self::Error>>>;
method poll_ready (line 37) | fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Sel...
method call (line 41) | fn call(&mut self, _req: ModelRequest) -> Self::Future {
FILE: rust/xaynet-server/src/services/fetchers/round_parameters.rs
type RoundParamsRequest (line 13) | pub struct RoundParamsRequest;
type RoundParamsResponse (line 16) | pub type RoundParamsResponse = RoundParameters;
type RoundParamsService (line 19) | pub struct RoundParamsService(EventListener<RoundParameters>);
method new (line 22) | pub fn new(events: &EventSubscriber) -> Self {
type Response (line 28) | type Response = RoundParameters;
type Error (line 29) | type Error = std::convert::Infallible;
type Future (line 30) | type Future = Instrumented<Ready<Result<Self::Response, Self::Error>>>;
method poll_ready (line 32) | fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Sel...
method call (line 36) | fn call(&mut self, _req: RoundParamsRequest) -> Self::Future {
FILE: rust/xaynet-server/src/services/fetchers/seed_dict.rs
type SeedDictService (line 15) | pub struct SeedDictService(EventListener<DictionaryUpdate<SeedDict>>);
method new (line 18) | pub fn new(events: &EventSubscriber) -> Self {
type Response (line 34) | type Response = SeedDictResponse;
type Error (line 35) | type Error = std::convert::Infallible;
type Future (line 36) | type Future = Instrumented<Ready<Result<Self::Response, Self::Error>>>;
method poll_ready (line 38) | fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Sel...
method call (line 42) | fn call(&mut self, _req: SeedDictRequest) -> Self::Future {
type SeedDictRequest (line 25) | pub struct SeedDictRequest;
type SeedDictResponse (line 31) | pub type SeedDictResponse = Option<Arc<SeedDict>>;
FILE: rust/xaynet-server/src/services/fetchers/sum_dict.rs
type SumDictService (line 15) | pub struct SumDictService(EventListener<DictionaryUpdate<SumDict>>);
method new (line 28) | pub fn new(events: &EventSubscriber) -> Self {
type Response (line 34) | type Response = SumDictResponse;
type Error (line 35) | type Error = std::convert::Infallible;
type Future (line 36) | type Future = Instrumented<Ready<Result<Self::Response, Self::Error>>>;
method poll_ready (line 38) | fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Sel...
method call (line 42) | fn call(&mut self, _req: SumDictRequest) -> Self::Future {
type SumDictRequest (line 19) | pub struct SumDictRequest;
type SumDictResponse (line 25) | pub type SumDictResponse = Option<Arc<SumDict>>;
FILE: rust/xaynet-server/src/services/messages/decryptor.rs
type RawDecryptor (line 24) | struct RawDecryptor {
type Response (line 38) | type Response = Vec<u8>;
type Error (line 39) | type Error = ServiceError;
type Future (line 41) | type Future =
method poll_ready (line 44) | fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Sel...
method call (line 48) | fn call(&mut self, data: T) -> Self::Future {
type Decryptor (line 73) | pub struct Decryptor(ConcurrencyLimit<RawDecryptor>);
method new (line 76) | pub fn new(state_machine_events: &EventSubscriber, thread_pool: Arc<Th...
type Response (line 91) | type Response = Vec<u8>;
type Error (line 92) | type Error = ServiceError;
type Future (line 93) | type Future = ResponseFuture<BoxedServiceFuture<Self::Response, Self::...
method poll_ready (line 95) | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self...
method call (line 99) | fn call(&mut self, data: T) -> Self::Future {
function spawn_svc (line 117) | fn spawn_svc() -> (EventPublisher, EventSubscriber, Spawn<Decryptor>) {
function test_decrypt_fail (line 125) | async fn test_decrypt_fail() {
function test_decrypt_ok (line 138) | async fn test_decrypt_ok() {
FILE: rust/xaynet-server/src/services/messages/error.rs
type ServiceError (line 9) | pub enum ServiceError {
method from (line 33) | fn from(e: Box<dyn std::error::Error>) -> Self {
method from (line 42) | fn from(e: Box<dyn std::error::Error + Sync + Send>) -> Self {
FILE: rust/xaynet-server/src/services/messages/message_parser.rs
type RawMessage (line 22) | struct RawMessage<T> {
method clone (line 28) | fn clone(&self) -> Self {
function from (line 36) | fn from(buffer: MessageBuffer<T>) -> Self {
type BufferWrapper (line 46) | struct BufferWrapper<S>(S);
type Response (line 54) | type Response = Message;
type Error (line 55) | type Error = ServiceError;
type Future (line 56) | type Future = BoxedServiceFuture<Self::Response, Self::Error>;
function poll_ready (line 58) | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::...
function call (line 62) | fn call(&mut self, req: T) -> Self::Future {
type BufferWrapperLayer (line 77) | struct BufferWrapperLayer;
type Service (line 80) | type Service = BufferWrapper<S>;
method layer (line 82) | fn layer(&self, service: S) -> BufferWrapper<S> {
type PhaseFilter (line 89) | struct PhaseFilter<S> {
type Response (line 102) | type Response = Message;
type Error (line 103) | type Error = ServiceError;
type Future (line 104) | type Future = BoxedServiceFuture<Self::Response, Self::Error>;
function poll_ready (line 106) | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::...
function call (line 110) | fn call(&mut self, req: RawMessage<T>) -> Self::Future {
type PhaseFilterLayer (line 128) | struct PhaseFilterLayer {
type Service (line 133) | type Service = PhaseFilter<S>;
method layer (line 135) | fn layer(&self, service: S) -> PhaseFilter<S> {
type SignatureVerifier (line 149) | struct SignatureVerifier<S> {
type Response (line 166) | type Response = Message;
type Error (line 167) | type Error = ServiceError;
type Future (line 168) | type Future = BoxedServiceFuture<Self::Response, Self::Error>;
function poll_ready (line 170) | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::...
function call (line 174) | fn call(&mut self, req: RawMessage<T>) -> Self::Future {
type SignatureVerifierLayer (line 206) | struct SignatureVerifierLayer {
type Service (line 211) | type Service = ConcurrencyLimit<SignatureVerifier<S>>;
method layer (line 213) | fn layer(&self, service: S) -> Self::Service {
type CoordinatorPublicKeyValidator (line 231) | struct CoordinatorPublicKeyValidator<S> {
type Response (line 244) | type Response = Message;
type Error (line 245) | type Error = ServiceError;
type Future (line 246) | type Future = BoxedServiceFuture<Self::Response, Self::Error>;
function poll_ready (line 248) | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::...
function call (line 252) | fn call(&mut self, req: RawMessage<T>) -> Self::Future {
type CoordinatorPublicKeyValidatorLayer (line 275) | struct CoordinatorPublicKeyValidatorLayer {
type Service (line 280) | type Service = CoordinatorPublicKeyValidator<S>;
method layer (line 282) | fn layer(&self, service: S) -> CoordinatorPublicKeyValidator<S> {
type Parser (line 291) | struct Parser;
type Response (line 297) | type Response = Message;
type Error (line 298) | type Error = ServiceError;
type Future (line 299) | type Future = future::Ready<Result<Self::Response, Self::Error>>;
method poll_ready (line 301) | fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Sel...
method call (line 305) | fn call(&mut self, req: RawMessage<T>) -> Self::Future {
type InnerService (line 311) | type InnerService = BufferWrapper<
type MessageParser (line 316) | pub struct MessageParser(InnerService);
type Response (line 322) | type Response = Message;
type Error (line 323) | type Error = ServiceError;
type Future (line 324) | type Future = BoxedServiceFuture<Self::Response, Self::Error>;
method poll_ready (line 326) | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self...
method call (line 330) | fn call(&mut self, req: T) -> Self::Future {
method new (line 337) | pub fn new(events: &EventSubscriber, thread_pool: Arc<ThreadPool>) -> ...
function spawn_svc (line 364) | fn spawn_svc() -> (EventPublisher, EventSubscriber, Spawn<MessageParser>) {
function test_valid_request (line 372) | async fn test_valid_request() {
function test_unexpected_message (line 397) | async fn test_unexpected_message() {
FILE: rust/xaynet-server/src/services/messages/mod.rs
type PetMessageHandler (line 108) | pub struct PetMessageHandler {
method new (line 31) | pub fn new(event_subscriber: &EventSubscriber, requests_tx: RequestSen...
method decrypt (line 51) | async fn decrypt(&mut self, enc_data: Vec<u8>) -> Result<Vec<u8>, Serv...
method parse (line 56) | async fn parse(&mut self, data: Vec<u8>) -> Result<Message, ServiceErr...
method handle_multipart (line 62) | async fn handle_multipart(
method validate_task (line 70) | async fn validate_task(&mut self, message: Message) -> Result<Message,...
method process (line 75) | async fn process(&mut self, message: Message) -> Result<(), ServiceErr...
method handle_message (line 80) | pub async fn handle_message(&mut self, enc_data: Vec<u8>) -> Result<()...
type BoxedServiceFuture (line 116) | pub type BoxedServiceFuture<Response, Error> = std::pin::Pin<
FILE: rust/xaynet-server/src/services/messages/multipart/buffer.rs
type MultipartMessageBuffer (line 8) | pub struct MultipartMessageBuffer {
method from (line 20) | fn from(map: BTreeMap<u16, Vec<u8>>) -> Self {
type Item (line 36) | type Item = u8;
method next (line 38) | fn next(&mut self) -> Option<Self::Item> {
method size_hint (line 58) | fn size_hint(&self) -> (usize, Option<usize>) {
function test (line 72) | fn test() {
FILE: rust/xaynet-server/src/services/messages/multipart/mod.rs
type Inner (line 12) | type Inner = Buffer<service::MultipartHandler, Message>;
type MultipartHandler (line 15) | pub struct MultipartHandler(Inner);
type Response (line 18) | type Response = Option<Message>;
type Error (line 19) | type Error = ServiceError;
type Future (line 21) | type Future = futures::future::MapErr<
method poll_ready (line 26) | fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self...
method call (line 30) | fn call(&mut self, req: Message) -> Self::Future {
method new (line 36) | pub fn new() -> Self {
FILE: rust/xaynet-server/src/services/messages/multipart/service.rs
type MessageBuilder (line 26) | pub struct MessageBuilder {
method new (line 42) | fn new(tag: Tag, participant_pk: PublicSigningKey, coordinator_pk: Pub...
method has_all_chunks (line 54) | fn has_all_chunks(&self) -> bool {
method add_chunk (line 64) | fn add_chunk(&mut self, chunk: Chunk) {
method into_message (line 75) | fn into_message(self) -> Result<Message, DecodeError> {
type MessageId (line 98) | pub struct MessageId {
type MultipartHandler (line 104) | pub struct MultipartHandler {
method new (line 110) | pub fn new() -> Self {
type Response (line 118) | type Response = Option<Message>;
type Error (line 119) | type Error = ServiceError;
type Future (line 120) | type Future = Ready<Result<Self::Response, Self::Error>>;
method poll_ready (line 122) | fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Sel...
method call (line 126) | fn call(&mut self, message: Message) -> Self::Future {
function ready_ok (line 182) | fn ready_ok<T, E>(t: T) -> Ready<Result<T, E>> {
function ready_err (line 186) | fn ready_err<T, E>(e: E) -> Ready<Result<T, E>> {
function spawn_svc (line 200) | fn spawn_svc() -> Spawn<MultipartHandler> {
function sum (line 204) | fn sum() -> (Vec<u8>, Sum) {
function message_builder (line 221) | fn message_builder() -> MessageBuilder {
function chunks (line 228) | fn chunks(mut data: Vec<u8>) -> (Chunk, Chunk, Chunk, Chunk, Chunk) {
function test_message_builder_in_order (line 291) | fn test_message_builder_in_order() {
function test_message_builder_out_of_order (line 332) | fn test_message_builder_out_of_order() {
function message_handler (line 373) | async fn message_handler() {
FILE: rust/xaynet-server/src/services/messages/state_machine.rs
type StateMachine (line 16) | pub struct StateMachine {
method new (line 26) | pub fn new(handle: RequestSender) -> Self {
type Response (line 32) | type Response = ();
type Error (line 33) | type Error = ServiceError;
type Future (line 34) | type Future = BoxedServiceFuture<Self::Response, Self::Error>;
method poll_ready (line 36) | fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Sel...
method call (line 40) | fn call(&mut self, req: Message) -> Self::Future {
FILE: rust/xaynet-server/src/services/messages/task_validator.rs
type TaskValidator (line 19) | pub struct TaskValidator {
method new (line 24) | pub fn new(subscriber: &EventSubscriber) -> Self {
type Response (line 32) | type Response = Message;
type Error (line 33) | type Error = ServiceError;
type Future (line 34) | type Future = future::Ready<Result<Self::Response, Self::Error>>;
method poll_ready (line 36) | fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Sel...
method call (line 40) | fn call(&mut self, message: Message) -> Self::Future {
function spawn_svc (line 105) | fn spawn_svc() -> (EventPublisher, EventSubscriber, Spawn<TaskValidator>) {
function test_sum_ok (line 112) | async fn test_sum_ok() {
function test_sum_not_eligible (line 131) | async fn test_sum_not_eligible() {
FILE: rust/xaynet-server/src/services/tests/fetchers.rs
function test_model_svc (line 32) | async fn test_model_svc() {
function test_round_params_svc (line 54) | async fn test_round_params_svc() {
function dummy_seed_dict (line 78) | fn dummy_seed_dict() -> SeedDict {
function dummy_update_dict (line 85) | fn dummy_update_dict() -> UpdateSeedDict {
function test_seed_dict_svc (line 99) | async fn test_seed_dict_svc() {
function dummy_sum_dict (line 120) | fn dummy_sum_dict() -> SumDict {
function test_sum_dict_svc (line 134) | async fn test_sum_dict_svc() {
FILE: rust/xaynet-server/src/services/tests/utils.rs
function mask_config (line 12) | pub fn mask_config() -> MaskConfig {
function new_event_channels (line 24) | pub fn new_event_channels() -> (EventPublisher, EventSubscriber) {
function new_sum_message (line 43) | pub fn new_sum_message(round_params: &RoundParameters) -> (Message, Sign...
function encrypt_message (line 57) | pub fn encrypt_message(
function serialize_message (line 66) | pub fn serialize_message(message: &Message, participant_signing_keys: &S...
FILE: rust/xaynet-server/src/settings/mod.rs
type SettingsError (line 34) | pub enum SettingsError {
type Settings (line 45) | pub struct Settings {
method new (line 70) | pub fn new(path: impl AsRef<Path>) -> Result<Self, SettingsError> {
method load (line 76) | fn load(path: impl AsRef<Path>) -> Result<Self, ConfigError> {
type PetSettingsCount (line 88) | pub struct PetSettingsCount {
type PetSettingsTime (line 98) | pub struct PetSettingsTime {
type PetSettingsSum (line 108) | pub struct PetSettingsSum {
type PetSettingsUpdate (line 177) | pub struct PetSettingsUpdate {
type PetSettingsSum2 (line 251) | pub struct PetSettingsSum2 {
type PetSettings (line 308) | pub struct PetSettings {
method validate_pet (line 319) | fn validate_pet(&self) -> Result<(), ValidationError> {
method validate_counts (line 326) | fn validate_counts(&self) -> Result<(), ValidationError> {
method validate_times (line 344) | fn validate_times(&self) -> Result<(), ValidationError> {
method validate_probabilities (line 356) | fn validate_probabilities(&self) -> Result<(), ValidationError> {
function validate_pet (line 372) | fn validate_pet(s: &PetSettings) -> Result<(), ValidationError> {
type ApiSettings (line 387) | pub struct ApiSettings {
method validate_api (line 474) | fn validate_api(&self) -> Result<(), ValidationError> {
function validate_api (line 484) | fn validate_api(s: &ApiSettings) -> Result<(), ValidationError> {
type MaskSettings (line 491) | pub struct MaskSettings {
method from (line 558) | fn from(
type ModelSettings (line 578) | pub struct ModelSettings {
type MetricsSettings (line 599) | pub struct MetricsSettings {
type InfluxSettings (line 607) | pub struct InfluxSettings {
type RedisSettings (line 644) | pub struct RedisSettings {
function deserialize_redis_url (line 665) | fn deserialize_redis_url<'de, D>(deserializer: D) -> Result<ConnectionIn...
type TrustAnchorSettings (line 696) | pub struct TrustAnchorSettings {}
method default (line 700) | fn default() -> Self {
type LoggingSettings (line 707) | pub struct LoggingSettings {
function deserialize_env_filter (line 729) | fn deserialize_env_filter<'de, D>(deserializer: D) -> Result<EnvFilter, ...
method default (line 759) | fn default() -> Self {
method default (line 792) | fn default() -> Self {
function test_settings_new (line 803) | fn test_settings_new() {
function test_validate_pet (line 809) | fn test_validate_pet() {
function test_validate_pet_counts (line 814) | fn test_validate_pet_counts() {
function test_validate_pet_times (line 857) | fn test_validate_pet_times() {
function test_validate_pet_probabilities (line 875) | fn test_validate_pet_probabilities() {
function test_validate_api (line 895) | fn test_validate_api() {
FILE: rust/xaynet-server/src/settings/s3.rs
type S3Settings (line 15) | pub struct S3Settings {
type S3BucketsSettings (line 88) | pub struct S3BucketsSettings {
method default (line 113) | fn default() -> Self {
function validate_s3_bucket_name (line 122) | fn validate_s3_bucket_name(bucket_name: &str) -> Result<(), ValidationEr...
function deserialize_s3_region (line 142) | fn deserialize_s3_region<'de, D>(deserializer: D) -> Result<Region, D::E...
type RestoreSettings (line 191) | pub struct RestoreSettings {
method load_from_str (line 219) | fn load_from_str(string: &str) -> Result<Self, ConfigError> {
type ConfigBuilder (line 228) | struct ConfigBuilder {
method new (line 233) | fn new() -> Self {
method build (line 239) | fn build(self) -> String {
method with_log (line 243) | fn with_log(mut self) -> Self {
method with_api (line 253) | fn with_api(mut self) -> Self {
method with_pet (line 265) | fn with_pet(mut self) -> Self {
method with_mask (line 286) | fn with_mask(mut self) -> Self {
method with_model (line 299) | fn with_model(mut self) -> Self {
method with_metrics (line 309) | fn with_metrics(mut self) -> Self {
method with_redis (line 320) | fn with_redis(mut self) -> Self {
method with_s3 (line 330) | fn with_s3(mut self) -> Self {
method with_s3_buckets (line 342) | fn with_s3_buckets(mut self) -> Self {
method with_restore (line 352) | fn with_restore(mut self) -> Self {
method with_custom (line 362) | fn with_custom(mut self, custom_config: &str) -> Self {
function test_validate_s3_bucket_name (line 369) | fn test_validate_s3_bucket_name() {
function test_s3_bucket_name_default (line 390) | fn test_s3_bucket_name_default() {
function test_s3_bucket_name_toml_overrides_default (line 412) | fn test_s3_bucket_name_toml_overrides_default() {
function test_s3_bucket_name_env_overrides_toml_and_default (line 432) | fn test_s3_bucket_name_env_overrides_toml_and_default() {
function test_s3_bucket_name_env_overrides_default (line 454) | fn test_s3_bucket_name_env_overrides_default() {
function test_s3_region_toml (line 475) | fn test_s3_region_toml() {
function test_s3_custom_region_toml (line 501) | fn test_s3_custom_region_toml() {
function test_s3_region_env (line 526) | fn test_s3_region_env() {
function test_restore (line 547) | fn test_restore() {
function test_s3_custom_region_env (line 571) | fn test_s3_custom_region_env() {
FILE: rust/xaynet-server/src/state_machine/coordinator.rs
type CountParameters (line 23) | pub struct CountParameters {
method from (line 31) | fn from(count: PetSettingsCount) -> Self {
type TimeParameters (line 39) | pub struct TimeParameters {
method from (line 47) | fn from(time: PetSettingsTime) -> Self {
type PhaseParameters (line 55) | pub struct PhaseParameters {
method from (line 63) | fn from(sum: PetSettingsSum) -> Self {
method from (line 73) | fn from(update: PetSettingsUpdate) -> Self {
method from (line 83) | fn from(sum2: PetSettingsSum2) -> Self {
type CoordinatorState (line 94) | pub struct CoordinatorState {
method new (line 110) | pub fn new(
FILE: rust/xaynet-server/src/state_machine/events.rs
type Event (line 18) | pub struct Event<E> {
type ModelUpdate (line 29) | pub enum ModelUpdate {
type DictionaryUpdate (line 36) | pub enum DictionaryUpdate<D> {
type EventPublisher (line 43) | pub struct EventPublisher {
method init (line 68) | pub fn init(
method set_round_id (line 130) | pub fn set_round_id(&mut self, id: u64) {
method event (line 134) | fn event<T>(&self, event: T) -> Event<T> {
method broadcast_keys (line 142) | pub fn broadcast_keys(&mut self, keys: EncryptKeyPair) {
method broadcast_params (line 147) | pub fn broadcast_params(&mut self, params: RoundParameters) {
method broadcast_phase (line 152) | pub fn broadcast_phase(&mut self, phase: PhaseName) {
method broadcast_model (line 157) | pub fn broadcast_model(&mut self, update: ModelUpdate) {
method broadcast_sum_dict (line 162) | pub fn broadcast_sum_dict(&mut self, update: DictionaryUpdate<SumDict>) {
method broadcast_seed_dict (line 167) | pub fn broadcast_seed_dict(&mut self, update: DictionaryUpdate<SeedDic...
type EventSubscriber (line 57) | pub struct EventSubscriber {
method keys_listener (line 176) | pub fn keys_listener(&self) -> EventListener<EncryptKeyPair> {
method params_listener (line 180) | pub fn params_listener(&self) -> EventListener<RoundParameters> {
method phase_listener (line 185) | pub fn phase_listener(&self) -> EventListener<PhaseName> {
method model_listener (line 190) | pub fn model_listener(&self) -> EventListener<ModelUpdate> {
method sum_dict_listener (line 195) | pub fn sum_dict_listener(&self) -> EventListener<DictionaryUpdate<SumD...
method seed_dict_listener (line 200) | pub fn seed_dict_listener(&self) -> EventListener<DictionaryUpdate<See...
type EventListener (line 209) | pub struct EventListener<E>(watch::Receiver<Event<E>>);
function from (line 212) | fn from(receiver: watch::Receiver<Event<E>>) -> Self {
function get_latest (line 221) | pub fn get_latest(&self) -> Event<E> {
function changed (line 226) | pub async fn changed(&mut self) -> Result<(), watch::error::RecvError> {
type EventBroadcaster (line 233) | pub struct EventBroadcaster<E>(watch::Sender<Event<E>>);
function broadcast (line 237) | fn broadcast(&self, event: Event<E>) {
function from (line 244) | fn from(sender: watch::Sender<Event<E>>) -> Self {
FILE: rust/xaynet-server/src/state_machine/initializer.rs
type StateMachineInitializationResult (line 24) | type StateMachineInitializationResult<T> = Result<T, StateMachineInitial...
type StateMachineInitializationError (line 28) | pub enum StateMachineInitializationError {
type StateMachineInitializer (line 46) | pub struct StateMachineInitializer<T> {
function new (line 57) | pub fn new(
function init_state_machine (line 75) | fn init_state_machine(
function init (line 103) | pub async fn init(
function from_settings (line 116) | pub(in crate::state_machine) async fn from_settings(
function init (line 162) | pub async fn init(
function from_previous_state (line 180) | async fn from_previous_state(
function try_restore_state (line 199) | async fn try_restore_state(
function load_global_model (line 236) | async fn load_global_model(
function model_properties_matches_settings (line 275) | fn model_properties_matches_settings(
FILE: rust/xaynet-server/src/state_machine/mod.rs
type StateMachine (line 124) | pub enum StateMachine<T> {
function next (line 155) | pub async fn next(self) -> Option<Self> {
function run (line 172) | pub async fn run(mut self) -> Option<()> {
FILE: rust/xaynet-server/src/state_machine/phases/failure.rs
type PhaseError (line 32) | pub enum PhaseError {
type Failure (line 49) | pub struct Failure {
constant NAME (line 58) | const NAME: PhaseName = PhaseName::Failure;
function process (line 60) | async fn process(&mut self) -> Result<(), PhaseError> {
function broadcast (line 67) | fn broadcast(&mut self) {
function next (line 79) | async fn next(mut self) -> Option<StateMachine<T>> {
function new (line 91) | pub fn new(shared: Shared<T>, error: PhaseError) -> Self {
function wait_for_store_readiness (line 106) | async fn wait_for_store_readiness(&mut self) {
function state_and_events_from_sum2_phase (line 141) | fn state_and_events_from_sum2_phase() -> (CoordinatorState, EventPublish...
function error_to_idle_phase (line 155) | async fn error_to_idle_phase() {
function test_error_to_shutdown_phase (line 224) | async fn test_error_to_shutdown_phase() {
function test_error_to_idle_store_failed (line 284) | async fn test_error_to_idle_store_failed() {
function test_error_to_shutdown_skip_store_readiness_check (line 359) | async fn test_error_to_shutdown_skip_store_readiness_check() {
FILE: rust/xaynet-server/src/state_machine/phases/handler.rs
type Handler (line 19) | pub trait Handler {
method handle_request (line 24) | async fn handle_request(&mut self, req: StateMachineRequest) -> Result...
type Counter (line 28) | struct Counter {
method as_mut (line 42) | fn as_mut(&mut self) -> &mut Self {
method new (line 49) | fn new(CountParameters { min, max }: CountParameters) -> Self {
method has_enough_messages (line 60) | fn has_enough_messages(&self) -> bool {
method has_overmuch_messages (line 65) | fn has_overmuch_messages(&self) -> bool {
method increment_accepted (line 70) | fn increment_accepted(&mut self) {
method increment_rejected (line 79) | fn increment_rejected(&mut self) {
method increment_discarded (line 85) | fn increment_discarded(&mut self) {
function process (line 103) | pub(super) async fn process(
function process_during (line 138) | async fn process_during(
function process_until_enough (line 163) | async fn process_until_enough(&mut self, counter: &mut Counter) -> Resul...
function process_single (line 175) | async fn process_single(
function test_counter (line 210) | fn test_counter() {
FILE: rust/xaynet-server/src/state_machine/phases/idle.rs
type IdleError (line 23) | pub enum IdleError {
type Idle (line 32) | pub struct Idle;
constant NAME (line 39) | const NAME: PhaseName = PhaseName::Idle;
function process (line 41) | async fn process(&mut self) -> Result<(), PhaseError> {
function broadcast (line 53) | fn broadcast(&mut self) {
function next (line 59) | async fn next(self) -> Option<StateMachine<T>> {
function new (line 66) | pub fn new(mut shared: Shared<T>) -> Self {
function update_round_probabilities (line 79) | fn update_round_probabilities(&mut self) {
function update_round_seed (line 85) | fn update_round_seed(&mut self) {
function gen_round_keypair (line 105) | fn gen_round_keypair(&mut self) {
function broadcast_keys (line 112) | fn broadcast_keys(&mut self) {
function broadcast_params (line 120) | fn broadcast_params(&mut self) {
function delete_dicts (line 133) | async fn delete_dicts(&mut self) -> Result<(), IdleError> {
function set_coordinator_state (line 143) | async fn set_coordinator_state(&mut self) -> Result<(), IdleError> {
function broadcast_metrics (line 159) | fn broadcast_metrics(&self) {
function state_and_events_from_unmask_phase (line 201) | fn state_and_events_from_unmask_phase() -> (CoordinatorState, EventPubli...
function assert_params (line 214) | fn assert_params(params1: &RoundParameters, params2: &RoundParameters) {
function assert_after_delete_dict_failure (line 223) | fn assert_after_delete_dict_failure(
function test_idle_to_sum_phase (line 268) | async fn test_idle_to_sum_phase() {
function test_idle_to_sum_delete_dicts_failed (line 333) | async fn test_idle_to_sum_delete_dicts_failed() {
function test_idle_to_sum_save_state_failed (line 382) | async fn test_idle_to_sum_save_state_failed() {
FILE: rust/xaynet-server/src/state_machine/phases/phase.rs
type PhaseName (line 25) | pub enum PhaseName {
type Phase (line 49) | pub trait Phase<T>
constant NAME (line 54) | const NAME: PhaseName;
method process (line 57) | async fn process(&mut self) -> Result<(), PhaseError>;
method broadcast (line 66) | fn broadcast(&mut self) {}
method next (line 69) | async fn next(self) -> Option<StateMachine<T>>;
type Shared (line 74) | pub struct Shared<T> {
function fmt (line 86) | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
function new (line 97) | pub fn new(
function set_round_id (line 112) | pub fn set_round_id(&mut self, id: u64) {
function round_id (line 118) | pub fn round_id(&self) -> u64 {
type PhaseState (line 127) | pub struct PhaseState<S, T> {
function run_phase (line 146) | pub async fn run_phase(mut self) -> Option<StateMachine<T>> {
function purge_outdated_requests (line 183) | fn purge_outdated_requests(&mut self) -> Result<(), PhaseError> {
function next_request (line 200) | pub async fn next_request(
function try_next_request (line 210) | pub fn try_next_request(
function into_failure_state (line 228) | fn into_failure_state(self, err: PhaseError) -> StateMachine<T> {
FILE: rust/xaynet-server/src/state_machine/phases/shutdown.rs
type Shutdown (line 14) | pub struct Shutdown;
constant NAME (line 21) | const NAME: PhaseName = PhaseName::Shutdown;
function process (line 23) | async fn process(&mut self) -> Result<(), PhaseError> {
function next (line 31) | async fn next(self) -> Option<StateMachine<T>> {
function new (line 38) | pub fn new(shared: Shared<T>) -> Self {
function test_shutdown_to_none (line 63) | async fn test_shutdown_to_none() {
FILE: rust/xaynet-server/src/state_machine/phases/sum.rs
type SumError (line 21) | pub enum SumError {
type Sum (line 30) | pub struct Sum {
constant NAME (line 41) | const NAME: PhaseName = PhaseName::Sum;
function process (line 43) | async fn process(&mut self) -> Result<(), PhaseError> {
function broadcast (line 50) | fn broadcast(&mut self) {
function next (line 62) | async fn next(self) -> Option<StateMachine<T>> {
method handle_request (line 72) | async fn handle_request(&mut self, req: StateMachineRequest) -> Result<(...
function new (line 87) | pub fn new(shared: Shared<T>) -> Self {
function update_sum_dict (line 100) | async fn update_sum_dict(
function sum_dict (line 114) | async fn sum_dict(&mut self) -> Result<(), SumError> {
function events_from_idle_phase (line 162) | fn events_from_idle_phase(state: &CoordinatorState) -> (EventPublisher, ...
function assert_after_phase_success (line 171) | fn assert_after_phase_success(
function assert_after_phase_failure (line 188) | fn assert_after_phase_failure(
function test_sum_to_update_phase (line 206) | async fn test_sum_to_update_phase() {
function test_sum_phase_timeout (line 261) | async fn test_sum_phase_timeout() {
function test_rejected_messages (line 313) | async fn test_rejected_messages() {
function test_discarded_messages (line 369) | async fn test_discarded_messages() {
function test_request_channel_is_dropped (line 425) | async fn test_request_channel_is_dropped() {
function test_sum_to_update_fetch_sum_dict_failed (line 477) | async fn test_sum_to_update_fetch_sum_dict_failed() {
function test_sum_to_update_sum_dict_none (line 535) | async fn test_sum_to_update_sum_dict_none() {
function test_rejected_messages_pet_error (line 592) | async fn test_rejected_messages_pet_error() {
FILE: rust/xaynet-server/src/state_machine/phases/sum2.rs
type Sum2 (line 20) | pub struct Sum2 {
constant NAME (line 31) | const NAME: PhaseName = PhaseName::Sum2;
function process (line 33) | async fn process(&mut self) -> Result<(), PhaseError> {
function broadcast (line 37) | fn broadcast(&mut self) {
function next (line 49) | async fn next(self) -> Option<StateMachine<T>> {
method handle_request (line 59) | async fn handle_request(&mut self, req: StateMachineRequest) -> Result<(...
function new (line 74) | pub fn new(shared: Shared<T>, model_agg: Aggregation) -> Self {
function update_mask_dict (line 87) | async fn update_mask_dict(
function events_from_update_phase (line 133) | fn events_from_update_phase(state: &CoordinatorState) -> (EventPublisher...
function assert_after_phase_success (line 142) | fn assert_after_phase_success(
function assert_after_phase_failure (line 161) | fn assert_after_phase_failure(
function test_sum2_to_unmask_phase (line 179) | async fn test_sum2_to_unmask_phase() {
function test_rejected_messages_pet_error (line 237) | async fn test_rejected_messages_pet_error() {
FILE: rust/xaynet-server/src/state_machine/phases/unmask.rs
type UnmaskError (line 24) | pub enum UnmaskError {
type Unmask (line 42) | pub struct Unmask {
constant NAME (line 54) | const NAME: PhaseName = PhaseName::Unmask;
function process (line 56) | async fn process(&mut self) -> Result<(), PhaseError> {
function broadcast (line 68) | fn broadcast(&mut self) {
function next (line 79) | async fn next(self) -> Option<StateMachine<T>> {
function new (line 86) | pub fn new(shared: Shared<T>, model_agg: Aggregation) -> Self {
function freeze_mask_dict (line 97) | async fn freeze_mask_dict(
function end_round (line 118) | async fn end_round(&mut self, best_masks: Vec<(MaskObject, u64)>) -> Res...
function emit_number_of_unique_masks_metrics (line 138) | fn emit_number_of_unique_masks_metrics(&mut self) {
function best_masks (line 160) | async fn best_masks(&mut self) -> Result<Vec<(MaskObject, u64)>, UnmaskE...
function save_global_model (line 171) | async fn save_global_model(&mut self) -> Result<(), UnmaskError> {
function publish_proof (line 204) | async fn publish_proof(&mut self) -> Result<(), UnmaskError> {
function events_from_sum2_phase (line 251) | fn events_from_sum2_phase(state: &CoordinatorState) -> (EventPublisher, ...
function assert_after_phase_success (line 260) | fn assert_after_phase_success(
function assert_after_phase_failure (line 282) | fn assert_after_phase_failure(
function init_aggregator (line 299) | fn init_aggregator(state: &CoordinatorState) -> Aggregation {
function test_unmask_to_idle_phase (line 309) | async fn test_unmask_to_idle_phase() {
function test_unmask_to_idle_phase_best_masks_fails (line 377) | async fn test_unmask_to_idle_phase_best_masks_fails() {
function test_unmask_to_idle_phase_no_mask (line 427) | async fn test_unmask_to_idle_phase_no_mask() {
function test_unmask_to_idle_phase_ambiguous_masks (line 476) | async fn test_unmask_to_idle_phase_ambiguous_masks() {
function test_unmask_to_idle_phase_validate_unmasking_fails (line 533) | async fn test_unmask_to_idle_phase_validate_unmasking_fails() {
function test_unmask_to_idle_phase_publish_proof_fails (line 589) | async fn test_unmask_to_idle_phase_publish_proof_fails() {
function test_unmask_to_idle_phase_set_global_model_fails (line 674) | async fn test_unmask_to_idle_phase_set_global_model_fails() {
function test_unmask_to_idle_phase_set_global_model_id_fails (line 736) | async fn test_unmask_to_idle_phase_set_global_model_id_fails() {
FILE: rust/xaynet-server/src/state_machine/phases/update.rs
type UpdateError (line 26) | pub enum UpdateError {
type Update (line 35) | pub struct Update {
constant NAME (line 48) | const NAME: PhaseName = PhaseName::Update;
function process (line 50) | async fn process(&mut self) -> Result<(), PhaseError> {
function broadcast (line 57) | fn broadcast(&mut self) {
function next (line 69) | async fn next(self) -> Option<StateMachine<T>> {
method handle_request (line 79) | async fn handle_request(&mut self, req: StateMachineRequest) -> Result<(...
function new (line 100) | pub fn new(shared: Shared<T>) -> Self {
function update_seed_dict_and_aggregate_mask (line 120) | async fn update_seed_dict_and_aggregate_mask(
function add_local_seed_dict (line 159) | async fn add_local_seed_dict(
function seed_dict (line 173) | async fn seed_dict(&mut self) -> Result<(), UpdateError> {
function events_from_sum_phase (line 223) | fn events_from_sum_phase(state: &CoordinatorState) -> (EventPublisher, E...
function assert_after_phase_success (line 232) | fn assert_after_phase_success(
function assert_after_phase_failure (line 249) | fn assert_after_phase_failure(
function test_update_to_sum2_phase (line 267) | async fn test_update_to_sum2_phase() {
function test_update_to_sum2_fetch_seed_dict_failed (line 323) | async fn test_update_to_sum2_fetch_seed_dict_failed() {
function test_update_to_sum2_seed_dict_none (line 382) | async fn test_update_to_sum2_seed_dict_none() {
function test_aggregation_error (line 440) | async fn test_aggregation_error() {
function test_rejected_messages_pet_error (line 497) | async fn test_rejected_messages_pet_error() {
FILE: rust/xaynet-server/src/state_machine/requests.rs
type RequestError (line 29) | pub enum RequestError {
type SumRequest (line 50) | pub struct SumRequest {
type UpdateRequest (line 59) | pub struct UpdateRequest {
type Sum2Request (line 70) | pub struct Sum2Request {
type StateMachineRequest (line 81) | pub enum StateMachineRequest {
method from (line 88) | fn from(message: Message) -> Self {
type RequestSender (line 120) | pub struct RequestSender(mpsc::UnboundedSender<(StateMachineRequest, Spa...
method request (line 130) | pub async fn request(&self, req: StateMachineRequest, span: Span) -> R...
method is_closed (line 143) | pub fn is_closed(&self) -> bool {
type ResponseSender (line 150) | pub(in crate::state_machine) type ResponseSender = oneshot::Sender<Resul...
type RequestReceiver (line 157) | pub struct RequestReceiver(mpsc::UnboundedReceiver<(StateMachineRequest,...
method new (line 171) | pub fn new() -> (Self, RequestSender) {
method close (line 182) | pub fn close(&mut self) {
method recv (line 190) | pub async fn recv(&mut self) -> Option<(StateMachineRequest, Span, Res...
method try_recv (line 195) | pub fn try_recv(&mut self) -> Option<Option<(StateMachineRequest, Span...
type Item (line 160) | type Item = (StateMachineRequest, Span, ResponseSender);
method poll_next (line 162) | fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self...
FILE: rust/xaynet-server/src/state_machine/tests/coordinator_state.rs
type CoordinatorStateBuilder (line 7) | pub struct CoordinatorStateBuilder {
method new (line 13) | pub fn new() -> Self {
method build (line 19) | pub fn build(self) -> CoordinatorState {
method with_keys (line 23) | pub fn with_keys(mut self, keys: EncryptKeyPair) -> Self {
method with_round_id (line 29) | pub fn with_round_id(mut self, id: u64) -> Self {
method with_sum_probability (line 34) | pub fn with_sum_probability(mut self, prob: f64) -> Self {
method with_update_probability (line 39) | pub fn with_update_probability(mut self, prob: f64) -> Self {
method with_seed (line 44) | pub fn with_seed(mut self, seed: RoundSeed) -> Self {
method with_sum_count_min (line 49) | pub fn with_sum_count_min(mut self, min: u64) -> Self {
method with_sum_count_max (line 54) | pub fn with_sum_count_max(mut self, max: u64) -> Self {
method with_mask_config (line 59) | pub fn with_mask_config(mut self, mask_config: MaskConfig) -> Self {
method with_update_count_min (line 64) | pub fn with_update_count_min(mut self, min: u64) -> Self {
method with_update_count_max (line 69) | pub fn with_update_count_max(mut self, max: u64) -> Self {
method with_sum2_count_min (line 74) | pub fn with_sum2_count_min(mut self, min: u64) -> Self {
method with_sum2_count_max (line 79) | pub fn with_sum2_count_max(mut self, max: u64) -> Self {
method with_model_length (line 84) | pub fn with_model_length(mut self, model_length: usize) -> Self {
method with_sum_time_min (line 89) | pub fn with_sum_time_min(mut self, min: u64) -> Self {
method with_sum_time_max (line 94) | pub fn with_sum_time_max(mut self, max: u64) -> Self {
method with_update_time_min (line 99) | pub fn with_update_time_min(mut self, min: u64) -> Self {
method with_update_time_max (line 104) | pub fn with_update_time_max(mut self, max: u64) -> Self {
method with_sum2_time_min (line 109) | pub fn with_sum2_time_min(mut self, min: u64) -> Self {
method with_sum2_time_max (line 114) | pub fn with_sum2_time_max(mut self, max: u64) -> Self {
FILE: rust/xaynet-server/src/state_machine/tests/event_bus.rs
type EventBusBuilder (line 11) | pub struct EventBusBuilder {
method new (line 17) | pub fn new(state: &CoordinatorState) -> Self {
method broadcast_phase (line 32) | pub fn broadcast_phase(mut self, phase: PhaseName) -> Self {
method broadcast_model (line 37) | pub fn broadcast_model(mut self, update: ModelUpdate) -> Self {
method broadcast_sum_dict (line 42) | pub fn broadcast_sum_dict(mut self, update: DictionaryUpdate<SumDict>)...
method broadcast_seed_dict (line 47) | pub fn broadcast_seed_dict(mut self, update: DictionaryUpdate<SeedDict...
method build (line 52) | pub fn build(self) -> (EventPublisher, EventSubscriber) {
function test_initial_events (line 58) | fn test_initial_events() {
FILE: rust/xaynet-server/src/state_machine/tests/impls.rs
method msg (line 13) | pub async fn msg(&self, msg: &Message) -> Result<(), RequestError> {
function is_idle (line 19) | pub fn is_idle(&self) -> bool {
function into_idle_phase_state (line 23) | pub fn into_idle_phase_state(self) -> PhaseState<Idle, T> {
function is_sum (line 30) | pub fn is_sum(&self) -> bool {
function into_sum_phase_state (line 34) | pub fn into_sum_phase_state(self) -> PhaseState<Sum, T> {
function is_update (line 41) | pub fn is_update(&self) -> bool {
function into_update_phase_state (line 45) | pub fn into_update_phase_state(self) -> PhaseState<Update, T> {
function is_sum2 (line 52) | pub fn is_sum2(&self) -> bool {
function into_sum2_phase_state (line 56) | pub fn into_sum2_phase_state(self) -> PhaseState<Sum2, T> {
function is_unmask (line 63) | pub fn is_unmask(&self) -> bool {
function into_unmask_phase_state (line 67) | pub fn into_unmask_phase_state(self) -> PhaseState<Unmask, T> {
function is_failure (line 74) | pub fn is_failure(&self) -> bool {
function into_failure_phase_state (line 78) | pub fn into_failure_phase_state(self) -> PhaseState<Failure, T> {
function is_shutdown (line 85) | pub fn is_shutdown(&self) -> bool {
function into_shutdown_phase_state (line 89) | pub fn into_shutdown_phase_state(self) -> PhaseState<Shutdown, T> {
function as_ref (line 98) | fn as_ref(&self) -> &CoordinatorState {
function unwrap (line 112) | pub fn unwrap(self) -> std::sync::Arc<D> {
FILE: rust/xaynet-server/src/state_machine/tests/initializer.rs
function integration_state_machine_initializer_no_restore (line 29) | async fn integration_state_machine_initializer_no_restore() {
function integration_state_machine_initializer_no_state (line 63) | async fn integration_state_machine_initializer_no_state() {
function integration_state_machine_initializer_without_global_model (line 97) | async fn integration_state_machine_initializer_without_global_model() {
function integration_state_machine_initializer_with_global_model (line 144) | async fn integration_state_machine_initializer_with_global_model() {
function integration_state_machine_initializer_failed_because_of_wrong_size (line 204) | async fn integration_state_machine_initializer_failed_because_of_wrong_s...
function integration_state_machine_initializer_failed_to_find_global_model (line 250) | async fn integration_state_machine_initializer_failed_to_find_global_mod...
function integration_state_machine_initializer_reset_state (line 287) | async fn integration_state_machine_initializer_reset_state() {
FILE: rust/xaynet-server/src/state_machine/tests/mod.rs
constant WARNING (line 12) | const WARNING: &str = "All state machine tests were written assuming the...
FILE: rust/xaynet-server/src/state_machine/tests/utils.rs
function enable_logging (line 40) | pub fn enable_logging() {
function pet_settings (line 47) | pub fn pet_settings() -> PetSettings {
function mask_settings (line 66) | pub fn mask_settings() -> MaskSettings {
function model_settings (line 75) | pub fn model_settings() -> ModelSettings {
function init_shared (line 79) | pub fn init_shared<T>(
type EventSnapshot (line 92) | pub struct EventSnapshot {
method from (line 102) | fn from(event_subscriber: &EventSubscriber) -> Self {
function assert_event_updated_with_id (line 114) | pub fn assert_event_updated_with_id<T: Debug + PartialEq>(event1: &Event...
function assert_event_updated (line 119) | pub fn assert_event_updated<T: Debug + PartialEq>(event1: &Event<T>, eve...
function compose_sum_message (line 124) | pub fn compose_sum_message() -> Message {
function compose_update_message (line 136) | pub fn compose_update_message(masked_model: MaskObject) -> Message {
function compose_sum2_message (line 150) | pub fn compose_sum2_message() -> Message {
function send_sum_messages (line 162) | pub fn send_sum_messages(n: u32, request_tx: RequestSender) {
function send_sum_messages_with_latch (line 170) | pub fn send_sum_messages_with_latch(n: u32, request_tx: RequestSender, l...
function send_sum2_messages (line 181) | pub fn send_sum2_messages(n: u32, request_tx: RequestSender) {
function send_update_messages (line 188) | pub fn send_update_messages(n: u32, request_tx: RequestSender) {
function send_update_messages_with_model (line 197) | pub fn send_update_messages_with_model(
type Readiness (line 214) | pub struct Readiness(mpsc::Receiver<()>);
method new (line 222) | pub fn new() -> (Readiness, Latch) {
method is_ready (line 227) | pub async fn is_ready(&mut self) {
type Latch (line 218) | pub struct Latch(mpsc::Sender<()>);
method release (line 234) | pub fn release(self) {
function test_initial_settings (line 240) | fn test_initial_settings() {
FILE: rust/xaynet-server/src/storage/coordinator_storage/redis/impls.rs
function redis_type_error (line 25) | pub fn redis_type_error(desc: &'static str, details: Option<String>) -> ...
function error_code_type_error (line 33) | fn error_code_type_error(response: &Value) -> RedisError {
type MaskObjectRead (line 155) | pub(crate) struct MaskObjectRead(MaskObject);
type MaskObjectWrite (line 160) | pub(crate) struct MaskObjectWrite<'a>(&'a MaskObject);
method write_redis_args (line 163) | fn write_redis_args<W>(&self, out: &mut W)
type LocalSeedDictWrite (line 173) | pub(crate) struct LocalSeedDictWrite<'a>(&'a LocalSeedDict);
method write_redis_args (line 176) | fn write_redis_args<W>(&self, out: &mut W)
method from_redis_value (line 196) | fn from_redis_value(v: &Value) -> RedisResult<LocalSeedDictAdd> {
method from_redis_value (line 209) | fn from_redis_value(v: &Value) -> RedisResult<SumPartAdd> {
method from_redis_value (line 222) | fn from_redis_value(v: &Value) -> RedisResult<MaskScoreIncr> {
type SumDictDelete (line 236) | pub struct SumDictDelete(Result<(), SumDictDeleteError>);
method into_inner (line 240) | pub fn into_inner(self) -> Result<(), SumDictDeleteError> {
type SumDictDeleteError (line 248) | pub enum SumDictDeleteError {
method from_redis_value (line 255) | fn from_redis_value(v: &Value) -> RedisResult<SumDictDelete> {
FILE: rust/xaynet-server/src/storage/coordinator_storage/redis/mod.rs
type Client (line 82) | pub struct Client {
method new (line 98) | pub async fn new<T: IntoConnectionInfo>(url: T) -> Result<Self, RedisE...
method create_flush_dicts_pipeline (line 104) | async fn create_flush_dicts_pipeline(&mut self) -> RedisResult<Pipelin...
method remove_sum_dict_entry (line 448) | pub async fn remove_sum_dict_entry(
method sum_dict_len (line 462) | pub async fn sum_dict_len(&mut self) -> RedisResult<u64> {
method sum_pks (line 471) | pub async fn sum_pks(
method remove_update_participant (line 485) | pub async fn remove_update_participant(
method mask_submitted_set (line 497) | pub async fn mask_submitted_set(&mut self) -> RedisResult<Vec<SumParti...
method keys (line 505) | pub async fn keys(&mut self) -> RedisResult<Vec<String>> {
method seed_dict_for_sum_pk (line 511) | pub async fn seed_dict_for_sum_pk(
method flush_db (line 537) | pub async fn flush_db(&mut self) -> RedisResult<()> {
function to_storage_err (line 86) | fn to_storage_err(e: RedisError) -> StorageError {
method set_coordinator_state (line 136) | async fn set_coordinator_state(&mut self, state: &CoordinatorState) -> S...
method coordinator_state (line 149) | async fn coordinator_state(&mut self) -> StorageResult<Option<Coordinato...
method add_sum_participant (line 162) | async fn add_sum_participant(
method sum_dict (line 184) | async fn sum_dict(&mut self) -> StorageResult<Option<SumDict>> {
method add_local_seed_dict (line 208) | async fn add_local_seed_dict(
method seed_dict (line 271) | async fn seed_dict(&mut self) -> StorageResult<Option<SeedDict>> {
method incr_mask_score (line 303) | async fn incr_mask_score(
method best_masks (line 344) | async fn best_masks(&mut self) -> StorageResult<Option<Vec<(MaskObject, ...
method number_of_unique_masks (line 370) | async fn number_of_unique_masks(&mut self) -> StorageResult<u64> {
method delete_coordinator_data (line 383) | async fn delete_coordinator_data(&mut self) -> StorageResult<()> {
method delete_dicts (line 396) | async fn delete_dicts(&mut self) -> StorageResult<()> {
method set_latest_global_model_id (line 405) | async fn set_latest_global_model_id(&mut self, global_model_id: &str) ->...
method latest_global_model_id (line 418) | async fn latest_global_model_id(&mut self) -> StorageResult<Option<Strin...
method is_ready (line 432) | async fn is_ready(&mut self) -> StorageResult<()> {
function create_redis_client (line 558) | async fn create_redis_client() -> Client {
function init_client (line 562) | pub async fn init_client() -> Client {
function integration_set_and_get_coordinator_state (line 571) | async fn integration_set_and_get_coordinator_state() {
function integration_get_coordinator_empty (line 586) | async fn integration_get_coordinator_empty() {
function integration_incr_mask_score (line 598) | async fn integration_incr_mask_score() {
function integration_get_incr_mask_count_unknown_sum_pk (line 623) | async fn integration_get_incr_mask_count_unknown_sum_pk() {
function integration_get_incr_mask_score_sum_pk_already_submitted (line 643) | async fn integration_get_incr_mask_score_sum_pk_already_submitted() {
function integration_get_best_masks_only_one_mask (line 667) | async fn integration_get_best_masks_only_one_mask() {
function integration_get_best_masks_two_masks (line 690) | async fn integration_get_best_masks_two_masks() {
function integration_get_best_masks_no_mask (line 727) | async fn integration_get_best_masks_no_mask() {
function integration_get_number_of_unique_masks_empty (line 738) | async fn integration_get_number_of_unique_masks_empty() {
function integration_get_number_of_unique_masks (line 749) | async fn integration_get_number_of_unique_masks() {
function integration_sum_dict (line 770) | async fn integration_sum_dict() {
function integration_seed_dict (line 826) | async fn integration_seed_dict() {
function integration_seed_dict_len_mis_match (line 845) | async fn integration_seed_dict_len_mis_match() {
function integration_seed_dict_unknown_sum_participant (line 866) | async fn integration_seed_dict_unknown_sum_participant() {
function integration_seed_dict_update_pk_already_submitted (line 889) | async fn integration_seed_dict_update_pk_already_submitted() {
function integration_seed_dict_update_pk_already_exists_in_update_seed_dict (line 909) | async fn integration_seed_dict_update_pk_already_exists_in_update_seed_d...
function integration_seed_dict_get_seed_dict_for_sum_pk (line 937) | async fn integration_seed_dict_get_seed_dict_for_sum_pk() {
function integration_seed_dict_get_seed_dict_for_sum_pk_empty (line 958) | async fn integration_seed_dict_get_seed_dict_for_sum_pk_empty() {
function integration_flush_dicts (line 969) | async fn integration_flush_dicts() {
function integration_flush_coordinator_data (line 1019) | async fn integration_flush_coordinator_data() {
function integration_set_and_get_latest_global_model_id (line 1053) | async fn integration_set_and_get_latest_global_model_id() {
function integration_is_ready_ok (line 1068) | async fn integration_is_ready_ok() {
function integration_get_latest_global_model_id_empty (line 1079) | async fn integration_get_latest_global_model_id_empty() {
FILE: rust/xaynet-server/src/storage/model_storage/noop.rs
type NoOp (line 8) | pub struct NoOp;
method set_global_model (line 12) | async fn set_global_model(
method global_model (line 21) | async fn global_model(&mut self, _id: &str) -> StorageResult<Option<Mode...
method is_ready (line 25) | async fn is_ready(&mut self) -> StorageResult<()> {
FILE: rust/xaynet-server/src/storage/model_storage/s3.rs
type ClientResult (line 37) | type ClientResult<T> = Result<T, ClientError>;
type ClientError (line 40) | pub enum ClientError {
type Client (line 68) | pub struct Client {
method new (line 100) | pub fn new(settings: S3Settings) -> ClientResult<Self> {
method create_global_models_bucket (line 113) | pub async fn create_global_models_bucket(&self) -> ClientResult<()> {
method download_object_body (line 124) | async fn download_object_body(object: GetObjectOutput) -> ClientResult...
method fetch_object_meta (line 137) | async fn fetch_object_meta(
method upload_object (line 152) | async fn upload_object(
method create_bucket (line 168) | async fn create_bucket(
method clear_bucket (line 269) | pub async fn clear_bucket(&self, bucket: &str) -> ClientResult<()> {
method unpack_object_identifier (line 291) | fn unpack_object_identifier(
method delete_objects (line 310) | async fn delete_objects(
method list_objects (line 328) | async fn list_objects(
method unpack_next_continuation_token (line 347) | fn unpack_next_continuation_token(list_obj_resp: &ListObjectsV2Output)...
method delete_bucket (line 360) | async fn delete_bucket(&self, bucket: &str) -> Result<(), RusotoError<...
method set_global_model (line 182) | async fn set_global_model(
method global_model (line 206) | async fn global_model(&mut self, id: &str) -> StorageResult<Option<Model...
method is_ready (line 222) | async fn is_ready(&mut self) -> StorageResult<()> {
function create_minio_setup (line 369) | fn create_minio_setup(url: &str) -> S3Settings {
function init_client (line 383) | pub async fn init_client() -> Client {
function init_disconnected_client (line 391) | async fn init_disconnected_client() -> Client {
function integration_test_set_and_get_global_model (line 399) | async fn integration_test_set_and_get_global_model() {
function integration_test_get_global_model_non_existent (line 415) | async fn integration_test_get_global_model_non_existent() {
function integration_test_global_model_already_exists (line 426) | async fn integration_test_global_model_already_exists() {
function integration_test_is_ready_ok (line 453) | async fn integration_test_is_ready_ok() {
function integration_test_is_ready_ok_no_such_bucket (line 463) | async fn integration_test_is_ready_ok_no_such_bucket() {
function integration_test_is_ready_err (line 478) | async fn integration_test_is_ready_err() {
FILE: rust/xaynet-server/src/storage/store.rs
type Store (line 32) | pub struct Store<C, M, T>
function new_with_trust_anchor (line 52) | pub fn new_with_trust_anchor(coordinator: C, model: M, trust_anchor: T) ...
function new (line 67) | pub fn new(coordinator: C, model: M) -> Self {
method set_coordinator_state (line 83) | async fn set_coordinator_state(&mut self, state: &CoordinatorState) -> S...
method coordinator_state (line 87) | async fn coordinator_state(&mut self) -> StorageResult<Option<Coordinato...
method add_sum_participant (line 91) | async fn add_sum_participant(
method sum_dict (line 99) | async fn sum_dict(&mut self) -> StorageResult<Option<SumDict>> {
method add_local_seed_dict (line 103) | async fn add_local_seed_dict(
method seed_dict (line 113) | async fn seed_dict(&mut self) -> StorageResult<Option<SeedDict>> {
method incr_mask_score (line 117) | async fn incr_mask_score(
method best_masks (line 125) | async fn best_masks(&mut self) -> StorageResult<Option<Vec<(MaskObject, ...
method number_of_unique_masks (line 129) | async fn number_of_unique_masks(&mut self) -> StorageResult<u64> {
method delete_coordinator_data (line 133) | async fn delete_coordinator_data(&mut self) -> StorageResult<()> {
method delete_dicts (line 137) | async fn delete_dicts(&mut self) -> StorageResult<()> {
method set_latest_global_model_id (line 141) | async fn set_latest_global_model_id(&mut self, id: &str) -> StorageResul...
method latest_global_model_id (line 145) | async fn latest_global_model_id(&mut self) -> StorageResult<Option<Strin...
method is_ready (line 149) | async fn is_ready(&mut self) -> StorageResult<()> {
method set_global_model (line 161) | async fn set_global_model(
method global_model (line 172) | async fn global_model(&mut self, id: &str) -> StorageResult<Option<Model...
method is_ready (line 176) | async fn is_ready(&mut self) -> StorageResult<()> {
method publish_proof (line 188) | async fn publish_proof(&mut self, global_model: &Model) -> StorageResult...
method is_ready (line 192) | async fn is_ready(&mut self) -> StorageResult<()> {
method is_ready (line 204) | async fn is_ready(&mut self) -> StorageResult<()> {
FILE: rust/xaynet-server/src/storage/tests/mod.rs
function init_store (line 32) | pub async fn init_store() -> impl Storage {
FILE: rust/xaynet-server/src/storage/tests/utils.rs
function create_sum_participant_entry (line 18) | pub fn create_sum_participant_entry() -> (SumParticipantPublicKey, SumPa...
function create_local_seed_entries (line 27) | pub fn create_local_seed_entries(
function create_mask_zeroed (line 48) | pub fn create_mask_zeroed(model_length: usize) -> MaskObject {
function create_mask (line 57) | pub fn create_mask(model_length: usize, number: u32) -> MaskObject {
function create_seed_dict (line 66) | pub fn create_seed_dict(
function create_and_add_sum_participant_entries (line 84) | pub async fn create_and_add_sum_participant_entries(
function add_local_seed_entries (line 99) | pub async fn add_local_seed_entries(
function create_global_model (line 116) | pub fn create_global_model(model_length: usize) -> Model {
FILE: rust/xaynet-server/src/storage/traits.rs
type StorageError (line 24) | pub type StorageError = anyhow::Error;
type StorageResult (line 27) | pub type StorageResult<T> = Result<T, StorageError>;
type CoordinatorStorage (line 31) | pub trait CoordinatorStorage
method set_coordinator_state (line 41) | async fn set_coordinator_state(&mut self, state: &CoordinatorState) ->...
method coordinator_state (line 49) | async fn coordinator_state(&mut self) -> StorageResult<Option<Coordina...
method add_sum_participant (line 60) | async fn add_sum_participant(
method sum_dict (line 72) | async fn sum_dict(&mut self) -> StorageResult<Option<SumDict>>;
method add_local_seed_dict (line 83) | async fn add_local_seed_dict(
method seed_dict (line 95) | async fn seed_dict(&mut self) -> StorageResult<Option<SeedDict>>;
method incr_mask_score (line 106) | async fn incr_mask_score(
method best_masks (line 123) | async fn best_masks(&mut self) -> StorageResult<Option<Vec<(MaskObject...
method number_of_unique_masks (line 126) | async fn number_of_unique_masks(&mut self) -> StorageResult<u64>;
method delete_coordinator_data (line 130) | async fn delete_coordinator_data(&mut self) -> StorageResult<()>;
method delete_dicts (line 133) | async fn delete_dicts(&mut self) -> StorageResult<()>;
method set_latest_global_model_id (line 142) | async fn set_latest_global_model_id(&mut self, id: &str) -> StorageRes...
method latest_global_model_id (line 150) | async fn latest_global_model_id(&mut self) -> StorageResult<Option<Str...
method is_ready (line 159) | async fn is_ready(&mut self) -> StorageResult<()>;
type ModelStorage (line 164) | pub trait ModelStorage
method set_global_model (line 175) | async fn set_global_model(
method global_model (line 188) | async fn global_model(&mut self, id: &str) -> StorageResult<Option<Mod...
method create_global_model_id (line 195) | fn create_global_model_id(round_id: u64, round_seed: &RoundSeed) -> St...
method is_ready (line 207) | async fn is_ready(&mut self) -> StorageResult<()>;
type TrustAnchor (line 212) | pub trait TrustAnchor
method publish_proof (line 222) | async fn publish_proof(&mut self, global_model: &Model) -> StorageResu...
method is_ready (line 231) | async fn is_ready(&mut self) -> StorageResult<()>;
type Storage (line 235) | pub trait Storage: CoordinatorStorage + ModelStorage + TrustAnchor {
method is_ready (line 245) | async fn is_ready(&mut self) -> StorageResult<()>;
type SumPartAdd (line 250) | pub struct SumPartAdd(pub(crate) Result<(), SumPartAddError>);
method into_inner (line 254) | pub fn into_inner(self) -> Result<(), SumPartAddError> {
type SumPartAddError (line 262) | pub enum SumPartAddError {
type LocalSeedDictAdd (line 269) | pub struct LocalSeedDictAdd(pub(crate) Result<(), LocalSeedDictAddError>);
method into_inner (line 273) | pub fn into_inner(self) -> Result<(), LocalSeedDictAddError> {
type LocalSeedDictAddError (line 281) | pub enum LocalSeedDictAddError {
type MaskScoreIncr (line 294) | pub struct MaskScoreIncr(pub(crate) Result<(), MaskScoreIncrError>);
method into_inner (line 298) | pub fn into_inner(self) -> Result<(), MaskScoreIncrError> {
type MaskScoreIncrError (line 306) | pub enum MaskScoreIncrError {
FILE: rust/xaynet-server/src/storage/trust_anchor/noop.rs
type NoOp (line 6) | pub struct NoOp;
method publish_proof (line 10) | async fn publish_proof(&mut self, _global_model: &Model) -> StorageResul...
method is_ready (line 14) | async fn is_ready(&mut self) -> StorageResult<()> {
Condensed preview — 247 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,356K chars).
[
{
"path": ".dockerignore",
"chars": 103,
"preview": "**/.ignore\n**/shell.nix\n**/.envrc\n\n.git\n.github\nassets\nbindings\nconfigs\ndocker\nk8s\nrust/target\nscripts\n"
},
{
"path": ".github/codecov.yml",
"chars": 35,
"preview": "coverage:\n status:\n patch: off\n"
},
{
"path": ".github/dependabot.yml",
"chars": 547,
"preview": "version: 2\nupdates:\n - package-ecosystem: cargo\n directory: \"/rust\"\n schedule:\n interval: daily\n time: "
},
{
"path": ".github/workflows/dockercompose-validation.yml",
"chars": 398,
"preview": "name: docker-compose validation\n\non:\n push:\n paths:\n - 'docker/docker-compose*yml'\n\njobs:\n check-docker-compos"
},
{
"path": ".github/workflows/dockerfile-validation.yml",
"chars": 369,
"preview": "name: Dockerfiles linting\n\non:\n push:\n paths:\n - 'docker/Dockerfile**'\n\njobs:\n lint:\n name: Dockerfiles lin"
},
{
"path": ".github/workflows/dockerhub-cleanup.yml",
"chars": 2473,
"preview": "name: DockerHub Scheduled Cleanup\n\non:\n schedule:\n - cron: '00 00 * * sun'\n workflow_dispatch:\n\njobs:\n dockerhub-c"
},
{
"path": ".github/workflows/dockerhub-master.yml",
"chars": 1517,
"preview": "name: DockerHub (master)\n\non:\n push:\n branches:\n - master\n\njobs:\n build-tag-push-master:\n name: build-tag-p"
},
{
"path": ".github/workflows/dockerhub-pr-with-parameters.yml",
"chars": 2617,
"preview": "name: DockerHub (PR) with parameters\n\non:\n issue_comment:\n types: [created]\n\njobs:\n check_comments:\n name: Check"
},
{
"path": ".github/workflows/dockerhub-release.yml",
"chars": 1512,
"preview": "name: DockerHub (Release)\n\non:\n push:\n tags:\n - v[0-9]+.[0-9]+.[0-9]+\n\njobs:\n build-tag-push-release:\n name"
},
{
"path": ".github/workflows/kubernetes-manifests.yml",
"chars": 422,
"preview": "name: Kubernetes manifests validation\n\non:\n push:\n paths:\n - 'k8s/**'\n\njobs:\n k8s-kustomize-validation:\n na"
},
{
"path": ".github/workflows/rust-audit-cron.yml",
"chars": 1156,
"preview": "name: Rust Audit for Security Vulnerabilities (master)\n\non:\n schedule:\n - cron: '00 08 * * mon-fri'\n\njobs:\n audit:\n"
},
{
"path": ".github/workflows/rust-next.yml",
"chars": 6067,
"preview": "name: Rust-CI Next\n\non:\n schedule:\n - cron: '00 04 10,20 * *'\n\njobs:\n registry-cache:\n name: cargo-fetch\n tim"
},
{
"path": ".github/workflows/rust.yml",
"chars": 14596,
"preview": "name: Rust-CI\n\non:\n push:\n paths:\n - 'rust/**'\n - 'bindings/python/**'\n - '.github/workflows/rust.yml"
},
{
"path": ".gitignore",
"chars": 171,
"preview": "**/.ignore/\n\n# https://github.com/github/gitignore/blob/master/Global/macOS.gitignore\n# General\n**.DS_Store\n**.swp\n\n# vs"
},
{
"path": "CHANGELOG.md",
"chars": 16893,
"preview": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Change"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 11318,
"preview": "[](https://crates.io/crates/xaynet) [](https://crates.io/crates/xaynet) [\n\nIn Q1 we focus entirely on using XayNet for the [Xayn app] in te"
},
{
"path": "bindings/python/.gitignore",
"chars": 2062,
"preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
},
{
"path": "bindings/python/.isort.cfg",
"chars": 178,
"preview": "[settings]\ncombine_as_imports=True\nforce_grid_wrap=0\nforce_sort_within_sections=True\ninclude_trailing_comma=True\nindent="
},
{
"path": "bindings/python/.pylintrc",
"chars": 17141,
"preview": "[MASTER]\n\n# A comma-separated list of package or module names from where C extensions may\n# be loaded. Extensions are lo"
},
{
"path": "bindings/python/Cargo.toml",
"chars": 2260,
"preview": "[package]\nname = \"xaynet-sdk-python\"\nversion = \"0.1.0\"\nauthors = [\"Xayn Engineering <engineering@xaynet.dev>\"]\nedition ="
},
{
"path": "bindings/python/README.md",
"chars": 14915,
"preview": "\n\n## Installation\n\n**Prerequisites**\n\n- Python 3.6 or higher\n\n**1. Insta"
},
{
"path": "bindings/python/examples/README.md",
"chars": 1119,
"preview": "# Examples\n\nSome examples that show how the `ParticipantABC` or `AsyncParticipant` can be used.\n\n## Getting Started\n\nAll"
},
{
"path": "bindings/python/examples/download_global_model.py",
"chars": 1384,
"preview": "\"\"\"A `ParticipantABC` that only downloads the latest global model\"\"\"\n\nimport json\nimport logging\nfrom typing import Opti"
},
{
"path": "bindings/python/examples/download_global_model_async.py",
"chars": 880,
"preview": "\"\"\"An `AsyncParticipant` that only downloads the latest global model\"\"\"\n\nimport json\nimport logging\n\nimport xaynet_sdk\n\n"
},
{
"path": "bindings/python/examples/hello_world.py",
"chars": 1446,
"preview": "\"\"\"A basic `ParticipantABC` example\"\"\"\n\nimport json\nimport logging\nimport time\nfrom typing import Optional\n\nimport xayne"
},
{
"path": "bindings/python/examples/hello_world_async.py",
"chars": 845,
"preview": "\"\"\"A basic `AsyncParticipant` example\"\"\"\n\nimport logging\nimport time\n\nimport xaynet_sdk\n\nLOG = logging.getLogger(__name_"
},
{
"path": "bindings/python/examples/keras_house_prices/.gitignore",
"chars": 6,
"preview": "data/\n"
},
{
"path": "bindings/python/examples/keras_house_prices/README.md",
"chars": 1450,
"preview": "# `keras_house_prices` Example\n\n**Prerequisites**\n\n- Python >=3.7.1 <=3.8\n\n1. Adjust the coordinator settings\n\nChange th"
},
{
"path": "bindings/python/examples/keras_house_prices/keras_house_prices/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "bindings/python/examples/keras_house_prices/keras_house_prices/data_handlers/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "bindings/python/examples/keras_house_prices/keras_house_prices/data_handlers/data_handler.py",
"chars": 12360,
"preview": "\"\"\"DataHandler base class to read, preprocess and split data for each example.\"\"\"\n\nfrom abc import ABC, abstractmethod\ni"
},
{
"path": "bindings/python/examples/keras_house_prices/keras_house_prices/data_handlers/regression_data.py",
"chars": 5126,
"preview": "\"\"\"Implementation of the RegressionData subclass, to handle the data of regression examples.\"\"\"\n\nimport argparse\nimport "
},
{
"path": "bindings/python/examples/keras_house_prices/keras_house_prices/participant.py",
"chars": 4719,
"preview": "\"\"\"Tensorflow Keras regression test case\"\"\"\n\nimport argparse\nimport logging\nimport os\nimport random\nfrom typing import L"
},
{
"path": "bindings/python/examples/keras_house_prices/keras_house_prices/regressor.py",
"chars": 2776,
"preview": "\"\"\"Wrapper for tensorflow regression neural network.\"\"\"\nfrom typing import List, Tuple\n\nimport numpy as np\nimport pandas"
},
{
"path": "bindings/python/examples/keras_house_prices/setup.py",
"chars": 708,
"preview": "# pylint: disable=invalid-name\nfrom setuptools import find_packages, setup\n\nsetup(\n name=\"keras_house_prices\",\n ve"
},
{
"path": "bindings/python/examples/multiple_participants.py",
"chars": 2113,
"preview": "\"\"\"Spawn multiple `ParticipantABC`s in a single process\"\"\"\n\nimport json\nimport logging\nimport time\nfrom typing import Op"
},
{
"path": "bindings/python/examples/participate_in_update.py",
"chars": 1723,
"preview": "\"\"\"Only train a model when there is enough battery left\"\"\"\n\nimport json\nimport logging\nfrom random import randint\nimport"
},
{
"path": "bindings/python/examples/restore.py",
"chars": 845,
"preview": "\"\"\"Save and restore the state of an `AsyncParticipant`\"\"\"\n\nimport json\nimport logging\n\nimport xaynet_sdk\n\nLOG = logging."
},
{
"path": "bindings/python/migration_guide.md",
"chars": 3977,
"preview": "# Migration from `v0.8.0` to `v.0.11.0`\n\nTo demonstrate the API changes from `v0.8.0` to `v.0.11.0`, we will use the ker"
},
{
"path": "bindings/python/src/lib.rs",
"chars": 20,
"preview": "pub mod python_ffi;\n"
},
{
"path": "bindings/python/src/python_ffi.rs",
"chars": 10276,
"preview": "use pyo3::create_exception;\nuse pyo3::exceptions::PyException;\nuse pyo3::types::PyList;\nuse pyo3::{prelude::*, wrap_pyfu"
},
{
"path": "bindings/python/xaynet_sdk/__init__.py",
"chars": 4049,
"preview": "import threading\nfrom typing import List, Optional, Tuple\n\nfrom .async_participant import *\nfrom .participant import *\n\n"
},
{
"path": "bindings/python/xaynet_sdk/async_participant.py",
"chars": 5449,
"preview": "import logging\nimport threading\nfrom typing import List, Optional\n\nfrom justbackoff import Backoff\n\nfrom xaynet_sdk impo"
},
{
"path": "bindings/python/xaynet_sdk/participant.py",
"chars": 8698,
"preview": "from abc import ABC, abstractmethod\nimport logging\nimport threading\nfrom typing import List, Optional, TypeVar\n\nfrom jus"
},
{
"path": "configs/config.toml",
"chars": 777,
"preview": "[log]\nfilter = \"xaynet=debug,http=warn,info\"\n\n[api]\nbind_address = \"127.0.0.1:8081\"\ntls_certificate = \"/app/ssl/tls.pem\""
},
{
"path": "configs/docker-dev.toml",
"chars": 766,
"preview": "[log]\nfilter = \"xaynet=debug,http=warn,info\"\n\n[api]\nbind_address = \"0.0.0.0:8081\"\ntls_certificate = \"/app/ssl/tls.pem\"\nt"
},
{
"path": "docker/.dev.env",
"chars": 49,
"preview": "MINIO_ACCESS_KEY=minio\nMINIO_SECRET_KEY=minio123\n"
},
{
"path": "docker/Dockerfile",
"chars": 1562,
"preview": "FROM buildpack-deps:stable-curl AS builder\n\nRUN apt update\n\n# Install Rust\nENV RUSTUP_HOME=/usr/local/rustup \\\n CARGO"
},
{
"path": "docker/docker-compose.yml",
"chars": 1445,
"preview": "version: \"3.8\"\nservices:\n coordinator:\n image: xaynetwork/xaynet:development\n build:\n context: ..\n dock"
},
{
"path": "k8s/coordinator/base/deployment.yaml",
"chars": 1055,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: coordinator-deployment\nspec:\n selector:\n matchLabels:\n a"
},
{
"path": "k8s/coordinator/base/kustomization.yaml",
"chars": 237,
"preview": "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\n\ncommonLabels:\n app.kubernetes.io/component: backend\n "
},
{
"path": "k8s/coordinator/base/service.yaml",
"chars": 195,
"preview": "apiVersion: v1\nkind: Service\nmetadata:\n name: coordinator-service\nspec:\n type: ClusterIP\n ports:\n - port: 8081\n "
},
{
"path": "k8s/coordinator/development/cert-volume-mount.yaml",
"chars": 574,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: coordinator-deployment\nspec:\n template:\n spec:\n volumes:"
},
{
"path": "k8s/coordinator/development/config-volume-mount.yaml",
"chars": 457,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: coordinator-deployment\nspec:\n template:\n spec:\n volumes:"
},
{
"path": "k8s/coordinator/development/config.toml",
"chars": 1105,
"preview": "[log]\nfilter = \"xaynet=debug,http=warn,info\"\n\n[api]\nbind_address = \"0.0.0.0:8081\"\ntls_certificate = \"/app/ssl/tls.pem\"\nt"
},
{
"path": "k8s/coordinator/development/history-limit.yaml",
"chars": 110,
"preview": "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: coordinator-deployment\nspec:\n revisionHistoryLimit: 0\n"
},
{
"path": "k8s/coordinator/development/ingress.yaml",
"chars": 585,
"preview": "apiVersion: networking.k8s.io/v1\r\nkind: Ingress\r\nmetadata:\r\n name: coordinator-ingress\r\n annotations:\r\n kubernetes."
},
{
"path": "k8s/coordinator/development/kustomization.yaml",
"chars": 392,
"preview": "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\n\nnamespace: xaynet\n\nimages:\n - name: coordinator\n ne"
},
{
"path": "rust/.gitignore",
"chars": 212,
"preview": "# https://github.com/github/gitignore/blob/master/Rust.gitignore\n# Generated by Cargo\n# will have compiled files and exe"
},
{
"path": "rust/Cargo.toml",
"chars": 264,
"preview": "[workspace]\nmembers = [\n \"xaynet\",\n # \"xaynet-analytics\",\n \"xaynet-core\",\n \"xaynet-mobile\",\n \"xaynet-serv"
},
{
"path": "rust/benches/Cargo.toml",
"chars": 1190,
"preview": "[package]\nname = \"benches\"\nversion = \"0.0.0\"\nauthors = [\"Xayn Engineering <engineering@xaynet.dev>\"]\nedition = \"2018\"\nde"
},
{
"path": "rust/benches/messages/sum.rs",
"chars": 2646,
"preview": "use std::time::Duration;\n\nuse criterion::{black_box, criterion_group, criterion_main, Criterion};\n\nuse xaynet_core::{\n "
},
{
"path": "rust/benches/messages/update.rs",
"chars": 3052,
"preview": "use criterion::{black_box, criterion_group, criterion_main, Criterion};\nuse paste::paste;\n\nuse xaynet_core::{\n messag"
},
{
"path": "rust/benches/models/from_primitives.rs",
"chars": 1470,
"preview": "use std::time::Duration;\n\nuse criterion::{black_box, criterion_group, criterion_main, Criterion};\nuse paste::paste;\n\nuse"
},
{
"path": "rust/benches/models/to_primitives.rs",
"chars": 1529,
"preview": "use std::{iter, time::Duration};\n\nuse criterion::{black_box, criterion_group, criterion_main, Criterion};\nuse num::{bigi"
},
{
"path": "rust/examples/Cargo.toml",
"chars": 1337,
"preview": "[package]\nname = \"examples\"\nversion = \"0.0.0\"\nauthors = [\"Xayn Engineering <engineering@xaynet.dev>\"]\nedition = \"2018\"\nd"
},
{
"path": "rust/examples/test-drive/main.rs",
"chars": 2590,
"preview": "use std::{fs::File, io::Read, sync::Arc, time::Duration};\n\nuse structopt::StructOpt;\nuse tracing::error_span;\nuse tracin"
},
{
"path": "rust/examples/test-drive/participant.rs",
"chars": 4004,
"preview": "use std::{sync::Arc, time::Duration};\n\nuse async_trait::async_trait;\nuse tokio::{sync::mpsc, time::sleep};\nuse tracing::"
},
{
"path": "rust/examples/test-drive/settings.rs",
"chars": 1010,
"preview": "use std::path::PathBuf;\n\nuse structopt::StructOpt;\n\n#[derive(Debug, StructOpt)]\n#[structopt(name = \"Test Drive\")]\npub st"
},
{
"path": "rust/rustfmt.toml",
"chars": 163,
"preview": "# requires nightly rustfmt until the options are stabilized\nformat_code_in_doc_comments = true\nimports_granularity = \"Cr"
},
{
"path": "rust/xaynet/Cargo.toml",
"chars": 1390,
"preview": "[package]\nname = \"xaynet\"\nversion = \"0.11.0\"\nauthors = [\"Xayn Engineering <engineering@xaynet.dev>\"]\nedition = \"2018\"\nde"
},
{
"path": "rust/xaynet/src/lib.rs",
"chars": 5865,
"preview": "#![cfg_attr(docsrs, feature(doc_cfg))]\n#![cfg_attr(\n doc,\n forbid(rustdoc::broken_intra_doc_links, rustdoc::privat"
},
{
"path": "rust/xaynet-analytics/Cargo.toml",
"chars": 925,
"preview": "[package]\nname = \"xaynet-analytics\"\nversion = \"0.1.0\"\nauthors = [\"Xayn Engineering <engineering@xaynet.dev>\"]\nedition = "
},
{
"path": "rust/xaynet-analytics/src/controller.rs",
"chars": 25200,
"preview": "//! In this file the `AnalyticsController` is defined.\n\nuse anyhow::{anyhow, Error, Result};\nuse chrono::{DateTime, Date"
},
{
"path": "rust/xaynet-analytics/src/data_combination/data_combiner.rs",
"chars": 17715,
"preview": "//! Declaration and implementation of `DataCombiner`.\n\nuse anyhow::{Error, Result};\nuse chrono::{DateTime, Datelike, Dur"
},
{
"path": "rust/xaynet-analytics/src/data_combination/data_points/data_point.rs",
"chars": 3730,
"preview": "//! File containing various structs used to define `DataPoints`.\n\nuse chrono::{DateTime, Utc};\n\nuse crate::database::ana"
},
{
"path": "rust/xaynet-analytics/src/data_combination/data_points/mod.rs",
"chars": 145,
"preview": "pub mod data_point;\npub mod screen_active_time;\npub mod screen_enter_count;\npub mod was_active_each_past_period;\npub mod"
},
{
"path": "rust/xaynet-analytics/src/data_combination/data_points/screen_active_time.rs",
"chars": 7568,
"preview": "use chrono::Duration;\n\nuse crate::{\n data_combination::data_points::data_point::{\n CalcScreenActiveTime,\n "
},
{
"path": "rust/xaynet-analytics/src/data_combination/data_points/screen_enter_count.rs",
"chars": 3013,
"preview": "use crate::{\n data_combination::data_points::data_point::{\n CalcScreenEnterCount,\n CalculateDataPoints,"
},
{
"path": "rust/xaynet-analytics/src/data_combination/data_points/was_active_each_past_period.rs",
"chars": 7608,
"preview": "use chrono::{DateTime, Utc};\nuse std::collections::BTreeMap;\n\nuse crate::{\n data_combination::data_points::data_point"
},
{
"path": "rust/xaynet-analytics/src/data_combination/data_points/was_active_past_n_days.rs",
"chars": 1633,
"preview": "use crate::{\n data_combination::data_points::data_point::{\n CalcWasActivePastNDays,\n CalculateDataPoint"
},
{
"path": "rust/xaynet-analytics/src/data_combination/mod.rs",
"chars": 44,
"preview": "pub mod data_combiner;\npub mod data_points;\n"
},
{
"path": "rust/xaynet-analytics/src/database/analytics_event/adapter.rs",
"chars": 4817,
"preview": "//! This file contains struct and impls for `AnalyticsEventAdapter` and `AnalyticsEventRelationalAdapter`,\n//! as well a"
},
{
"path": "rust/xaynet-analytics/src/database/analytics_event/data_model.rs",
"chars": 8028,
"preview": "//! In this file `AnalyticsEvent` and `AnalyticsEventType` are declared, together with some conversion methods to/from a"
},
{
"path": "rust/xaynet-analytics/src/database/analytics_event/mod.rs",
"chars": 51,
"preview": "pub mod adapter;\npub mod data_model;\npub mod repo;\n"
},
{
"path": "rust/xaynet-analytics/src/database/analytics_event/repo.rs",
"chars": 2485,
"preview": "//! Implementations of the methods needed to save and get `AnalyticsEvents` to/from Isar.\n\nuse anyhow::{anyhow, Error, R"
},
{
"path": "rust/xaynet-analytics/src/database/common.rs",
"chars": 6106,
"preview": "//! This file contains traits and structs that are common to other components involved with the database.\n//! It could b"
},
{
"path": "rust/xaynet-analytics/src/database/controller_data/adapter.rs",
"chars": 1951,
"preview": "//! This file contains struct and impl for `ControllerDataAdapter` the implementation of `IsarAdapter`\n//! for `Controll"
},
{
"path": "rust/xaynet-analytics/src/database/controller_data/data_model.rs",
"chars": 2199,
"preview": "//! In this file `ControllerData` is declared, together with some conversion methods to/from adapters.\n\nuse anyhow::Resu"
},
{
"path": "rust/xaynet-analytics/src/database/controller_data/mod.rs",
"chars": 51,
"preview": "pub mod adapter;\npub mod data_model;\npub mod repo;\n"
},
{
"path": "rust/xaynet-analytics/src/database/controller_data/repo.rs",
"chars": 1973,
"preview": "//! Implementations of the methods needed to save and get `ControllerData` to/from Isar.\n\nuse anyhow::{anyhow, Error, Re"
},
{
"path": "rust/xaynet-analytics/src/database/isar.rs",
"chars": 5563,
"preview": "//! `IsarDb` is an internal abstraction on top of Isar that wraps `IsarInstance`, the main singleton from Isar.\n\nuse any"
},
{
"path": "rust/xaynet-analytics/src/database/mod.rs",
"chars": 102,
"preview": "pub mod analytics_event;\npub mod common;\npub mod controller_data;\npub mod isar;\npub mod screen_route;\n"
},
{
"path": "rust/xaynet-analytics/src/database/screen_route/adapter.rs",
"chars": 2337,
"preview": "//! This file contains struct and impl for `ScreenRouteAdapter` the implementation of `IsarAdapter`\n//! for `ScreenRoute"
},
{
"path": "rust/xaynet-analytics/src/database/screen_route/data_model.rs",
"chars": 3035,
"preview": "//! In this file `ScreenRoute` is declared, together with some conversion methods to/from adapters.\n\nuse anyhow::Result;"
},
{
"path": "rust/xaynet-analytics/src/database/screen_route/mod.rs",
"chars": 51,
"preview": "pub mod adapter;\npub mod data_model;\npub mod repo;\n"
},
{
"path": "rust/xaynet-analytics/src/database/screen_route/repo.rs",
"chars": 1972,
"preview": "//! Implementations of the methods needed to save and get ScreenRoute to/from Isar.\n\nuse anyhow::{anyhow, Error, Result}"
},
{
"path": "rust/xaynet-analytics/src/lib.rs",
"chars": 760,
"preview": "#![cfg_attr(doc, forbid(broken_intra_doc_links, private_intra_doc_links))]\n#![doc(\n html_logo_url = \"https://raw.gith"
},
{
"path": "rust/xaynet-analytics/src/sender.rs",
"chars": 900,
"preview": "//! In this file `Sender` is just stubbed and will need to be implemented.\n\nuse anyhow::{Error, Result};\n\nuse crate::dat"
},
{
"path": "rust/xaynet-core/Cargo.toml",
"chars": 1222,
"preview": "[package]\nname = \"xaynet-core\"\nversion = \"0.2.0\"\nauthors = [\"Xayn Engineering <engineering@xaynet.dev>\"]\nedition = \"2018"
},
{
"path": "rust/xaynet-core/src/common.rs",
"chars": 1401,
"preview": "use serde::{Deserialize, Serialize};\nuse sodiumoxide::{self, crypto::box_};\n\nuse crate::{crypto::ByteObject, mask::MaskC"
},
{
"path": "rust/xaynet-core/src/crypto/encrypt.rs",
"chars": 4793,
"preview": "//! Wrappers around some of the [sodiumoxide] encryption primitives.\n//!\n//! See the [crypto module] documentation since"
},
{
"path": "rust/xaynet-core/src/crypto/hash.rs",
"chars": 1107,
"preview": "//! Wrappers around some of the [sodiumoxide] hashing primitives.\n//!\n//! See the [crypto module] documentation since th"
},
{
"path": "rust/xaynet-core/src/crypto/mod.rs",
"chars": 2673,
"preview": "//! Wrappers around some of the [sodiumoxide] crypto primitives.\n//!\n//! The wrappers provide methods defined on structs"
},
{
"path": "rust/xaynet-core/src/crypto/prng.rs",
"chars": 2550,
"preview": "//! PRNG utilities for the crypto primitives.\n//!\n//! See the [crypto module] documentation since this is a private modu"
},
{
"path": "rust/xaynet-core/src/crypto/sign.rs",
"chars": 7545,
"preview": "//! Wrappers around some of the [sodiumoxide] signing primitives.\n//!\n//! See the [crypto module] documentation since th"
},
{
"path": "rust/xaynet-core/src/lib.rs",
"chars": 3890,
"preview": "#![cfg_attr(docsrs, feature(doc_cfg))]\n#![cfg_attr(\n doc,\n forbid(rustdoc::broken_intra_doc_links, rustdoc::privat"
},
{
"path": "rust/xaynet-core/src/mask/config/mod.rs",
"chars": 40509,
"preview": "//! Masking configuration parameters.\n//!\n//! See the [mask module] documentation since this is a private module anyways"
},
{
"path": "rust/xaynet-core/src/mask/config/serialization.rs",
"chars": 6537,
"preview": "//! Serialization of masking configurations.\n//!\n//! See the [mask module] documentation since this is a private module "
},
{
"path": "rust/xaynet-core/src/mask/masking.rs",
"chars": 52212,
"preview": "//! Masking, aggregation and unmasking of models.\n//!\n//! See the [mask module] documentation since this is a private mo"
},
{
"path": "rust/xaynet-core/src/mask/mod.rs",
"chars": 11959,
"preview": "//! Masking, aggregation and unmasking of models.\n//!\n//! # Models\n//! A [`Model`] is a collection of weights/parameters"
},
{
"path": "rust/xaynet-core/src/mask/model.rs",
"chars": 16186,
"preview": "//! Model representation and conversion.\n//!\n//! See the [mask module] documentation since this is a private module anyw"
},
{
"path": "rust/xaynet-core/src/mask/object/mod.rs",
"chars": 4735,
"preview": "//! Masked objects.\n//!\n//! See the [mask module] documentation since this is a private module anyways.\n//!\n//! [mask mo"
},
{
"path": "rust/xaynet-core/src/mask/object/serialization/mod.rs",
"chars": 6059,
"preview": "//! Serialization of masked objects.\n//!\n//! See the [mask module] documentation since this is a private module anyways."
},
{
"path": "rust/xaynet-core/src/mask/object/serialization/unit.rs",
"chars": 7083,
"preview": "//! Serialization of masked units.\n//!\n//! See the [mask module] documentation since this is a private module anyways.\n/"
},
{
"path": "rust/xaynet-core/src/mask/object/serialization/vect.rs",
"chars": 9736,
"preview": "//! Serialization of masked vectors.\n//!\n//! See the [mask module] documentation since this is a private module anyways."
},
{
"path": "rust/xaynet-core/src/mask/scalar.rs",
"chars": 12031,
"preview": "//! Scalar representation and conversion.\n//!\n//! See the [mask module] documentation since this is a private module any"
},
{
"path": "rust/xaynet-core/src/mask/seed.rs",
"chars": 5386,
"preview": "//! Mask seed and mask generation.\n//!\n//! See the [mask module] documentation since this is a private module anyways.\n/"
},
{
"path": "rust/xaynet-core/src/message/message.rs",
"chars": 26724,
"preview": "//! Message buffers.\n//!\n//! See the [message module] documentation since this is a private module anyways.\n//!\n//! [mes"
},
{
"path": "rust/xaynet-core/src/message/mod.rs",
"chars": 2425,
"preview": "//! The messages of the PET protocol.\n//!\n//! # The sum message\n//! The [`Sum`] message is an abstraction for the values"
},
{
"path": "rust/xaynet-core/src/message/payload/chunk.rs",
"chars": 9435,
"preview": "use std::convert::TryInto;\n\nuse anyhow::{anyhow, Context};\n\nuse crate::message::{\n traits::{FromBytes, ToBytes},\n "
},
{
"path": "rust/xaynet-core/src/message/payload/mod.rs",
"chars": 1740,
"preview": "//! Message payloads.\n//!\n//! See the [message module] documentation since this is a private module anyways.\n//!\n//! [me"
},
{
"path": "rust/xaynet-core/src/message/payload/sum.rs",
"chars": 9071,
"preview": "//! Sum message payloads.\n//!\n//! See the [message module] documentation since this is a private module anyways.\n//!\n//!"
},
{
"path": "rust/xaynet-core/src/message/payload/sum2.rs",
"chars": 6965,
"preview": "//! Sum2 message payloads.\n//!\n//! See the [message module] documentation since this is a private module anyways.\n//!\n//"
},
{
"path": "rust/xaynet-core/src/message/payload/update.rs",
"chars": 11333,
"preview": "//! Update message payloads.\n//!\n//! See the [message module] documentation since this is a private module anyways.\n//!\n"
},
{
"path": "rust/xaynet-core/src/message/traits.rs",
"chars": 15394,
"preview": "//! Message traits.\n//!\n//! See the [message module] documentation since this is a private module anyways.\n//!\n//! [mess"
},
{
"path": "rust/xaynet-core/src/message/utils/chunkable_iterator.rs",
"chars": 13589,
"preview": "//! This module provides an extension to the [`Iterator`] trait that allows iterating by chunks. One\n//! important prope"
},
{
"path": "rust/xaynet-core/src/message/utils/mod.rs",
"chars": 432,
"preview": "//! Message utilities.\n//!\n//! See the [message module] documentation since this is a private module anyways.\n//!\n//! [m"
},
{
"path": "rust/xaynet-core/src/testutils/messages.rs",
"chars": 8628,
"preview": "//! This module provides helpers for generating messages or messages\n//! parts such as signatures, cryptographic keys, o"
},
{
"path": "rust/xaynet-core/src/testutils/mod.rs",
"chars": 37,
"preview": "pub mod messages;\npub mod multipart;\n"
},
{
"path": "rust/xaynet-core/src/testutils/multipart.rs",
"chars": 4820,
"preview": "use num::BigUint;\n\nuse crate::{\n crypto::{ByteObject, PublicSigningKey, Signature},\n mask::{\n BoundType,\n "
},
{
"path": "rust/xaynet-mobile/.cargo/config.toml",
"chars": 164,
"preview": "# These reduces the size of the libraries a lot!\n# See: https://github.com/johnthagen/min-sized-rust\n[profile.release]\nl"
},
{
"path": "rust/xaynet-mobile/.gitignore",
"chars": 65,
"preview": "ffi_test.o.dSYM\nffi_test.o\ntest_participant_save_and_restore.txt\n"
},
{
"path": "rust/xaynet-mobile/Cargo.toml",
"chars": 1316,
"preview": "[package]\nname = \"xaynet-mobile\"\nversion = \"0.1.0\"\nauthors = [\"Xayn Engineering <engineering@xaynet.dev>\"]\nedition = \"20"
},
{
"path": "rust/xaynet-mobile/README.md",
"chars": 624,
"preview": "# Xaynet FFI\n\n## Generate C-Header File\n\nTo generate the header files, run `cargo build`.\n\n\n## Run tests\n\n### macOS\n\n```"
},
{
"path": "rust/xaynet-mobile/build.rs",
"chars": 1265,
"preview": "use std::{\n env,\n fs::read_dir,\n path::{Path, PathBuf},\n};\n\nuse cbindgen::{generate_with_config, Config};\n\n// c"
},
{
"path": "rust/xaynet-mobile/cbindgen.toml",
"chars": 395,
"preview": "language = \"C\"\nautogen_warning = \"/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */\"\nin"
},
{
"path": "rust/xaynet-mobile/src/ffi/config.rs",
"chars": 2739,
"preview": "use crate::ffi::{ERR_NULLPTR, OK};\nuse std::os::raw::c_int;\nuse xaynet_core::mask::DataType;\n\nmod pv {\n use super::Lo"
},
{
"path": "rust/xaynet-mobile/src/ffi/mod.rs",
"chars": 3808,
"preview": "#![allow(unused_unsafe)]\n\nmod participant;\npub use participant::*;\n\nmod settings;\npub use settings::*;\n\nmod config;\npub "
},
{
"path": "rust/xaynet-mobile/src/ffi/participant.rs",
"chars": 17849,
"preview": "use std::{\n convert::TryFrom,\n os::raw::{c_int, c_uchar, c_uint, c_void},\n ptr,\n slice,\n};\n\nuse ffi_support:"
},
{
"path": "rust/xaynet-mobile/src/ffi/settings.rs",
"chars": 9388,
"preview": "use std::os::raw::{c_double, c_int};\n\nuse ffi_support::{ByteBuffer, FfiStr};\nuse xaynet_core::crypto::{ByteObject, Publi"
},
{
"path": "rust/xaynet-mobile/src/lib.rs",
"chars": 2481,
"preview": "#![cfg_attr(\n doc,\n forbid(rustdoc::broken_intra_doc_links, rustdoc::private_intra_doc_links)\n)]\n#![doc(\n html_"
},
{
"path": "rust/xaynet-mobile/src/participant.rs",
"chars": 12198,
"preview": "//! Participant implementation\nuse std::{convert::TryInto, sync::Arc};\n\nuse futures::future::FutureExt;\nuse thiserror::E"
},
{
"path": "rust/xaynet-mobile/src/reqwest_client.rs",
"chars": 2723,
"preview": "use std::{fs::File, io::Read};\n\nuse thiserror::Error;\n\nuse xaynet_sdk::client::Client;\n\n/// Error returned upon failing "
},
{
"path": "rust/xaynet-mobile/src/settings.rs",
"chars": 3031,
"preview": "//! This module provides utilities to configure a [`Participant`].\n//!\n//! [`Participant`]: crate::Participant\n\nuse std:"
},
{
"path": "rust/xaynet-mobile/tests/ffi_test.c",
"chars": 6322,
"preview": "#include <assert.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"minunit.h\""
},
{
"path": "rust/xaynet-mobile/tests/minunit.h",
"chars": 623,
"preview": "#define RESET \"\\033[0m\"\n#define BLACK \"\\033[30m\" /* Black */\n#define RED \"\\033[31m\" /* Red */\n#define "
},
{
"path": "rust/xaynet-mobile/xaynet_ffi.h",
"chars": 28415,
"preview": "/* Generated with cbindgen:0.17.0 */\n\n/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
},
{
"path": "rust/xaynet-sdk/Cargo.toml",
"chars": 1878,
"preview": "[package]\nname = \"xaynet-sdk\"\nversion = \"0.1.0\"\nauthors = [\"Xayn Engineering <engineering@xaynet.dev>\"]\nedition = \"2018\""
},
{
"path": "rust/xaynet-sdk/src/client.rs",
"chars": 6338,
"preview": "use async_trait::async_trait;\nuse thiserror::Error;\nuse url::Url;\n\nuse crate::XaynetClient;\nuse xaynet_core::{\n commo"
},
{
"path": "rust/xaynet-sdk/src/lib.rs",
"chars": 8165,
"preview": "#![cfg_attr(docsrs, feature(doc_cfg))]\n#![cfg_attr(\n doc,\n forbid(rustdoc::broken_intra_doc_links, rustdoc::privat"
},
{
"path": "rust/xaynet-sdk/src/message_encoder/chunker.rs",
"chars": 4154,
"preview": "#![allow(dead_code)]\n\nuse std::cmp;\n\n/// Default chunk size, for [`Chunker`]\npub const DEFAULT_CHUNK_SIZE: usize = 4096;"
},
{
"path": "rust/xaynet-sdk/src/message_encoder/encoder.rs",
"chars": 10372,
"preview": "use serde::{Deserialize, Serialize};\nuse thiserror::Error;\n\nuse super::Chunker;\nuse xaynet_core::{\n crypto::{PublicEn"
},
{
"path": "rust/xaynet-sdk/src/message_encoder/mod.rs",
"chars": 82,
"preview": "mod chunker;\nmod encoder;\n\nuse chunker::Chunker;\npub use encoder::MessageEncoder;\n"
},
{
"path": "rust/xaynet-sdk/src/settings/max_message_size.rs",
"chars": 4506,
"preview": "use serde::{de::Error as SerdeError, Deserialize, Deserializer, Serialize};\nuse thiserror::Error;\n\npub use xaynet_core::"
},
{
"path": "rust/xaynet-sdk/src/settings/mod.rs",
"chars": 586,
"preview": "mod max_message_size;\n\nuse serde::{Deserialize, Serialize};\n\npub use max_message_size::{InvalidMaxMessageSize, MaxMessag"
},
{
"path": "rust/xaynet-sdk/src/state_machine/io.rs",
"chars": 6933,
"preview": "use std::error::Error;\n\nuse async_trait::async_trait;\n\nuse xaynet_core::{\n common::RoundParameters,\n mask::Model,\n"
},
{
"path": "rust/xaynet-sdk/src/state_machine/mod.rs",
"chars": 773,
"preview": "// Important the macro_use modules must be declared first for the\n// macro to be used in the other modules (until declar"
},
{
"path": "rust/xaynet-sdk/src/state_machine/phase.rs",
"chars": 11484,
"preview": "use async_trait::async_trait;\nuse derive_more::From;\nuse serde::{Deserialize, Serialize};\nuse thiserror::Error;\nuse trac"
},
{
"path": "rust/xaynet-sdk/src/state_machine/phases/awaiting.rs",
"chars": 602,
"preview": "use async_trait::async_trait;\nuse serde::{Deserialize, Serialize};\nuse tracing::info;\n\nuse crate::state_machine::{IntoPh"
},
{
"path": "rust/xaynet-sdk/src/state_machine/phases/mod.rs",
"chars": 247,
"preview": "mod awaiting;\nmod new_round;\nmod sending;\nmod sum;\nmod sum2;\nmod update;\n\npub use self::{\n awaiting::Awaiting,\n ne"
},
{
"path": "rust/xaynet-sdk/src/state_machine/phases/new_round.rs",
"chars": 2514,
"preview": "use async_trait::async_trait;\nuse serde::{Deserialize, Serialize};\nuse tracing::info;\nuse xaynet_core::crypto::{ByteObje"
},
{
"path": "rust/xaynet-sdk/src/state_machine/phases/sending.rs",
"chars": 4634,
"preview": "use async_trait::async_trait;\nuse paste::paste;\nuse serde::{Deserialize, Serialize};\nuse tracing::{debug, error, info};\n"
},
{
"path": "rust/xaynet-sdk/src/state_machine/phases/sum.rs",
"chars": 2296,
"preview": "use async_trait::async_trait;\nuse serde::{Deserialize, Serialize};\nuse tracing::{debug, info};\n\nuse crate::{\n state_m"
},
{
"path": "rust/xaynet-sdk/src/state_machine/phases/sum2.rs",
"chars": 6828,
"preview": "use async_trait::async_trait;\nuse serde::{Deserialize, Serialize};\nuse tracing::{debug, error, info, warn};\nuse xaynet_c"
},
{
"path": "rust/xaynet-sdk/src/state_machine/phases/update.rs",
"chars": 8163,
"preview": "use std::ops::Deref;\n\nuse async_trait::async_trait;\nuse derive_more::From;\nuse serde::{Deserialize, Serialize};\nuse trac"
},
{
"path": "rust/xaynet-sdk/src/state_machine/state_machine.rs",
"chars": 5618,
"preview": "use derive_more::From;\n\nuse super::{\n boxed_io,\n Awaiting,\n IntoPhase,\n LocalModelConfig,\n NewRound,\n "
},
{
"path": "rust/xaynet-sdk/src/state_machine/tests/mod.rs",
"chars": 27,
"preview": "mod phases;\npub mod utils;\n"
},
{
"path": "rust/xaynet-sdk/src/state_machine/tests/phases/mod.rs",
"chars": 46,
"preview": "mod new_round;\nmod sum;\nmod sum2;\nmod update;\n"
},
{
"path": "rust/xaynet-sdk/src/state_machine/tests/phases/new_round.rs",
"chars": 2119,
"preview": "use crate::{\n state_machine::{\n tests::utils::{shared_state, SelectFor},\n IntoPhase,\n MockIO,\n "
},
{
"path": "rust/xaynet-sdk/src/state_machine/tests/phases/sum.rs",
"chars": 1490,
"preview": "use thiserror::Error;\nuse xaynet_core::crypto::{ByteObject, EncryptKeyPair, EncryptKeySeed};\n\nuse crate::{\n state_mac"
},
{
"path": "rust/xaynet-sdk/src/state_machine/tests/phases/sum2.rs",
"chars": 4167,
"preview": "use mockall::Sequence;\nuse xaynet_core::{\n crypto::{ByteObject, EncryptKeyPair, EncryptKeySeed, PublicEncryptKey},\n "
},
{
"path": "rust/xaynet-sdk/src/state_machine/tests/phases/update.rs",
"chars": 6040,
"preview": "use mockall::Sequence;\nuse xaynet_core::{\n crypto::ByteObject,\n mask::{FromPrimitives, Model},\n SumDict,\n};\n\nus"
},
{
"path": "rust/xaynet-sdk/src/state_machine/tests/utils.rs",
"chars": 6143,
"preview": "use xaynet_core::{\n common::{RoundParameters, RoundSeed},\n crypto::{ByteObject, EncryptKeyPair, EncryptKeySeed, Si"
},
{
"path": "rust/xaynet-sdk/src/traits.rs",
"chars": 2443,
"preview": "use async_trait::async_trait;\n\nuse xaynet_core::{\n common::RoundParameters,\n mask::Model,\n SumDict,\n SumPart"
},
{
"path": "rust/xaynet-sdk/src/utils/concurrent_futures.rs",
"chars": 3792,
"preview": "#![allow(dead_code)]\n\nuse std::{\n collections::VecDeque,\n pin::Pin,\n task::{Context, Poll},\n};\n\nuse futures::{\n"
},
{
"path": "rust/xaynet-sdk/src/utils/mod.rs",
"chars": 61,
"preview": "// TODO: move to the e2e package\npub mod concurrent_futures;\n"
},
{
"path": "rust/xaynet-server/Cargo.toml",
"chars": 2805,
"preview": "[package]\nname = \"xaynet-server\"\nversion = \"0.2.0\"\nauthors = [\"Xayn Engineering <engineering@xaynet.dev>\"]\nedition = \"20"
},
{
"path": "rust/xaynet-server/src/bin/main.rs",
"chars": 3908,
"preview": "use std::{path::PathBuf, process};\n\nuse structopt::StructOpt;\nuse tokio::signal;\nuse tracing::warn;\nuse tracing_subscrib"
},
{
"path": "rust/xaynet-server/src/examples.rs",
"chars": 7322,
"preview": "/*!\nA guide to getting started with the XayNet examples.\n\n# Examples\n\nThe XayNet examples code can be found under the `r"
},
{
"path": "rust/xaynet-server/src/lib.rs",
"chars": 917,
"preview": "#![cfg_attr(docsrs, feature(doc_cfg))]\n#![cfg_attr(\n doc,\n forbid(rustdoc::broken_intra_doc_links, rustdoc::privat"
},
{
"path": "rust/xaynet-server/src/metrics/mod.rs",
"chars": 2887,
"preview": "//! Utils to record metrics.\n\npub mod recorders;\n\nuse once_cell::sync::OnceCell;\n\npub use self::recorders::influxdb::{Me"
},
{
"path": "rust/xaynet-server/src/metrics/recorders/influxdb/dispatcher.rs",
"chars": 3124,
"preview": "use super::models::{Event, Metric};\nuse derive_more::From;\nuse futures::future::BoxFuture;\nuse influxdb::{Client as Infl"
},
{
"path": "rust/xaynet-server/src/metrics/recorders/influxdb/mod.rs",
"chars": 268,
"preview": "mod dispatcher;\nmod models;\nmod recorder;\nmod service;\n\npub(in crate::metrics) use self::{\n dispatcher::{Dispatcher, "
},
{
"path": "rust/xaynet-server/src/metrics/recorders/influxdb/models.rs",
"chars": 7708,
"preview": "use std::{borrow::Borrow, iter::IntoIterator};\n\nuse chrono::{DateTime, Utc};\nuse influxdb::{InfluxDbWriteable, Timestamp"
},
{
"path": "rust/xaynet-server/src/metrics/recorders/influxdb/recorder.rs",
"chars": 1945,
"preview": "use std::borrow::Borrow;\n\nuse futures::future::poll_fn;\nuse influxdb::Type;\nuse tower::Service;\nuse tracing::{error, war"
},
{
"path": "rust/xaynet-server/src/metrics/recorders/influxdb/service.rs",
"chars": 508,
"preview": "use super::{Dispatcher, Request};\nuse tower::{buffer::Buffer, limit::ConcurrencyLimit, load_shed::LoadShed, ServiceBuild"
},
{
"path": "rust/xaynet-server/src/metrics/recorders/mod.rs",
"chars": 18,
"preview": "pub mod influxdb;\n"
},
{
"path": "rust/xaynet-server/src/rest.rs",
"chars": 9751,
"preview": "//! A HTTP API for the PET protocol interactions.\n\nuse std::convert::Infallible;\n#[cfg(feature = \"tls\")]\nuse std::path::"
},
{
"path": "rust/xaynet-server/src/services/fetchers/mod.rs",
"chars": 6845,
"preview": "//! This module provides the services for serving data.\n//!\n//! There are multiple such services and the [`Fetcher`] tra"
},
{
"path": "rust/xaynet-server/src/services/fetchers/model.rs",
"chars": 1415,
"preview": "use std::{\n sync::Arc,\n task::{Context, Poll},\n};\n\nuse futures::future::{self, Ready};\nuse tower::Service;\nuse tra"
},
{
"path": "rust/xaynet-server/src/services/fetchers/round_parameters.rs",
"chars": 1280,
"preview": "use std::task::{Context, Poll};\n\nuse futures::future::{self, Ready};\nuse tower::Service;\nuse tracing::error_span;\nuse tr"
},
{
"path": "rust/xaynet-server/src/services/fetchers/seed_dict.rs",
"chars": 1503,
"preview": "use std::{\n sync::Arc,\n task::{Context, Poll},\n};\n\nuse futures::future::{self, Ready};\nuse tower::Service;\nuse tra"
},
{
"path": "rust/xaynet-server/src/services/fetchers/sum_dict.rs",
"chars": 1487,
"preview": "use std::{\n sync::Arc,\n task::{Context, Poll},\n};\n\nuse futures::future::{self, Ready};\nuse tower::Service;\nuse tra"
},
{
"path": "rust/xaynet-server/src/services/messages/decryptor.rs",
"chars": 5021,
"preview": "use std::{pin::Pin, sync::Arc, task::Poll};\n\nuse futures::{future::Future, task::Context};\nuse rayon::ThreadPool;\nuse to"
},
{
"path": "rust/xaynet-server/src/services/messages/error.rs",
"chars": 1487,
"preview": "use displaydoc::Display;\nuse thiserror::Error;\n\nuse crate::state_machine::requests::RequestError;\nuse xaynet_core::messa"
},
{
"path": "rust/xaynet-server/src/services/messages/message_parser.rs",
"chars": 13114,
"preview": "use std::{convert::TryInto, sync::Arc, task::Poll};\n\nuse futures::{future, task::Context};\nuse rayon::ThreadPool;\nuse to"
}
]
// ... and 47 more files (download for full content)
About this extraction
This page contains the full source code of the xaynetwork/xaynet GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 247 files (1.2 MB), approximately 322.2k tokens, and a symbol index with 2131 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.