Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e7d9b15158 | ||
|
|
c164b24049 | ||
|
|
e5e32c7c0a | ||
|
|
e509958ad9 | ||
|
|
40fde07559 | ||
|
|
2748dde76a | ||
|
|
0289c3ce91 | ||
|
|
50b451ff28 | ||
|
|
3123632877 | ||
|
|
c97dc62f62 | ||
|
|
5210452aef | ||
|
|
5055eba611 | ||
|
|
fb99e690a6 | ||
|
|
711318402a | ||
|
|
f25059fc3e | ||
|
|
a63d3dc0a6 | ||
|
|
7ce1a023ae | ||
|
|
7a24227e5e | ||
|
|
0f5736dae0 | ||
|
|
fd59ed70fa | ||
|
|
0518ca618c | ||
|
|
a30678eb62 | ||
|
|
ed111cdc25 | ||
|
|
9fd3f85733 | ||
|
|
5bfec5ffde | ||
|
|
f8d2c6f9c5 | ||
|
|
cb3e7eb4e5 | ||
|
|
27adf40262 | ||
|
|
0e5bf85a1a | ||
|
|
dd2d5744ca | ||
|
|
eb6bf67d30 | ||
|
|
b4384fb60b | ||
|
|
d1d9e18430 | ||
|
|
9e2ae17326 | ||
|
|
299aaeb8e4 | ||
|
|
393b09a43f | ||
|
|
7fab93f625 | ||
|
|
fa34779b3d | ||
|
|
9a4c969523 | ||
|
|
7ca92e80ab | ||
|
|
a87f0ad998 | ||
|
|
b9aa2a53ca | ||
|
|
faf6368b2a | ||
|
|
6d4c701f27 | ||
|
|
0f80795440 | ||
|
|
189496f182 | ||
|
|
eb21984300 | ||
|
|
5332a26264 | ||
|
|
0a8dbab87c | ||
|
|
9247c9fd99 | ||
|
|
261c1978ec | ||
|
|
b59ed7498c | ||
|
|
1e37b93e93 | ||
|
|
4ed47fec42 | ||
|
|
6ab15df0ec | ||
|
|
fbe8eb620f | ||
|
|
d9a5c388ad | ||
|
|
a96d930eb4 | ||
|
|
b8235c9eae | ||
|
|
43b67ccdba | ||
|
|
2218a12457 | ||
|
|
fa6dc4c724 | ||
|
|
0b4e5e490d | ||
|
|
09d15c0e8b | ||
|
|
353e2db77c | ||
|
|
2980863ebc | ||
|
|
73dba1a5bc | ||
|
|
fbb92b75b2 | ||
|
|
a68c19699e | ||
|
|
fd1889fedb | ||
|
|
f1ac9bfd12 | ||
|
|
483c19ca2c | ||
|
|
24f1cca2ce | ||
|
|
7d6f24afe6 | ||
|
|
20b73dd172 | ||
|
|
c39bfb9b32 | ||
|
|
d1ff642e9b | ||
|
|
8bf6d03752 | ||
|
|
54fe78c332 | ||
|
|
eebc07b1b4 | ||
|
|
947ad8abbd | ||
|
|
055eb0745d | ||
|
|
7d5710dbdb | ||
|
|
2a4e313301 | ||
|
|
03f5d99262 | ||
|
|
826444d867 | ||
|
|
6fae3e5843 | ||
|
|
742d6c80bf | ||
|
|
0e29408daa | ||
|
|
4507e91ef1 | ||
|
|
f57408de37 | ||
|
|
9caabc8d0d | ||
|
|
0ea4725525 | ||
|
|
e5b7e0e16e | ||
|
|
c763d1fdce | ||
|
|
142557b9eb | ||
|
|
8e2c837599 | ||
|
|
6c964a96eb | ||
|
|
07be41335b | ||
|
|
da62ebc979 | ||
|
|
28567c70da | ||
|
|
55e43bd610 | ||
|
|
e0b459639a | ||
|
|
b0b8ad8a62 | ||
|
|
da5d3f4924 | ||
|
|
a674f734cc | ||
|
|
ad43602e63 | ||
|
|
b31b44fbde | ||
|
|
cfd1049e8a | ||
|
|
e8c0733ce5 | ||
|
|
ffc7ae0d5f | ||
|
|
003ac2c02d | ||
|
|
d8913edb57 | ||
|
|
3d9be81c9a | ||
|
|
66a596ce53 | ||
|
|
35eb403b2d | ||
|
|
f0437a8ec2 | ||
|
|
5c74bfec3d | ||
|
|
5a337a4b64 | ||
|
|
0b2fa59a56 | ||
|
|
7e074ba39a | ||
|
|
8834ac1555 | ||
|
|
3132bf12b3 | ||
|
|
1ebb8b505c | ||
|
|
1191bb5f13 | ||
|
|
4bd0f9992f | ||
|
|
e69e155fe9 | ||
|
|
cbca2c06de | ||
|
|
00170f36e3 | ||
|
|
fff587f66f | ||
|
|
f954fd8522 | ||
|
|
81e78aed34 | ||
|
|
ba8169f189 | ||
|
|
d7391f13e1 | ||
|
|
289e90b80a | ||
|
|
d21d042ddd | ||
|
|
81b339dd70 | ||
|
|
35ab35b1a4 | ||
|
|
22c7e58513 | ||
|
|
ce83afc1b0 | ||
|
|
465065cff8 | ||
|
|
ec32d36cab | ||
|
|
9277cff3bd | ||
|
|
bd57868279 | ||
|
|
acea8b5e0c | ||
|
|
1b187a379c | ||
|
|
4fd3b087d1 | ||
|
|
ed962f61bb | ||
|
|
a4e5381432 | ||
|
|
6fecac3b91 | ||
|
|
0df7762587 | ||
|
|
7c43c940ce | ||
|
|
95f1277fed | ||
|
|
7268d72a65 | ||
|
|
fd719f534e | ||
|
|
42179a6721 | ||
|
|
79c94da915 | ||
|
|
67960902e8 | ||
|
|
d18494ea9a | ||
|
|
4ba32fe7db | ||
|
|
cdf7820037 | ||
|
|
81b6e7c370 | ||
|
|
3b8e62b74b | ||
|
|
b1cfea4f52 | ||
|
|
19d5ac0619 | ||
|
|
f27d0445e6 | ||
|
|
2ddea6a139 | ||
|
|
53ff8b5db1 | ||
|
|
3c7d726d4a | ||
|
|
af82e8fc5f | ||
|
|
6e0b215ce4 | ||
|
|
248cf9962c | ||
|
|
9af8b511b1 | ||
|
|
112e2efe20 | ||
|
|
df7c9d711c | ||
|
|
b446a9f9ad | ||
|
|
b0d365365b | ||
|
|
88bf66afd3 | ||
|
|
4e5c9e99a6 | ||
|
|
f828ee216b | ||
|
|
0143634927 | ||
|
|
06a82c0d95 | ||
|
|
ba3f8cfc20 | ||
|
|
fb9bb6a690 | ||
|
|
6d55e6995c | ||
|
|
22f37a0e93 | ||
|
|
bd3d138c7c | ||
|
|
e9f4962362 | ||
|
|
4a35532808 | ||
|
|
633ff35ba4 | ||
|
|
92bf5c4ca5 | ||
|
|
4f53d80b8d | ||
|
|
f1acc202eb | ||
|
|
b2504be8cb | ||
|
|
a2235a0d55 | ||
|
|
ec279581b8 | ||
|
|
a1edfe231e | ||
|
|
f54b5d45bd | ||
|
|
103b2a3847 | ||
|
|
70f2c0210f | ||
|
|
df742523d4 | ||
|
|
48400e3208 | ||
|
|
e4e9f985f7 | ||
|
|
24891a7aa2 | ||
|
|
bdd0a9a147 | ||
|
|
f0c82d3d81 | ||
|
|
d17c40e4e8 | ||
|
|
3856de32fc | ||
|
|
3c1b605883 | ||
|
|
e07ffabbe8 | ||
|
|
b80483a3f3 | ||
|
|
d61600ccd2 | ||
|
|
60003a42ab | ||
|
|
23fdcef9be | ||
|
|
1bc8283cd6 | ||
|
|
c30c1c429f | ||
|
|
9c67a406a5 | ||
|
|
d342ac541e | ||
|
|
f9863b901c | ||
|
|
134a8735d5 | ||
|
|
e08199551c | ||
|
|
d7aa304d61 | ||
|
|
54d19f56a4 | ||
|
|
019118710a | ||
|
|
9bb9d2f933 | ||
|
|
e1418c0679 | ||
|
|
1318080e01 | ||
|
|
a91f5da8cf | ||
|
|
ad7d37d6f9 | ||
|
|
5ba5425ef7 | ||
|
|
10794acd49 | ||
|
|
f7fb4b4d92 | ||
|
|
29daa4876a | ||
|
|
6cf68b1658 | ||
|
|
0d1310305e | ||
|
|
9ac5af38bf | ||
|
|
ed99eadf82 | ||
|
|
a5ce5e6d0a | ||
|
|
80d78c81f7 | ||
|
|
2b40c181de | ||
|
|
a071f4fd83 | ||
|
|
b7285c0a3a | ||
|
|
b0d8a55dd9 | ||
|
|
9643a1f4bc | ||
|
|
3b6d87b532 | ||
|
|
ebdf52d20c | ||
|
|
1d16ab3ed7 | ||
|
|
b0550f3936 | ||
|
|
eeb4425242 | ||
|
|
41777186d0 | ||
|
|
c9130e425d | ||
|
|
7fd08bfd80 | ||
|
|
53adabae00 | ||
|
|
5c19f0876f | ||
|
|
438b689cfa | ||
|
|
5d55d99de8 | ||
|
|
988ecaa42f | ||
|
|
b0f3a2d2ae | ||
|
|
150c5ca618 | ||
|
|
23ff0db5b5 | ||
|
|
c35de22070 | ||
|
|
43d50c2500 | ||
|
|
34b6eaeffd | ||
|
|
003eb91e2e | ||
|
|
a2d38ccbbe | ||
|
|
0ea1553b2c |
@@ -0,0 +1,160 @@
|
||||
name: "libp2p hole-punch interop test"
|
||||
description: "Run the libp2p hole-punch interoperability test suite"
|
||||
inputs:
|
||||
test-filter:
|
||||
description: "Filter which tests to run out of the created matrix"
|
||||
required: false
|
||||
default: ""
|
||||
test-ignore:
|
||||
description: "Exclude tests from the created matrix that include this string in their name"
|
||||
required: false
|
||||
default: ""
|
||||
extra-versions:
|
||||
description: "Space-separated paths to JSON files describing additional images"
|
||||
required: false
|
||||
default: ""
|
||||
s3-cache-bucket:
|
||||
description: "Which S3 bucket to use for container layer caching"
|
||||
required: false
|
||||
default: ""
|
||||
s3-access-key-id:
|
||||
description: "S3 Access key id for the cache"
|
||||
required: false
|
||||
default: ""
|
||||
s3-secret-access-key:
|
||||
description: "S3 secret key id for the cache"
|
||||
required: false
|
||||
default: ""
|
||||
aws-region:
|
||||
description: "Which AWS region to use"
|
||||
required: false
|
||||
default: "us-east-1"
|
||||
worker-count:
|
||||
description: "How many workers to use for the test"
|
||||
required: false
|
||||
default: "2"
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Configure AWS credentials for S3 build cache
|
||||
if: inputs.s3-access-key-id != '' && inputs.s3-secret-access-key != ''
|
||||
run: |
|
||||
echo "PUSH_CACHE=true" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
# This depends on where this file is within this repository. This walks up
|
||||
# from here to the hole-punch-interop folder
|
||||
- run: |
|
||||
WORK_DIR=$(realpath "$GITHUB_ACTION_PATH/../../../hole-punch-interop")
|
||||
echo "WORK_DIR=$WORK_DIR" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
id: find-workdir
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
# Existence of /etc/buildkit/buildkitd.toml indicates that this is a
|
||||
# self-hosted runner. If so, we need to pass the config to the buildx
|
||||
# action. The config enables docker.io proxy which is required to
|
||||
# work around docker hub rate limiting.
|
||||
- run: |
|
||||
if test -f /etc/buildkit/buildkitd.toml; then
|
||||
echo "config=/etc/buildkit/buildkitd.toml" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
shell: bash
|
||||
id: buildkit
|
||||
|
||||
- name: Install more recent docker-compose version # https://stackoverflow.com/questions/54331949/having-networking-issues-with-docker-compose
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p $HOME/.docker/cli-plugins
|
||||
wget -q -O- https://github.com/docker/compose/releases/download/v2.21.0/docker-compose-linux-x86_64 > $HOME/.docker/cli-plugins/docker-compose
|
||||
chmod +x $HOME/.docker/cli-plugins/docker-compose
|
||||
docker compose version
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
config: ${{ steps.buildkit.outputs.config }}
|
||||
|
||||
- name: Install deps
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: npm ci
|
||||
shell: bash
|
||||
|
||||
- name: Load cache and build
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
env:
|
||||
AWS_BUCKET: ${{ inputs.s3-cache-bucket }}
|
||||
AWS_REGION: ${{ inputs.aws-region }}
|
||||
AWS_ACCESS_KEY_ID: ${{ inputs.s3-access-key-id }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ inputs.s3-secret-access-key }}
|
||||
run: npm run cache -- load
|
||||
shell: bash
|
||||
|
||||
- name: Assert Git tree is clean.
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ -n "$(git status --porcelain)" ]]; then
|
||||
echo "Git tree is dirty. This means that building an impl generated something that should probably be .gitignore'd"
|
||||
git status
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Push the image cache
|
||||
if: env.PUSH_CACHE == 'true'
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
env:
|
||||
AWS_BUCKET: ${{ inputs.s3-cache-bucket }}
|
||||
AWS_REGION: ${{ inputs.aws-region }}
|
||||
AWS_ACCESS_KEY_ID: ${{ inputs.s3-access-key-id }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ inputs.s3-secret-access-key }}
|
||||
run: npm run cache -- push
|
||||
shell: bash
|
||||
|
||||
- name: Run the test
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
env:
|
||||
WORKER_COUNT: ${{ inputs.worker-count }}
|
||||
EXTRA_VERSION: ${{ inputs.extra-versions }}
|
||||
NAME_FILTER: ${{ inputs.test-filter }}
|
||||
NAME_IGNORE: ${{ inputs.test-ignore }}
|
||||
run: npm run test -- --extra-version=$EXTRA_VERSION --name-filter=$NAME_FILTER --name-ignore=$NAME_IGNORE
|
||||
shell: bash
|
||||
|
||||
- name: Print the results
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: cat results.csv
|
||||
shell: bash
|
||||
|
||||
- name: Render results
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: npm run renderResults > ./dashboard.md
|
||||
shell: bash
|
||||
|
||||
- name: Show Dashboard Output
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: cat ./dashboard.md >> $GITHUB_STEP_SUMMARY
|
||||
shell: bash
|
||||
|
||||
- name: Exit with Error
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: |
|
||||
if grep -q ":red_circle:" ./dashboard.md; then
|
||||
exit 1
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
name: test-plans-output
|
||||
path: |
|
||||
${{ steps.find-workdir.outputs.WORK_DIR }}/results.csv
|
||||
${{ steps.find-workdir.outputs.WORK_DIR }}/dashboard.md
|
||||
${{ steps.find-workdir.outputs.WORK_DIR }}/runs
|
||||
@@ -0,0 +1,150 @@
|
||||
name: "libp2p ping interop test"
|
||||
description: "Run the libp2p ping interoperability test suite"
|
||||
inputs:
|
||||
test-filter:
|
||||
description: "Filter which tests to run out of the created matrix"
|
||||
required: false
|
||||
default: ""
|
||||
test-ignore:
|
||||
description: "Exclude tests from the created matrix that include this string in their name"
|
||||
required: false
|
||||
default: ""
|
||||
extra-versions:
|
||||
description: "Space-separated paths to JSON files describing additional images"
|
||||
required: false
|
||||
default: ""
|
||||
s3-cache-bucket:
|
||||
description: "Which S3 bucket to use for container layer caching"
|
||||
required: false
|
||||
default: ""
|
||||
s3-access-key-id:
|
||||
description: "S3 Access key id for the cache"
|
||||
required: false
|
||||
default: ""
|
||||
s3-secret-access-key:
|
||||
description: "S3 secret key id for the cache"
|
||||
required: false
|
||||
default: ""
|
||||
aws-region:
|
||||
description: "Which AWS region to use"
|
||||
required: false
|
||||
default: "us-east-1"
|
||||
worker-count:
|
||||
description: "How many workers to use for the test"
|
||||
required: false
|
||||
default: "2"
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Configure AWS credentials for S3 build cache
|
||||
if: inputs.s3-access-key-id != '' && inputs.s3-secret-access-key != ''
|
||||
run: |
|
||||
echo "PUSH_CACHE=true" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
# This depends on where this file is within this repository. This walks up
|
||||
# from here to the transport-interop folder
|
||||
- run: |
|
||||
WORK_DIR=$(realpath "$GITHUB_ACTION_PATH/../../../transport-interop")
|
||||
echo "WORK_DIR=$WORK_DIR" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
id: find-workdir
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
# Existence of /etc/buildkit/buildkitd.toml indicates that this is a
|
||||
# self-hosted runner. If so, we need to pass the config to the buildx
|
||||
# action. The config enables docker.io proxy which is required to
|
||||
# work around docker hub rate limiting.
|
||||
- run: |
|
||||
if test -f /etc/buildkit/buildkitd.toml; then
|
||||
echo "config=/etc/buildkit/buildkitd.toml" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
shell: bash
|
||||
id: buildkit
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
config: ${{ steps.buildkit.outputs.config }}
|
||||
|
||||
- name: Install deps
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: npm ci
|
||||
shell: bash
|
||||
|
||||
- name: Load cache and build
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
env:
|
||||
AWS_BUCKET: ${{ inputs.s3-cache-bucket }}
|
||||
AWS_REGION: ${{ inputs.aws-region }}
|
||||
AWS_ACCESS_KEY_ID: ${{ inputs.s3-access-key-id }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ inputs.s3-secret-access-key }}
|
||||
run: npm run cache -- load
|
||||
shell: bash
|
||||
|
||||
- name: Assert Git tree is clean.
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ -n "$(git status --porcelain)" ]]; then
|
||||
echo "Git tree is dirty. This means that building an impl generated something that should probably be .gitignore'd"
|
||||
git status
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Push the image cache
|
||||
if: env.PUSH_CACHE == 'true'
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
env:
|
||||
AWS_BUCKET: ${{ inputs.s3-cache-bucket }}
|
||||
AWS_REGION: ${{ inputs.aws-region }}
|
||||
AWS_ACCESS_KEY_ID: ${{ inputs.s3-access-key-id }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ inputs.s3-secret-access-key }}
|
||||
run: npm run cache -- push
|
||||
shell: bash
|
||||
|
||||
- name: Run the test
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
env:
|
||||
WORKER_COUNT: ${{ inputs.worker-count }}
|
||||
EXTRA_VERSION: ${{ inputs.extra-versions }}
|
||||
NAME_FILTER: ${{ inputs.test-filter }}
|
||||
NAME_IGNORE: ${{ inputs.test-ignore }}
|
||||
run: npm run test -- --extra-version=$EXTRA_VERSION --name-filter=$NAME_FILTER --name-ignore=$NAME_IGNORE
|
||||
shell: bash
|
||||
|
||||
- name: Print the results
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: cat results.csv
|
||||
shell: bash
|
||||
|
||||
- name: Render results
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: npm run renderResults > ./dashboard.md
|
||||
shell: bash
|
||||
|
||||
- name: Show Dashboard Output
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: cat ./dashboard.md >> $GITHUB_STEP_SUMMARY
|
||||
shell: bash
|
||||
|
||||
- name: Exit with Error
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: |
|
||||
if grep -q ":red_circle:" ./dashboard.md; then
|
||||
exit 1
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-plans-output
|
||||
path: |
|
||||
${{ steps.find-workdir.outputs.WORK_DIR }}/results.csv
|
||||
${{ steps.find-workdir.outputs.WORK_DIR }}/dashboard.md
|
||||
@@ -0,0 +1,150 @@
|
||||
name: "libp2p transport interop test"
|
||||
description: "Run the libp2p transport interoperability test suite"
|
||||
inputs:
|
||||
test-filter:
|
||||
description: "Filter which tests to run out of the created matrix"
|
||||
required: false
|
||||
default: ""
|
||||
test-ignore:
|
||||
description: "Exclude tests from the created matrix that include this string in their name"
|
||||
required: false
|
||||
default: ""
|
||||
extra-versions:
|
||||
description: "Space-separated paths to JSON files describing additional images"
|
||||
required: false
|
||||
default: ""
|
||||
s3-cache-bucket:
|
||||
description: "Which S3 bucket to use for container layer caching"
|
||||
required: false
|
||||
default: ""
|
||||
s3-access-key-id:
|
||||
description: "S3 Access key id for the cache"
|
||||
required: false
|
||||
default: ""
|
||||
s3-secret-access-key:
|
||||
description: "S3 secret key id for the cache"
|
||||
required: false
|
||||
default: ""
|
||||
aws-region:
|
||||
description: "Which AWS region to use"
|
||||
required: false
|
||||
default: "us-east-1"
|
||||
worker-count:
|
||||
description: "How many workers to use for the test"
|
||||
required: false
|
||||
default: "2"
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Configure AWS credentials for S3 build cache
|
||||
if: inputs.s3-access-key-id != '' && inputs.s3-secret-access-key != ''
|
||||
run: |
|
||||
echo "PUSH_CACHE=true" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
# This depends on where this file is within this repository. This walks up
|
||||
# from here to the transport-interop folder
|
||||
- run: |
|
||||
WORK_DIR=$(realpath "$GITHUB_ACTION_PATH/../../../transport-interop")
|
||||
echo "WORK_DIR=$WORK_DIR" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
id: find-workdir
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
# Existence of /etc/buildkit/buildkitd.toml indicates that this is a
|
||||
# self-hosted runner. If so, we need to pass the config to the buildx
|
||||
# action. The config enables docker.io proxy which is required to
|
||||
# work around docker hub rate limiting.
|
||||
- run: |
|
||||
if test -f /etc/buildkit/buildkitd.toml; then
|
||||
echo "config=/etc/buildkit/buildkitd.toml" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
shell: bash
|
||||
id: buildkit
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
config: ${{ steps.buildkit.outputs.config }}
|
||||
|
||||
- name: Install deps
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: npm ci
|
||||
shell: bash
|
||||
|
||||
- name: Load cache and build
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
env:
|
||||
AWS_BUCKET: ${{ inputs.s3-cache-bucket }}
|
||||
AWS_REGION: ${{ inputs.aws-region }}
|
||||
AWS_ACCESS_KEY_ID: ${{ inputs.s3-access-key-id }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ inputs.s3-secret-access-key }}
|
||||
run: npm run cache -- load
|
||||
shell: bash
|
||||
|
||||
- name: Assert Git tree is clean.
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ -n "$(git status --porcelain)" ]]; then
|
||||
echo "Git tree is dirty. This means that building an impl generated something that should probably be .gitignore'd"
|
||||
git status
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Push the image cache
|
||||
if: env.PUSH_CACHE == 'true'
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
env:
|
||||
AWS_BUCKET: ${{ inputs.s3-cache-bucket }}
|
||||
AWS_REGION: ${{ inputs.aws-region }}
|
||||
AWS_ACCESS_KEY_ID: ${{ inputs.s3-access-key-id }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ inputs.s3-secret-access-key }}
|
||||
run: npm run cache -- push
|
||||
shell: bash
|
||||
|
||||
- name: Run the test
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
env:
|
||||
WORKER_COUNT: ${{ inputs.worker-count }}
|
||||
EXTRA_VERSION: ${{ inputs.extra-versions }}
|
||||
NAME_FILTER: ${{ inputs.test-filter }}
|
||||
NAME_IGNORE: ${{ inputs.test-ignore }}
|
||||
run: npm run test -- --extra-version=$EXTRA_VERSION --name-filter=$NAME_FILTER --name-ignore=$NAME_IGNORE
|
||||
shell: bash
|
||||
|
||||
- name: Print the results
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: cat results.csv
|
||||
shell: bash
|
||||
|
||||
- name: Render results
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: npm run renderResults > ./dashboard.md
|
||||
shell: bash
|
||||
|
||||
- name: Show Dashboard Output
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: cat ./dashboard.md >> $GITHUB_STEP_SUMMARY
|
||||
shell: bash
|
||||
|
||||
- name: Exit with Error
|
||||
working-directory: ${{ steps.find-workdir.outputs.WORK_DIR }}
|
||||
run: |
|
||||
if grep -q ":red_circle:" ./dashboard.md; then
|
||||
exit 1
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-plans-output
|
||||
path: |
|
||||
${{ steps.find-workdir.outputs.WORK_DIR }}/results.csv
|
||||
${{ steps.find-workdir.outputs.WORK_DIR }}/dashboard.md
|
||||
@@ -1,82 +0,0 @@
|
||||
name: start testground
|
||||
description: setup a local testground instance
|
||||
inputs:
|
||||
testground_endpoint:
|
||||
required: false
|
||||
default: ''
|
||||
testground_repository:
|
||||
required: false
|
||||
default: 'testground/testground'
|
||||
testground_ref:
|
||||
required: false
|
||||
default: 'edge'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# Default setup when we use the testground_ref == edge.
|
||||
- name: Load testground
|
||||
if: ${{ inputs.testground_ref == 'edge' }}
|
||||
shell: bash
|
||||
run: |
|
||||
for i in 1 2 3; do
|
||||
echo "=== Attempt $i ==="
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/testground/testground/master/install.sh)" && \
|
||||
exit 0
|
||||
sleep 10
|
||||
done
|
||||
exit 1
|
||||
# Custom setup (slower) when we use a different testground_ref
|
||||
- name: Checkout testground
|
||||
if: ${{ inputs.testground_ref != 'edge' }}
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: testground
|
||||
repository: ${{ inputs.testground_repository }}
|
||||
ref: ${{ inputs.testground_ref }}
|
||||
|
||||
- name: Setup Go
|
||||
if: ${{ inputs.testground_ref != 'edge' }}
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
cache: true
|
||||
go-version-file: 'testground/go.mod'
|
||||
cache-dependency-path: testground/go.sum
|
||||
|
||||
- name: Install testground
|
||||
if: ${{ inputs.testground_ref != 'edge' }}
|
||||
run: make install || make install || make install # 3 retries in case of network drops.
|
||||
working-directory: testground
|
||||
shell: bash
|
||||
|
||||
- name: Run the daemon or configure the client
|
||||
shell: bash
|
||||
env:
|
||||
TESTGROUND_ENDPOINT: ${{ inputs.testground_endpoint }}
|
||||
run: |
|
||||
if [[ ! -z "${TESTGROUND_ENDPOINT}" ]]; then
|
||||
mkdir -p ~/testground/;
|
||||
cat <<EOF >> ~/testground/.env.toml
|
||||
|
||||
[client]
|
||||
endpoint = "${TESTGROUND_ENDPOINT}"
|
||||
EOF
|
||||
else
|
||||
mkdir -p ~/testground/;
|
||||
cat <<EOF >> ~/testground/.env.toml
|
||||
|
||||
[daemon.scheduler]
|
||||
task_timeout_min = 60
|
||||
EOF
|
||||
testground daemon > testground.out 2> testground.err &
|
||||
fi;
|
||||
|
||||
- name: Check testground daemon health
|
||||
run:
|
||||
echo "Waiting for Testground to launch on 8042...";
|
||||
while ! nc -z localhost 8042; do
|
||||
sleep 1;
|
||||
done;
|
||||
echo "Testground launched";
|
||||
testground healthcheck --runner local:docker --fix;
|
||||
shell: bash
|
||||
@@ -0,0 +1,13 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: npm
|
||||
# this should point to the latest js-libp2p major in order to automate
|
||||
# updating deps automatically after a release
|
||||
directory: "/transport-interop/impl/js/v1.x"
|
||||
schedule:
|
||||
interval: daily
|
||||
time: "10:00"
|
||||
open-pull-requests-limit: 20
|
||||
commit-message:
|
||||
prefix: "deps"
|
||||
prefix-development: "deps(dev)"
|
||||
@@ -0,0 +1,152 @@
|
||||
name: Add new implementation versions
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# “At minute 36 past every 24th hour.” - https://crontab.guru/#36_*/24_*_*_*
|
||||
- cron: '36 */24 * * *'
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
actions: write
|
||||
|
||||
jobs:
|
||||
add:
|
||||
name: Add new ${{ matrix.repository_name }} version to ${{ matrix.test_name }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- repository_name: go-libp2p
|
||||
implementation_name: go-libp2p
|
||||
test_name: perf
|
||||
implementation_update_script: |
|
||||
sed -i "1s/$LOCAL_MAJOR_MINOR_VERSION/$REMOTE_MAJOR_MINOR_VERSION/g" go.mod
|
||||
go mod tidy -go=$GO_MAJOR_MINOR_VERSION
|
||||
go mod tidy
|
||||
go get github.com/libp2p/go-libp2p@$REMOTE_VERSION
|
||||
- repository_name: go-libp2p
|
||||
implementation_name: go
|
||||
test_name: transport-interop
|
||||
implementation_update_script: |
|
||||
sed -i "s/image_name := go-${LOCAL_MAJOR_MINOR_VERSION}/image_name := go-${REMOTE_MAJOR_MINOR_VERSION}/g" Makefile
|
||||
sed -i "s/version := ${LOCAL_MAJOR_MINOR_VERSION#v}\..*/version := ${REMOTE_VERSION#v}/g" Makefile
|
||||
make version.lock
|
||||
- repository_name: rust-libp2p
|
||||
implementation_name: rust-libp2p
|
||||
test_name: perf
|
||||
implementation_update_script: |
|
||||
sed -i "s/commitSha := .*/commitSha := ${REMOTE_SHA}/g" Makefile
|
||||
- repository_name: rust-libp2p
|
||||
implementation_name: rust
|
||||
test_name: transport-interop
|
||||
implementation_update_script: |
|
||||
sed -i "s/image_name := rust-${LOCAL_MAJOR_MINOR_VERSION}/image_name := rust-${REMOTE_MAJOR_MINOR_VERSION}/g" Makefile
|
||||
sed -i "s/commitSha := .*/commitSha := ${REMOTE_SHA}/g" Makefile
|
||||
- repository_name: js-libp2p
|
||||
implementation_name: js-libp2p
|
||||
test_name: perf
|
||||
implementation_update_script: |
|
||||
suffix="$(echo "${REMOTE_MAJOR_MINOR_VERSION#v}" | sed 's/\./-/g')"
|
||||
sed -i "s/perf-js-libp2p-[^\"]*/perf-js-libp2p-$suffix/g" package.json
|
||||
npm install libp2p@$REMOTE_VERSION
|
||||
- repository_name: js-libp2p
|
||||
implementation_name: js
|
||||
test_name: transport-interop
|
||||
implementation_update_script: |
|
||||
sed -i "s/image_name := js-${LOCAL_MAJOR_MINOR_VERSION}\..*/image_name := js-${REMOTE_VERSION}/g" Makefile
|
||||
npm install libp2p@$REMOTE_VERSION
|
||||
env:
|
||||
BRANCH: add/${{ matrix.test_name }}/${{ matrix.repository_name }}
|
||||
steps:
|
||||
- name: Checkout test-plans
|
||||
uses: actions/checkout@v4
|
||||
- name: Configure git
|
||||
run: |
|
||||
git fetch origin $BRANCH && git checkout $BRANCH || git checkout -b $BRANCH
|
||||
git rebase $GITHUB_REF -X theirs || git rebase --abort
|
||||
git config --global user.email $GITHUB_ACTOR@users.noreply.github.com
|
||||
git config --global user.name $GITHUB_ACTOR
|
||||
- id: go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: stable
|
||||
- name: Get the latest version (local)
|
||||
id: local
|
||||
env:
|
||||
IMPLEMENTATION_DIRECTORY: ${{ matrix.test_name }}/impl/${{ matrix.implementation_name }}
|
||||
run: |
|
||||
pushd $IMPLEMENTATION_DIRECTORY
|
||||
ls -d v* | sort -V | tail -n-1 | xargs -I{} echo "version={}" | tee -a $GITHUB_OUTPUT
|
||||
popd
|
||||
- name: Get the latest version (remote)
|
||||
id: remote
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
REPOSITORY_NAME: ${{ matrix.repository_name }}
|
||||
run: |
|
||||
releases="$(gh api --paginate repos/libp2p/$REPOSITORY_NAME/releases)"
|
||||
latest="$(jq 'map(select(.tag_name | startswith("libp2p-"))) | first' <<< "$releases")"
|
||||
if [[ "$latest" == "null" ]]; then
|
||||
latest="$(jq 'first' <<< "$releases")"
|
||||
fi
|
||||
tag_name=$(jq -r '.tag_name' <<< "$latest")
|
||||
target_commitish=$(jq -r '.target_commitish' <<< "$latest")
|
||||
echo "version=${tag_name#libp2p-}" | tee -a $GITHUB_OUTPUT
|
||||
echo "target_commitish=${target_commitish}" | tee -a $GITHUB_OUTPUT
|
||||
- id: mm
|
||||
env:
|
||||
REMOTE_VERSION: ${{ steps.remote.outputs.version }}
|
||||
GO_VERSION: ${{ steps.go.outputs.go-version }}
|
||||
run: |
|
||||
echo $REMOTE_VERSION | sed 's/\.[0-9]*$//' | xargs -I{} echo "remote={}" | tee -a $GITHUB_OUTPUT
|
||||
echo $GO_VERSION | sed 's/\.[0-9]*$//' | xargs -I{} echo "go={}" | tee -a $GITHUB_OUTPUT
|
||||
- name: Add the latest version
|
||||
if: ${{ !startsWith(steps.remote.outputs.version, steps.local.outputs.version) }}
|
||||
env:
|
||||
LOCAL_MAJOR_MINOR_VERSION: ${{ steps.local.outputs.version }}
|
||||
REMOTE_VERSION: ${{ steps.remote.outputs.version }}
|
||||
REMOTE_MAJOR_MINOR_VERSION: ${{ steps.mm.outputs.remote }}
|
||||
REMOTE_SHA: ${{ steps.remote.outputs.sha }}
|
||||
GO_VERSION: ${{ steps.go.outputs.go-version }}
|
||||
GO_MAJOR_MINOR_VERSION: ${{ steps.mm.outputs.go }}
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
IMPLEMENTATION_DIRECTORY: ${{ matrix.test_name }}/impl/${{ matrix.implementation_name }}
|
||||
VERSIONS_DIRECTORY: ${{ matrix.test_name == 'perf' && format('{0}/runner', matrix.test_name) || matrix.test_name }}
|
||||
IMPLEMENTATION_NAME: ${{ matrix.implementation_name }}
|
||||
REPOSITORY_NAME: ${{ matrix.repository_name }}
|
||||
TEST_NAME: ${{ matrix.test_name }}
|
||||
run: |
|
||||
pushd $IMPLEMENTATION_DIRECTORY
|
||||
cp -r $LOCAL_MAJOR_MINOR_VERSION $REMOTE_MAJOR_MINOR_VERSION
|
||||
pushd $REMOTE_MAJOR_MINOR_VERSION
|
||||
${{ matrix.implementation_update_script }}
|
||||
popd
|
||||
popd
|
||||
|
||||
pushd $VERSIONS_DIRECTORY
|
||||
versions=''
|
||||
if [[ "$TEST_NAME" == "perf" ]]; then
|
||||
versions="$(jq '. + map(select(.implementation == env.IMPLEMENTATION_NAME and .id == env.LOCAL_MAJOR_MINOR_VERSION) | .id = env.REMOTE_MAJOR_MINOR_VERSION)' versionsInput.json)"
|
||||
else
|
||||
versions="$(jq '. + map(select(.id == "\(env.IMPLEMENTATION_NAME)-\(env.LOCAL_MAJOR_MINOR_VERSION)") | .id = "\(env.IMPLEMENTATION_NAME)-\(env.REMOTE_MAJOR_MINOR_VERSION)")' versionsInput.json)"
|
||||
fi
|
||||
echo "$versions" > versionsInput.json
|
||||
popd
|
||||
|
||||
git add .
|
||||
git commit -m "chore: add $REPOSITORY_NAME@$REMOTE_VERSION to $TEST_NAME"
|
||||
|
||||
git push origin $BRANCH --force
|
||||
|
||||
if [[ $(gh pr list --state open --base $GITHUB_REF --head $BRANCH | wc -l) -eq 0 ]]; then
|
||||
gh pr create --title "chore: add $REPOSITORY_NAME@$REMOTE_VERSION to $TEST_NAME" --body "This PR adds $REPOSITORY_NAME@$REMOTE_VERSION to $TEST_NAME" --head $BRANCH --base $GITHUB_REF
|
||||
fi
|
||||
|
||||
gh workflow run $TEST_NAME.yml --ref $BRANCH
|
||||
@@ -0,0 +1,34 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'hole-punch-interop/**'
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
paths:
|
||||
- 'hole-punch-interop/**'
|
||||
|
||||
name: libp2p holepunching interop test
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
run-hole-punch-interop:
|
||||
runs-on: ['self-hosted', 'linux', 'x64', '4xlarge'] # https://github.com/pl-strflt/tf-aws-gh-runner/blob/main/runners.tf
|
||||
# Uncomment to test for flakiness.
|
||||
# strategy:
|
||||
# matrix:
|
||||
# dim1: ['a', 'b', 'c', 'd', 'e']
|
||||
# dim2: [1, 2, 3, 4, 5]
|
||||
# fail-fast: false
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/run-interop-hole-punch-test
|
||||
with:
|
||||
s3-cache-bucket: ${{ vars.S3_LIBP2P_BUILD_CACHE_BUCKET_NAME }}
|
||||
s3-access-key-id: ${{ vars.S3_LIBP2P_BUILD_CACHE_AWS_ACCESS_KEY_ID }}
|
||||
s3-secret-access-key: ${{ secrets.S3_LIBP2P_BUILD_CACHE_AWS_SECRET_ACCESS_KEY }}
|
||||
worker-count: 16
|
||||
@@ -0,0 +1,104 @@
|
||||
name: libp2p perf test
|
||||
|
||||
# How to configure a repository for running this workflow:
|
||||
# 1. Configure auth for the AWS provider as per https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration
|
||||
# 2. Run 'terraform init' and 'terraform apply' in 'perf/terraform/configs/remote' to create the resources needed for this workflow
|
||||
# 3. Go to https://console.aws.amazon.com/iamv2/home?#/users/details/perf?section=security_credentials
|
||||
# 4. Click 'Create access key' to get the access key ID and secret access key
|
||||
# 5. Go to https://github.com/libp2p/test-plans/settings/secrets/actions
|
||||
# 6. Click 'New repository secret', set the name to 'PERF_AWS_SECRET_ACCESS_KEY', and paste the secret access key from step 5
|
||||
# 7. Go to https://github.com/libp2p/test-plans/settings/variables/actions
|
||||
# 8. Click 'New repository variable', set the name to 'PERF_AWS_ACCESS_KEY_ID', and paste the access key ID from step 5
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
push:
|
||||
description: 'Push the benchmark results to the repository'
|
||||
required: false
|
||||
default: 'true'
|
||||
|
||||
jobs:
|
||||
perf:
|
||||
name: Perf
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 240
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: perf
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ vars.PERF_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.PERF_AWS_SECRET_ACCESS_KEY }}
|
||||
TF_IN_AUTOMATION: 1
|
||||
TF_INPUT: 0
|
||||
steps:
|
||||
- name: Checkout test-plans
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: ${{ github.repository }}
|
||||
ref: ${{ github.ref }}
|
||||
- id: ssh
|
||||
name: Generate SSH key
|
||||
run: |
|
||||
make ssh-keygen
|
||||
echo "key<<EOF" >> $GITHUB_OUTPUT
|
||||
while read -r line; do
|
||||
echo "::add-mask::$line"
|
||||
echo "$line" >> $GITHUB_OUTPUT
|
||||
done < terraform/modules/short_lived/files/perf
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
- name: Configure SSH
|
||||
uses: webfactory/ssh-agent@d4b9b8ff72958532804b70bbe600ad43b36d5f2e # v0.8.0
|
||||
with:
|
||||
ssh-private-key: ${{ steps.ssh.outputs.key }}
|
||||
- name: Configure git
|
||||
run: |
|
||||
git config --global user.email "${GITHUB_ACTOR}@users.noreply.github.com>"
|
||||
git config --global user.name "${GITHUB_ACTOR}"
|
||||
- name: Configure terraform
|
||||
uses: hashicorp/setup-terraform@633666f66e0061ca3b725c73b2ec20cd13a8fdd1 # v2.0.3
|
||||
- name: Init terraform
|
||||
id: init
|
||||
run: terraform init
|
||||
working-directory: perf/terraform/configs/local
|
||||
- name: Apply terraform
|
||||
run: terraform apply -auto-approve
|
||||
working-directory: perf/terraform/configs/local
|
||||
- id: server
|
||||
name: Retrieve server's IP
|
||||
run: terraform output -raw server_ip
|
||||
working-directory: perf/terraform/configs/local
|
||||
- id: client
|
||||
name: Retrieve client's IP
|
||||
run: terraform output -raw client_ip
|
||||
working-directory: perf/terraform/configs/local
|
||||
- name: Download dependencies
|
||||
run: npm ci
|
||||
working-directory: perf/runner
|
||||
- name: Run tests
|
||||
env:
|
||||
SERVER_IP: ${{ steps.server.outputs.stdout }}
|
||||
CLIENT_IP: ${{ steps.client.outputs.stdout }}
|
||||
run: npm run start -- --client-public-ip $CLIENT_IP --server-public-ip $SERVER_IP
|
||||
working-directory: perf/runner
|
||||
- name: Push
|
||||
if: github.event.inputs.push == 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
git add benchmark-results.json
|
||||
git commit -m "perf: update benchmark results"
|
||||
git push
|
||||
gh pr comment --body "See new metrics at https://observablehq.com/@libp2p-workspace/performance-dashboard?branch=$(git rev-parse HEAD)" || true
|
||||
working-directory: perf/runner
|
||||
- name: Archive
|
||||
if: github.event.intputs.push == 'false'
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: benchmark-results
|
||||
path: perf/runner/benchmark-results.json
|
||||
- name: Destroy terraform
|
||||
if: always() && steps.init.outputs.exitcode == 0
|
||||
run: terraform destroy -auto-approve
|
||||
working-directory: perf/terraform/configs/local
|
||||
@@ -1,34 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
testground_endpoint:
|
||||
type: string
|
||||
required: false
|
||||
description: testground endpoint
|
||||
custom_git_reference:
|
||||
type: string
|
||||
required: false
|
||||
description: go ref
|
||||
custom_git_target:
|
||||
type: string
|
||||
required: false
|
||||
description: repository to use as replace target
|
||||
default: github.com/libp2p/go-libp2p
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
name: go-libp2p ping - go test with testground.
|
||||
|
||||
jobs:
|
||||
run-libp2p-test-plans:
|
||||
# If you intend to use this workflow from another repo,
|
||||
# you need to pass the repo and the version:
|
||||
# uses: "libp2p/test-plans/.github/workflows/run-composition.yml@master"
|
||||
uses: "./.github/workflows/run-composition.yml"
|
||||
with:
|
||||
composition_file: "ping/_compositions/go-cross-versions.toml"
|
||||
custom_git_target: ${{ github.event.inputs.custom_git_target }} # nothing or "some-fork/go-libp2p"
|
||||
custom_git_reference: ${{ github.event.inputs.custom_git_reference }} # a git branch
|
||||
testground_endpoint: ${{ github.event.inputs.testground_endpoint }}
|
||||
test_repository: ${{ (github.event.inputs && '') || github.repository }}
|
||||
test_ref: ${{ (github.event.inputs && '') || github.event.pull_request.head.sha || github.sha }}
|
||||
@@ -1,35 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
testground_endpoint:
|
||||
type: string
|
||||
required: false
|
||||
description: testground endpoint
|
||||
custom_git_reference:
|
||||
description: the git commit or branch we're going to use for the custom target
|
||||
required: false
|
||||
type: string
|
||||
custom_git_target:
|
||||
description: the custom git fork url we're going to use for the custom target (github.com/some-fork/rust-libp2p)
|
||||
required: false
|
||||
type: string
|
||||
custom_interop_target:
|
||||
description: in the case of cross-implementation testing, the implementation target (go | rust | nim)
|
||||
required: false
|
||||
type: string
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
name: libp2p ping - go, rust and nim test (latest) with testground.
|
||||
|
||||
jobs:
|
||||
run-ping-latest:
|
||||
uses: "./.github/workflows/run-composition.yml"
|
||||
with:
|
||||
composition_file: "ping/_compositions/all-interop-latest.toml"
|
||||
custom_git_target: ${{ github.event.inputs.custom_git_target }} # nothing or "some-fork/go-libp2p"
|
||||
custom_git_reference: ${{ github.event.inputs.custom_git_reference }} # a git reference
|
||||
custom_interop_target: ${{ github.event.inputs.custom_interop_target }} # go | rust | nim
|
||||
testground_endpoint: ${{ github.event.inputs.testground_endpoint }}
|
||||
test_repository: ${{ (github.event.inputs && '') || github.repository }}
|
||||
test_ref: ${{ (github.event.inputs && '') || github.event.pull_request.head.sha || github.sha }}
|
||||
@@ -1,34 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
testground_endpoint:
|
||||
type: string
|
||||
required: false
|
||||
description: testground endpoint
|
||||
custom_git_reference:
|
||||
type: string
|
||||
required: false
|
||||
description: rust ref
|
||||
custom_git_target:
|
||||
type: string
|
||||
required: false
|
||||
description: repository to use as replace target
|
||||
default: github.com/libp2p/rust-libp2p
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
name: rust-libp2p ping - rust test with testground.
|
||||
|
||||
jobs:
|
||||
run-libp2p-test-plans:
|
||||
# If you intend to use this workflow from another repo,
|
||||
# you need to pass the repo and the version:
|
||||
# uses: "libp2p/test-plans/.github/workflows/run-composition.yml@master"
|
||||
uses: "./.github/workflows/run-composition.yml"
|
||||
with:
|
||||
composition_file: "ping/_compositions/rust-cross-versions.toml"
|
||||
custom_git_target: ${{ github.event.inputs.custom_git_target }} # nothing or "some-fork/go-libp2p"
|
||||
custom_git_reference: ${{ github.event.inputs.custom_git_reference }} # a git reference
|
||||
testground_endpoint: ${{ github.event.inputs.testground_endpoint }}
|
||||
test_repository: ${{ (github.event.inputs && '') || github.repository }}
|
||||
test_ref: ${{ (github.event.inputs && '') || github.event.pull_request.head.sha || github.sha }}
|
||||
@@ -1,45 +0,0 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
testground_endpoint:
|
||||
type: string
|
||||
required: false
|
||||
description: testground endpoint
|
||||
custom_git_reference:
|
||||
description: the git commit or branch we're going to use for the custom target
|
||||
required: false
|
||||
type: string
|
||||
custom_git_target:
|
||||
description: the custom git fork url we're going to use for the custom target (github.com/some-fork/rust-libp2p)
|
||||
required: false
|
||||
type: string
|
||||
custom_interop_target:
|
||||
description: in the case of cross-implementation testing, the implementation target (go | rust | nim)
|
||||
required: false
|
||||
type: string
|
||||
push:
|
||||
pull_request:
|
||||
|
||||
name: libp2p ping - go, rust and nim test (all) with testground.
|
||||
|
||||
jobs:
|
||||
run-ping-latest:
|
||||
uses: "./.github/workflows/run-composition.yml"
|
||||
with:
|
||||
composition_file: "ping/_compositions/all-interop-latest.toml"
|
||||
custom_git_target: ${{ github.event.inputs.custom_git_target }} # nothing or "some-fork/go-libp2p"
|
||||
custom_git_reference: ${{ github.event.inputs.custom_git_reference }} # a git reference
|
||||
custom_interop_target: ${{ github.event.inputs.custom_interop_target }} # go | rust | nim
|
||||
testground_endpoint: ${{ github.event.inputs.testground_endpoint }}
|
||||
test_repository: ${{ (github.event.inputs && '') || github.repository }}
|
||||
test_ref: ${{ (github.event.inputs && '') || github.event.pull_request.head.sha || github.sha }}
|
||||
run-ping-all:
|
||||
uses: "./.github/workflows/run-composition.yml"
|
||||
with:
|
||||
composition_file: "ping/_compositions/all-interop.toml"
|
||||
custom_git_target: ${{ github.event.inputs.custom_git_target }} # nothing or "some-fork/go-libp2p"
|
||||
custom_git_reference: ${{ github.event.inputs.custom_git_reference }} # a git reference
|
||||
custom_interop_target: ${{ github.event.inputs.custom_interop_target }} # go | rust | nim
|
||||
testground_endpoint: ${{ github.event.inputs.testground_endpoint }}
|
||||
test_repository: ${{ (github.event.inputs && '') || github.repository }}
|
||||
test_ref: ${{ (github.event.inputs && '') || github.event.pull_request.head.sha || github.sha }}
|
||||
@@ -1,105 +0,0 @@
|
||||
name: Run composition file with a custom git reference
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
composition_file:
|
||||
description: the workflow we're going to run
|
||||
required: true
|
||||
type: string
|
||||
custom_git_reference:
|
||||
description: the git commit or branch we're going to use for the custom target
|
||||
required: false
|
||||
type: string
|
||||
custom_git_target:
|
||||
description: the custom git fork url we're going to use for the custom target (github.com/some-fork/rust-libp2p)
|
||||
required: false
|
||||
type: string
|
||||
custom_interop_target:
|
||||
description: in the case of cross-implementation testing, the implementation target (go | rust | ...)
|
||||
required: false
|
||||
type: string
|
||||
testground_endpoint:
|
||||
required: false
|
||||
type: string
|
||||
test_repository:
|
||||
required: false
|
||||
type: string
|
||||
test_ref:
|
||||
required: false
|
||||
type: string
|
||||
jobs:
|
||||
run_test:
|
||||
name: Run a test with different versions
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
TEST_PLAN_REPO: ${{ inputs.test_repository || 'libp2p/test-plans' }}
|
||||
TEST_PLAN_BRANCH: ${{ inputs.test_ref || 'master' }}
|
||||
TESTGROUND_ENDPOINT: ${{ inputs.testground_endpoint }}
|
||||
COMPOSITION_FILE: ${{ inputs.composition_file }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: test-plans
|
||||
repository: ${{ env.TEST_PLAN_REPO }}
|
||||
ref: ${{ env.TEST_PLAN_BRANCH }}
|
||||
- name: setup testground
|
||||
uses: ./test-plans/.github/actions/setup-testground
|
||||
- name: Import the plan
|
||||
working-directory: ./test-plans
|
||||
run: |
|
||||
testground plan import --from ./ --name libp2p
|
||||
- name: Resolve the git references
|
||||
if: ${{ inputs.custom_git_reference && inputs.custom_git_target }}
|
||||
id: resolve_reference
|
||||
working-directory: ./test-plans
|
||||
run: |
|
||||
git fetch https://${{ inputs.custom_git_target }} ${{ inputs.custom_git_reference }}
|
||||
SHA=`git log FETCH_HEAD -n 1 --pretty=format:"%H"`
|
||||
echo "::set-output name=custom_git_sha::${SHA}"
|
||||
- name: Build the composition file
|
||||
working-directory: ./test-plans
|
||||
timeout-minutes: 40
|
||||
run: |
|
||||
for i in 1 2 3; do
|
||||
echo "=== Attempt $i ==="
|
||||
testground build composition \
|
||||
-f "${COMPOSITION_FILE}" \
|
||||
--write-artifacts \
|
||||
--wait && exit 0;
|
||||
sleep 10
|
||||
done
|
||||
exit 1
|
||||
env:
|
||||
GitReference: ${{ steps.resolve_reference.outputs.custom_git_sha || inputs.custom_git_reference }}
|
||||
GitTarget: ${{ inputs.custom_git_target }}
|
||||
InteropTarget: ${{ inputs.custom_interop_target }}
|
||||
- name: Run the composition file
|
||||
working-directory: ./test-plans
|
||||
timeout-minutes: 6
|
||||
run: |
|
||||
testground run composition \
|
||||
-f "${COMPOSITION_FILE}" \
|
||||
--metadata-repo "${GITHUB_REPOSITORY}" \
|
||||
--metadata-branch "${GITHUB_REF#refs/heads/}" \
|
||||
--metadata-commit "${GITHUB_SHA}" \
|
||||
--collect-file ./result.tgz \
|
||||
--collect --wait
|
||||
env:
|
||||
GitReference: ${{ steps.resolve_reference.outputs.custom_git_sha || inputs.custom_git_reference }}
|
||||
GitTarget: ${{ inputs.custom_git_target }}
|
||||
InteropTarget: ${{ inputs.custom_interop_target }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: ${{ failure() }}
|
||||
with:
|
||||
name: testground-output
|
||||
path: |
|
||||
~/testground/
|
||||
~/test-plans/result.tgz
|
||||
${{env.COMPOSITION_FILE}}
|
||||
testground.*
|
||||
test-plans/*.out
|
||||
@@ -2,25 +2,12 @@ name: Close and mark stale issue
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
- cron: '0 0 * * *'
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v3
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: 'Oops, seems like we needed more information for this issue, please comment with more details or this issue will be closed in 7 days.'
|
||||
close-issue-message: 'This issue was closed because it is missing author input.'
|
||||
stale-issue-label: 'kind/stale'
|
||||
any-of-labels: 'need/author-input'
|
||||
exempt-issue-labels: 'need/triage,need/community-input,need/maintainer-input,need/maintainers-input,need/analysis,status/blocked,status/in-progress,status/ready,status/deferred,status/inactive'
|
||||
days-before-issue-stale: 6
|
||||
days-before-issue-close: 7
|
||||
enable-statistics: true
|
||||
uses: pl-strflt/.github/.github/workflows/reusable-stale-issue.yml@v0.3
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'transport-interop/**'
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
paths:
|
||||
- 'transport-interop/**'
|
||||
|
||||
name: libp2p transport interop test
|
||||
|
||||
jobs:
|
||||
run-transport-interop:
|
||||
runs-on: ['self-hosted', 'linux', 'x64', '4xlarge'] # https://github.com/pl-strflt/tf-aws-gh-runner/blob/main/runners.tf
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/run-transport-interop-test
|
||||
with:
|
||||
s3-cache-bucket: ${{ vars.S3_LIBP2P_BUILD_CACHE_BUCKET_NAME }}
|
||||
s3-access-key-id: ${{ vars.S3_LIBP2P_BUILD_CACHE_AWS_ACCESS_KEY_ID }}
|
||||
s3-secret-access-key: ${{ secrets.S3_LIBP2P_BUILD_CACHE_AWS_SECRET_ACCESS_KEY }}
|
||||
worker-count: 16
|
||||
build-without-secrets:
|
||||
runs-on: ['self-hosted', 'linux', 'x64', '4xlarge'] # https://github.com/pl-strflt/tf-aws-gh-runner/blob/main/runners.tf
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
# Purposely not using secrets to replicate how forks will behave.
|
||||
- uses: ./.github/actions/run-transport-interop-test
|
||||
with:
|
||||
# It's okay to not run the tests, we only care to check if the tests build without cache.
|
||||
test-filter: '"no test matches this, skip all"'
|
||||
@@ -0,0 +1,79 @@
|
||||
name: Update Badge
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- libp2p transport interop test
|
||||
types:
|
||||
- completed
|
||||
branches:
|
||||
- master
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
BADGE_NAME: Interop Dashboard
|
||||
|
||||
jobs:
|
||||
update-badge:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- id: workflow
|
||||
env:
|
||||
WORKFLOW_PATH: ${{ github.event.workflow.path }}
|
||||
run: echo "name=${WORKFLOW_PATH#.github/workflows/}" >> $GITHUB_OUTPUT
|
||||
- uses: pl-strflt/job-summary-url-action@v1
|
||||
id: metadata
|
||||
with:
|
||||
workflow: ${{ steps.workflow.outputs.name }}
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
run_attempt: ${{ github.event.workflow_run.run_attempt }}
|
||||
job: latest
|
||||
- uses: actions/checkout@v3
|
||||
- id: update
|
||||
uses: actions/github-script@v6
|
||||
env:
|
||||
BADGE_URL: ${{ github.event.workflow.badge_url }}
|
||||
SUMMARY_URL: ${{ steps.metadata.outputs.job_summary_url }}
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs')
|
||||
|
||||
const badgeName = process.env.BADGE_NAME
|
||||
const badgeURL = process.env.BADGE_URL
|
||||
const refName = process.env.GITHUB_REF_NAME
|
||||
const summaryURL = process.env.SUMMARY_URL
|
||||
|
||||
const searchValue = new RegExp(`\\[!\\[${badgeName}\\]\\(.*\\)\\]\\(.*\\)`, 'g')
|
||||
const replaceValue = `[](${summaryURL})`
|
||||
|
||||
console.log(`Searching for: ${searchValue}`)
|
||||
console.log(`To replace it with: ${replaceValue}`)
|
||||
|
||||
const readme = fs.readFileSync('README.md').toString()
|
||||
const updatedReadme = readme.replace(searchValue, replaceValue)
|
||||
|
||||
if (readme !== updatedReadme) {
|
||||
console.log('Updating README')
|
||||
fs.writeFileSync('README.md', updatedReadme)
|
||||
return true
|
||||
} else {
|
||||
console.log('README does not need to be updated')
|
||||
return false
|
||||
}
|
||||
# https://github.com/orgs/community/discussions/26560
|
||||
- if: steps.update.outputs.result == 'true'
|
||||
run: |
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git config user.name "github-actions[bot]"
|
||||
- if: steps.update.outputs.result == 'true'
|
||||
run: |
|
||||
git add README.md
|
||||
git commit -m 'chore: update the link to the interop dashboard [skip ci]'
|
||||
git push
|
||||
@@ -39,3 +39,11 @@ __pycache__/
|
||||
.history
|
||||
|
||||
# End of https://www.gitignore.io/api/go,visualstudiocode
|
||||
|
||||
### NodeJS
|
||||
|
||||
node_modules
|
||||
dist
|
||||
|
||||
# ignore system files
|
||||
.DS_Store
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
# libp2p testing story
|
||||
|
||||
```
|
||||
Date: 2022-10-18
|
||||
Status: In Progress
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes our process for testing interoperability & backward compatibility across libp2p implementations.
|
||||
|
||||
**Why:**
|
||||
|
||||
- Interoperability is a shared concern.
|
||||
- There is no single blessed libp2p reference implementation that we use for conformance testing.
|
||||
- No single maintainer (go|rust|js-libp2p or IPDX) will succeed without everyone's involvement.
|
||||
- We want to share a Testing Story with the world that shows we care about quality & interop.
|
||||
- We want to encourage other implementations to join the testing party.
|
||||
|
||||
**Historical Context:**
|
||||
|
||||
- We completed a “PING” interop test with Testground. It is running in the go-libp2p and rust-libp2p CI pipeline.
|
||||
- It means we “proved” that we can write and run interop tests between versions AND implementations.
|
||||
|
||||
# Libp2p Testing Matrix
|
||||
|
||||
*What do we want to test next?*
|
||||
|
||||
| | go-libp2p | rust-libp2p | js-libp2p (node) | js-libp2p (browser) | jvm-libp2p | nim-libp2p |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| Simple PING [#35][issue-35] | ✅ | ✅ | 🍎 | 🔥 | | |
|
||||
| Circuit Relay | | | | | | |
|
||||
| WebTransport Transport | 🔥 | | 🔥 (depends on https://github.com/libp2p/js-libp2p-webtransport/issues/1) | 🔥 (depends on https://github.com/libp2p/js-libp2p-webtransport/issues/1) | | |
|
||||
| WebRTC Transport | 🔥 (depends on working implementation) | 🔥 (depends on working implementation) | 🔥 (depends on working implementation) | 🔥 (depends on working implementation) | | |
|
||||
| NAT Traversal | | | | | | |
|
||||
| Hole Punching (STUN) | | | | | | |
|
||||
| Identify Protocol | | | | | | |
|
||||
| AutoNAT | | | | | | |
|
||||
| DHT | | | | | | |
|
||||
| QUIC | | | | | | |
|
||||
| Benchmarking? | | | | | | |
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- Anything `js-libp2p` related requires the `ping` test to start
|
||||
- Benchmarking must relate to [Remote Runners][remote-runners]
|
||||
- https://github.com/testground/testground/pull/1425
|
||||
- https://github.com/testground/testground/issues/1392
|
||||
|
||||
**Questions**
|
||||
|
||||
- When do we revisit this table to discuss priorities and add new tests?
|
||||
|
||||
**Legend**
|
||||
|
||||
- ✅ Done
|
||||
- 🚚 In Progress
|
||||
- 🔥 Highest Priority
|
||||
- 🍎 Low-hanging fruit
|
||||
- 🧊 Lowest priority
|
||||
|
||||
# How does libp2p test interoperability?
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
|
||||
## Background
|
||||
The approach outlined below is pretty much what happen with the go|rust-libp2p ping tests in 2022Q3.
|
||||
|
||||
libp2p implementations aren't forced to adopt this approach, but it is the approach that has been taken by some of the longer-lived implementations (go, JS, and rust).
|
||||
|
||||
I (@laurent) haven’t had time to look at [libp2p/interop](https://github.com/libp2p/interop/actions/runs/3021456724) yet. Some information may be missing.
|
||||
|
||||
## 202210 Proposal
|
||||
<aside>
|
||||
1️⃣ Before working on a new feature, the libp2p maintainers come together and agree on a description of the new test plan.*
|
||||
|
||||
</aside>
|
||||
|
||||
**Example:**
|
||||
|
||||
- [IPFS Test Story in libp2p/interop](https://github.com/libp2p/interop/blob/master/pdd/PDD-THE-IPFS-BUNDLE.md)
|
||||
|
||||
**Question:**
|
||||
|
||||
- What should be the format for this description?
|
||||
- Can we live with a rough “here is a general idea of what the test should do”, and let the first implementor figure out the details?
|
||||
- Do we need to make these decisions now? (09-09-2022)
|
||||
|
||||
<aside>
|
||||
2️⃣ *The maintainers agree on which implementation will provide the reference test implementation (go, rust, js, or other). This implementation is written for Testground and merged in the `libp2p/test-plan` repository.*
|
||||
|
||||
</aside>
|
||||
|
||||
**Example:**
|
||||
|
||||
- https://github.com/libp2p/test-plans/pull/9 “add an instructional libp2p ping test plan”
|
||||
|
||||
**Why:**
|
||||
|
||||
- During implementation, some decisions might be taken on how coordination works, details of the tests, etc. It will be easier to clear the path from one implementation.
|
||||
|
||||
<aside>
|
||||
3️⃣ Once this implementation is merged, the reference implementation enables the test in their CI. It will be a “simple” test that runs the current branch against the last N implementations.
|
||||
|
||||
</aside>
|
||||
|
||||
**Example:**
|
||||
|
||||
- https://github.com/libp2p/go-libp2p/pull/1625 “ci: run testground:ping plan on pull requests” in go-libp2p
|
||||
|
||||
<aside>
|
||||
4️⃣ Other implementation will provide their version of the test. And enable a similar test in CI
|
||||
|
||||
</aside>
|
||||
|
||||
**Example:**
|
||||
|
||||
- https://github.com/libp2p/test-plans/pull/26 “ping/rust: introduce rust cross-version test”
|
||||
- https://github.com/libp2p/rust-libp2p/pull/2835 “.github: introduce interop tests” in rust-libp2p
|
||||
|
||||
<aside>
|
||||
5️⃣ Once multiple implementations have been provided and are running the test in CI, each project will add a “big” test workflow in their Release Process.
|
||||
This “big test” runs the test between every known implementation & version.
|
||||
It might be enabled in a nightly job too.
|
||||
|
||||
</aside>
|
||||
|
||||
**Example:**
|
||||
|
||||
- TODO: add the `full` interop test to `go-libp2p` + update their release documentation.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- When do we revisit this scenario to improve and gather feedback?
|
||||
- How do we evaluate progress & success?
|
||||
- When we’re able to use these tests for benchmarking probably.
|
||||
- What’s the plan for the day when everything starts to break?
|
||||
- What’s the plan for the time when we start to crumble under test complexity?
|
||||
- Maintenance
|
||||
- Tests will need updates on new releases, etc.
|
||||
- What are the dependencies between tests?
|
||||
- ex: Does it make sense to test HOLE PUNCHING if you don’t test AUTONAT first?
|
||||
|
||||
## Refs
|
||||
|
||||
- [https://docs.libp2p.io/concepts/protocols/](https://docs.libp2p.io/concepts/protocols/)
|
||||
- libp2p interop in [Interop Repository](https://github.com/libp2p/interop)
|
||||
- [libp2p interop issue](https://github.com/libp2p/interop/issues/70)
|
||||
- [libp2p/interop test plans](https://github.com/libp2p/interop/blob/master/pdd/PDD-THE-IPFS-BUNDLE.md)
|
||||
|
||||
|
||||
[issue-35]: https://github.com/libp2p/test-plans/issues/35
|
||||
[remote-runners]: https://pl-strflt.notion.site/Remote-Runners-c4ad4886c4294fb6a6f8afd9c0c5b73c
|
||||
@@ -1,9 +1,27 @@
|
||||
# Testground test plans for libp2p
|
||||
# Interoperability/end to end test-plans & performance benchmarking for libp2p
|
||||
|
||||
[](https://github.com/vacp2p/libp2p-test-plans/actions/runs/10508587062/attempts/1#summary-29112802717)
|
||||
|
||||
[](http://protocol.ai)
|
||||

|
||||
|
||||
This repository contains Testground test plans for libp2p components.
|
||||
This repository contains:
|
||||
* interoperability tests for libp2p's transport layers modules across different implementations and versions
|
||||
* components to run performance benchmarks for different libp2p implementations
|
||||
|
||||
## Transport Interop
|
||||
### Specs
|
||||
|
||||
Please see our first specification for interoperability tests between transports, multiplexers, and secure channels here: [Transport Interoperability Test Specs](transport-interop/README.md)
|
||||
|
||||
More specs to come soon!
|
||||
|
||||
## History
|
||||
|
||||
These test-plans historically used Testground. To read why we're now using `docker compose` instead please see: [Why we're moving away from Testground](https://github.com/libp2p/test-plans/issues/103)
|
||||
|
||||
## Performance Benchmarking
|
||||
|
||||
Please see the [benchmarking README](./perf#libp2p-performance-benchmarking).
|
||||
|
||||
## Roadmap
|
||||
|
||||
@@ -12,38 +30,6 @@ Our roadmap for test-plans can be found here: https://github.com/libp2p/test-pla
|
||||
It represents current projects the test-plans maintainers are focused on and provides an estimation of completion targets.
|
||||
It is complementary to those of [go-libp2p](https://github.com/libp2p/go-libp2p/blob/master/ROADMAP.md), [rust-libp2p](https://github.com/libp2p/rust-libp2p/blob/master/ROADMAP.md), [js-libp2p](https://github.com/libp2p/js-libp2p/blob/master/ROADMAP.md), and the [overarching libp2p project roadmap](https://github.com/libp2p/specs/blob/master/ROADMAP.md).
|
||||
|
||||
## How to add a new version to ping/go
|
||||
|
||||
When a new version of libp2p is released, we want to make it permanent in the `ping/go` test folder.
|
||||
|
||||
1. In the `ping/_compositions/go.toml` file,
|
||||
- copy the `[master]` section and turn it into a `[[groups]]` item
|
||||
- update the `[master]` section with the future version
|
||||
2. In the `ping/go` folder,
|
||||
- Add a new compatibility shim in `compat/` if needed, or add your new selector to the latest shim (see `compat/libp2p.v0.17.go` for example).
|
||||
- Create the new mod and sum files (`go.v0.21.mod` for example). Assuming you're updating from `v$A` to `v$B`, a simple way to do this is to:
|
||||
- `cp go.v$A.mod go.v$B.mod; cp go.v$A.sum go.v$B.sum`
|
||||
- `ln -s go.v$B.mod go.mod; ln -s go.v$B.sum go.sum` (you may also use this for local development, these files are ignored by git)
|
||||
- update the `go-libp2p` version, go version, and update the code if needed.
|
||||
- then `go get -tags v$B && go mod tidy`
|
||||
3. Run the test on your machine
|
||||
- Do once, from the test-plans root: import the test-plans with `testground plan import --from ./ --name libp2p`
|
||||
- Run the test with `testground run composition -f ping/_compositions/go-cross-versions.toml --wait`
|
||||
|
||||
## How to add a new version to ping/rust
|
||||
|
||||
When a new version of libp2p is released, we want to make it permanent in the `ping/rust` test folder.
|
||||
|
||||
1. In the `ping/_compositions/rust.toml` file,
|
||||
- Copy the latest `[[groups]]` section and update it's `Id` and `BinaryName` accordingly.
|
||||
2. In the `ping/rust` folder,
|
||||
- `Cargo.toml`: Add the newly released version as a crates.io dependency.
|
||||
- `Cargo.toml`: Update the `Next release` dependency to the latest `master` SHA.
|
||||
- `src/bin`: Add a new binary with the next released version.
|
||||
3. Run the test on your machine
|
||||
- Do once, from the test-plans root: import the test-plans with `testground plan import --from ./ --name libp2p`
|
||||
- Run the test with `testground run composition -f ping/_compositions/rust-cross-versions.toml --wait`
|
||||
|
||||
## License
|
||||
|
||||
Dual-licensed: [MIT](./LICENSE-MIT), [Apache Software License v2](./LICENSE-APACHE), by way of the
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
# `Plan:` The go-libp2p DHT behaves
|
||||
|
||||

|
||||
|
||||
IPFS can safely rely on the latest DHT upgrades by running go-libp2p DHT tests directly
|
||||
|
||||
## What is being optimized (min/max, reach)
|
||||
|
||||
- (Minimize) Numbers of peers dialed to as part of the call
|
||||
- (Minimize) Number of failed dials to peers
|
||||
- (Minimize) Time that it took for the test
|
||||
- (Minimize) Routing efficiency (# of hops (XOR metric should decrease at every step))
|
||||
|
||||
## Plan Parameters
|
||||
|
||||
- **Network Parameters**
|
||||
- `instances` - Number of nodes that are spawned for the test (from 10 to 1000000)
|
||||
- **Image Parameters**
|
||||
- Single Image - The go-libp2p commit that is being tested
|
||||
- Image Resources CPU & Ram
|
||||
|
||||
## Tests
|
||||
|
||||
### `Test:` Find Peers
|
||||
|
||||
- **Test Parameters**
|
||||
- `auto-refresh` - Enable autoRefresh (equivalent to running random-walk multiple times automatically) (true/false, default: false)
|
||||
- `random-walk` - Run random-walk manually 5 times (true/false, default: false)
|
||||
- `bucket-size` - Kademlia DHT bucket size (default: 20)
|
||||
- `n-find-peers` - Number of times a Find Peers call is executed from each node (picking another node PeerId at random that is not yet in our Routing table) (default: 1)
|
||||
- **Narrative**
|
||||
- **Warm up**
|
||||
- All nodes boot up
|
||||
- Each node as it boots up, connects to the node that previously joined
|
||||
- Nodes ran 5 random-walk queries to populate their Routing Tables
|
||||
- **Act I**
|
||||
- Each node calls Find Peers `n-find-peers` times
|
||||
|
||||
### `Test:` Find Providers
|
||||
|
||||
- **Test Parameters**
|
||||
- `auto-refresh` - Enable autoRefresh (equivalent to running random-walk multiple times automatically) (true/false, default: false)
|
||||
- `random-walk` - Run random-walk manually 5 times (true/false, default: false)
|
||||
- `bucket-size` - Kademlia DHT bucket size (default: 20)
|
||||
- `p-providing` - Percentage of nodes providing a record
|
||||
- `p-resolving` - Percentage of nodes trying to resolve the network a record
|
||||
- `p-failing` - Percentage of nodes trying to resolve a record that hasn't been provided
|
||||
- **Narrative**
|
||||
- **Warm up**
|
||||
- All nodes boot up
|
||||
- Each node as it boots up, connects to the node that previously joined
|
||||
- Nodes ran 5 random-walk queries to populate their Routing Tables
|
||||
- **Act I**
|
||||
- `p-providing` of the nodes provide a record and store its key on redis
|
||||
- **Act II**
|
||||
- `p-resolving` of the nodes attempt to resolve the records provided before
|
||||
- `p-failing` of the nodes attempt to resolve records that do not exist
|
||||
|
||||
|
||||
### `Test:` Provide Stress
|
||||
|
||||
- **Test Parameters**
|
||||
- `auto-refresh` - Enable autoRefresh (equivalent to running random-walk multiple times automatically) (true/false, default: false)
|
||||
- `random-walk` - Run random-walk manually 5 times (true/false, default: false)
|
||||
- `bucket-size` - Kademlia DHT bucket size (default: 20)
|
||||
- `n-provides` - The number of provide calls that are done by each node
|
||||
- `i-provides` - The interval between each provide call (in seconds)
|
||||
- **Narrative**
|
||||
- **Warm up**
|
||||
- All nodes boot up
|
||||
- Each node as it boots up, connects to the node that previously joined
|
||||
- Nodes ran 5 random-walk queries to populate their Routing Tables
|
||||
- **Act I**
|
||||
- Each node calls Provide for `i-provides` until it reaches a total of `n-provides`
|
||||
@@ -1,170 +0,0 @@
|
||||
[metadata]
|
||||
name = "all-balsam"
|
||||
author = "adin"
|
||||
|
||||
[global]
|
||||
plan = "dht"
|
||||
case = "all"
|
||||
total_instances = 1000
|
||||
builder = "docker:go"
|
||||
runner = "cluster:k8s"
|
||||
[global.build_config]
|
||||
push_registry = true
|
||||
registry_type = "aws"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-provider-small"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-provider-medium"
|
||||
[groups.instances]
|
||||
count = 15
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-provider-large"
|
||||
[groups.instances]
|
||||
count = 100
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-provider-small"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-provider-medium"
|
||||
[groups.instances]
|
||||
count = 15
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-provider-large"
|
||||
[groups.instances]
|
||||
count = 100
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-searcher"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-searcher"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-passive"
|
||||
[groups.instances]
|
||||
count = 495
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-passive"
|
||||
[groups.instances]
|
||||
count = 250
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-bs"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bootstrapper = "true"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
timeout_secs = "600"
|
||||
@@ -1,205 +0,0 @@
|
||||
[metadata]
|
||||
name = "all-both"
|
||||
author = "adin"
|
||||
|
||||
[global]
|
||||
plan = "dht"
|
||||
case = "all"
|
||||
total_instances = 1000
|
||||
builder = "docker:go"
|
||||
runner = "cluster:k8s"
|
||||
[global.build_config]
|
||||
push_registry = true
|
||||
registry_type = "aws"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-provider"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "4"
|
||||
latency = "100"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-searcher"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "5"
|
||||
latency = "100"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-passive"
|
||||
[groups.instances]
|
||||
count = 780
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "6"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
undialable = "false"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-provider"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "7"
|
||||
latency = "100"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
undialable = "false"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-searcher"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "8"
|
||||
latency = "100"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
undialable = "false"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-passive"
|
||||
[groups.instances]
|
||||
count = 185
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
group_order = "1"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-provider"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
group_order = "2"
|
||||
latency = "100"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-searcher"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
group_order = "3"
|
||||
latency = "100"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-bs"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bootstrapper = "true"
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
group_order = "0"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
@@ -1,169 +0,0 @@
|
||||
[metadata]
|
||||
name = "all-cypress"
|
||||
author = "adin"
|
||||
|
||||
[global]
|
||||
plan = "dht"
|
||||
case = "all"
|
||||
total_instances = 1170
|
||||
builder = "docker:go"
|
||||
runner = "cluster:k8s"
|
||||
[global.build_config]
|
||||
push_registry = true
|
||||
registry_type = "aws"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-passive"
|
||||
[groups.instances]
|
||||
count = 1020
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "1"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-provider-small"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "4"
|
||||
latency = "100"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-provider-medium"
|
||||
[groups.instances]
|
||||
count = 15
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "3"
|
||||
latency = "100"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-provider-large"
|
||||
[groups.instances]
|
||||
count = 100
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "2"
|
||||
latency = "100"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-searcher"
|
||||
[groups.instances]
|
||||
count = 25
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "5"
|
||||
latency = "100"
|
||||
n_find_peers = "5"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-bs"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bootstrapper = "true"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "0"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
@@ -1,89 +0,0 @@
|
||||
[metadata]
|
||||
name = "bs-network"
|
||||
author = "adin"
|
||||
|
||||
[global]
|
||||
plan = "dht"
|
||||
case = "bootstrap-network"
|
||||
total_instances = 100
|
||||
builder = "docker:go"
|
||||
runner = "cluster:k8s"
|
||||
[global.build_config]
|
||||
push_registry = true
|
||||
registry_type = "aws"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-passive"
|
||||
[groups.instances]
|
||||
count = 65
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "1"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-last"
|
||||
[groups.instances]
|
||||
count = 30
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "2"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-bs"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bootstrapper = "true"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "0"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
@@ -1,43 +0,0 @@
|
||||
## THIS IS AN EXAMPLE COMPOSITION
|
||||
##
|
||||
## It performs a run of the dht/find-peers test case, with 100 instances:
|
||||
##
|
||||
## * 10 of them are boostrappers, with upstream dependency overrides.
|
||||
## * 45% are DHT clients.
|
||||
## * 45% are DHT servers.
|
||||
##
|
||||
[metadata]
|
||||
name = "find-peers-01"
|
||||
author = "raulk"
|
||||
|
||||
[global]
|
||||
plan = "dht"
|
||||
case = "find-peers"
|
||||
builder = "exec:go"
|
||||
runner = "local:exec"
|
||||
|
||||
total_instances = 50
|
||||
|
||||
[[groups]]
|
||||
id = "bootstrappers"
|
||||
instances = { count = 1 }
|
||||
|
||||
[groups.build]
|
||||
selectors = ["foo"]
|
||||
dependencies = [
|
||||
{ module = "github.com/libp2p/go-libp2p-kad-dht", version = "995fee9e5345fdd7c151a5fe871252262db4e788"},
|
||||
{ module = "github.com/libp2p/go-libp2p", version = "76944c4fc848530530f6be36fb22b70431ca506c"},
|
||||
]
|
||||
|
||||
[groups.run]
|
||||
test_params = { random_walk = "true", n_bootstrap = "1" }
|
||||
|
||||
[[groups]]
|
||||
id = "peers"
|
||||
instances = { count = 49 }
|
||||
|
||||
[groups.run]
|
||||
test_params = { random_walk = "true", n_bootstrap = "1" }
|
||||
|
||||
[groups.build]
|
||||
selectors = ["bar", "bee"]
|
||||
@@ -1,172 +0,0 @@
|
||||
[metadata]
|
||||
name = "find-provs"
|
||||
author = "adin"
|
||||
|
||||
[global]
|
||||
plan = "dht"
|
||||
case = "find-providers"
|
||||
total_instances = 1000
|
||||
builder = "docker:go"
|
||||
runner = "cluster:k8s"
|
||||
[global.build_config]
|
||||
push_registry = true
|
||||
registry_type = "aws"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-provider-small"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-provider-medium"
|
||||
[groups.instances]
|
||||
count = 15
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-provider-large"
|
||||
[groups.instances]
|
||||
count = 100
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-provider-small"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-provider-medium"
|
||||
[groups.instances]
|
||||
count = 15
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-provider-large"
|
||||
[groups.instances]
|
||||
count = 100
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-searcher"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-searcher"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-passive"
|
||||
[groups.instances]
|
||||
count = 495
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-passive"
|
||||
[groups.instances]
|
||||
count = 250
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-bs"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bootstrapper = "true"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
timeout_secs = "600"
|
||||
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
[metadata]
|
||||
name = "find-provs"
|
||||
author = "adin"
|
||||
|
||||
[global]
|
||||
plan = "dht"
|
||||
case = "find-providers"
|
||||
total_instances = 1000
|
||||
builder = "docker:go"
|
||||
runner = "cluster:k8s"
|
||||
[global.build_config]
|
||||
push_registry = true
|
||||
registry_type = "aws"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-provider"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "4"
|
||||
latency = "100"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-searcher"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "5"
|
||||
latency = "100"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-passive"
|
||||
[groups.instances]
|
||||
count = 780
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "6"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
undialable = "false"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-provider"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "7"
|
||||
latency = "100"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
undialable = "false"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-searcher"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "8"
|
||||
latency = "100"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
undialable = "false"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-passive"
|
||||
[groups.instances]
|
||||
count = 185
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
group_order = "1"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-provider"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
group_order = "2"
|
||||
latency = "100"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-searcher"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
group_order = "3"
|
||||
latency = "100"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-bs"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bootstrapper = "true"
|
||||
bs_strategy = "7"
|
||||
bucket_size = "10"
|
||||
group_order = "0"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
@@ -1,189 +0,0 @@
|
||||
[metadata]
|
||||
name = "find-provs"
|
||||
author = "adin"
|
||||
|
||||
[global]
|
||||
plan = "dht"
|
||||
case = "find-providers"
|
||||
total_instances = 150
|
||||
builder = "docker:go"
|
||||
runner = "local:docker"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-provider"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "3"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "4"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-undialable-searcher"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "3"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "5"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
undialable = "true"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-passive"
|
||||
[groups.instances]
|
||||
count = 80
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "3"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "6"
|
||||
timeout_secs = "600"
|
||||
undialable = "false"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-provider"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "3"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "7"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
undialable = "false"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam-dialable-searcher"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["balsam"]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bs_strategy = "3"
|
||||
bucket_size = "10"
|
||||
expect_dht = "false"
|
||||
group_order = "8"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
undialable = "false"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-passive"
|
||||
[groups.instances]
|
||||
count = 35
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
bs_strategy = "3"
|
||||
bucket_size = "10"
|
||||
group_order = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-provider"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
bs_strategy = "3"
|
||||
bucket_size = "10"
|
||||
group_order = "2"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-searcher"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
bs_strategy = "3"
|
||||
bucket_size = "10"
|
||||
group_order = "3"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-bs"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
bootstrapper = "true"
|
||||
bs_strategy = "1"
|
||||
bucket_size = "10"
|
||||
group_order = "0"
|
||||
timeout_secs = "600"
|
||||
@@ -1,168 +0,0 @@
|
||||
[metadata]
|
||||
name = "find-provs"
|
||||
author = "adin"
|
||||
|
||||
[global]
|
||||
plan = "dht"
|
||||
case = "find-providers"
|
||||
total_instances = 1170
|
||||
builder = "docker:go"
|
||||
runner = "cluster:k8s"
|
||||
[global.build_config]
|
||||
push_registry = true
|
||||
registry_type = "aws"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-passive"
|
||||
[groups.instances]
|
||||
count = 1020
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "1"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-provider-small"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "4"
|
||||
latency = "100"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-provider-medium"
|
||||
[groups.instances]
|
||||
count = 15
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "3"
|
||||
latency = "100"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-provider-large"
|
||||
[groups.instances]
|
||||
count = 100
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "2"
|
||||
latency = "100"
|
||||
record_count = "1"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-searcher"
|
||||
[groups.instances]
|
||||
count = 25
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "5"
|
||||
latency = "100"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-bs"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bootstrapper = "true"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "0"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
@@ -1,54 +0,0 @@
|
||||
[metadata]
|
||||
name = "find-provs"
|
||||
author = "adin"
|
||||
|
||||
[global]
|
||||
plan = "dht"
|
||||
case = "find-providers"
|
||||
total_instances = 100
|
||||
builder = "docker:go"
|
||||
runner = "cluster:k8s"
|
||||
[global.build_config]
|
||||
push_registry = true
|
||||
registry_type = "aws"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam"
|
||||
[groups.instances]
|
||||
count = 100
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bucket_size = "4"
|
||||
client_mode = "false"
|
||||
f_undialable = "0.9"
|
||||
n_bootstrap = "-4"
|
||||
n_providing = "1"
|
||||
record_count = "5"
|
||||
timeout_secs = "2000"
|
||||
autonat_ok = "false"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress"
|
||||
[groups.instances]
|
||||
count = 0
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "v0.4.2-0.20200204202258-35d3e4a5d43e"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-autonat"
|
||||
version = "v0.1.2-0.20200204200147-902af8cb7b6a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bucket_size = "4"
|
||||
client_mode = "false"
|
||||
f_undialable = "0.9"
|
||||
n_bootstrap = "-4"
|
||||
n_providing = "1"
|
||||
record_count = "5"
|
||||
timeout_secs = "2000"
|
||||
@@ -1,52 +0,0 @@
|
||||
[metadata]
|
||||
name = "find-provs"
|
||||
author = "adin"
|
||||
|
||||
[global]
|
||||
plan = "dht"
|
||||
case = "find-providers"
|
||||
total_instances = 150
|
||||
builder = "docker:go"
|
||||
runner = "local:docker"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam"
|
||||
[groups.instances]
|
||||
count = 0
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bucket_size = "4"
|
||||
client_mode = "false"
|
||||
f_undialable = "0.0"
|
||||
n_bootstrap = "-4"
|
||||
n_paths = "10"
|
||||
n_providing = "1"
|
||||
record_count = "5"
|
||||
timeout_secs = "200"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress"
|
||||
[groups.instances]
|
||||
count = 0
|
||||
percentage = 1.0
|
||||
[groups.build]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "v0.4.2-0.20200204202258-35d3e4a5d43e"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-autonat"
|
||||
version = "v0.1.2-0.20200204200147-902af8cb7b6a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bucket_size = "4"
|
||||
client_mode = "false"
|
||||
f_undialable = "0.9"
|
||||
n_bootstrap = "-4"
|
||||
n_paths = "0"
|
||||
n_providing = "1"
|
||||
record_count = "5"
|
||||
timeout_secs = "200"
|
||||
@@ -1,31 +0,0 @@
|
||||
[metadata]
|
||||
name = "gcp"
|
||||
author = "adin"
|
||||
|
||||
[global]
|
||||
plan = "dht"
|
||||
case = "get-closest-peers"
|
||||
total_instances = 400
|
||||
builder = "docker:go"
|
||||
runner = "cluster:k8s"
|
||||
[global.build_config]
|
||||
push_registry = true
|
||||
registry_type = "aws"
|
||||
|
||||
[[groups]]
|
||||
id = "balsam"
|
||||
[groups.instances]
|
||||
count = 0
|
||||
percentage = 1.0
|
||||
[groups.build]
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
bucket_size = "10"
|
||||
client_mode = "false"
|
||||
f_undialable = "0.5"
|
||||
n_bootstrap = "-4"
|
||||
n_find_peers = "5"
|
||||
n_providing = "1"
|
||||
record_count = "5"
|
||||
timeout_secs = "600"
|
||||
autonat_ok = "false"
|
||||
@@ -1,91 +0,0 @@
|
||||
[metadata]
|
||||
name = "gcp"
|
||||
author = "adin"
|
||||
|
||||
[global]
|
||||
plan = "dht"
|
||||
case = "get-closest-peers"
|
||||
total_instances = 1000
|
||||
builder = "docker:go"
|
||||
runner = "cluster:k8s"
|
||||
[global.build_config]
|
||||
push_registry = true
|
||||
registry_type = "aws"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-passive"
|
||||
[groups.instances]
|
||||
count = 975
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "1"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-searcher"
|
||||
[groups.instances]
|
||||
count = 20
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "2"
|
||||
latency = "100"
|
||||
record_count = "1"
|
||||
search_records = "true"
|
||||
timeout_secs = "600"
|
||||
|
||||
[[groups]]
|
||||
id = "cypress-bs"
|
||||
[groups.instances]
|
||||
count = 5
|
||||
percentage = 0.0
|
||||
[groups.build]
|
||||
selectors = ["cypress"]
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-kad-dht"
|
||||
version = "180be07b8303d536e39809bc39c58be5407fedd9"
|
||||
|
||||
[[groups.build.dependencies]]
|
||||
module = "github.com/libp2p/go-libp2p-xor"
|
||||
version = "df24f5b04bcbdc0059b27989163a6090f4f6dc7a"
|
||||
[groups.run]
|
||||
[groups.run.test_params]
|
||||
alpha = "6"
|
||||
beta = "3"
|
||||
bootstrapper = "true"
|
||||
bs_strategy = "6"
|
||||
bucket_size = "10"
|
||||
group_order = "0"
|
||||
latency = "100"
|
||||
timeout_secs = "600"
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
module github.com/libp2p/test-plans/dht
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/gogo/protobuf v1.3.1
|
||||
github.com/ipfs/go-cid v0.0.3
|
||||
github.com/ipfs/go-datastore v0.4.1
|
||||
github.com/ipfs/go-ds-leveldb v0.4.1
|
||||
github.com/ipfs/go-ipfs-util v0.0.1
|
||||
github.com/ipfs/go-ipns v0.0.2
|
||||
github.com/libp2p/go-libp2p v0.4.2
|
||||
github.com/libp2p/go-libp2p-connmgr v0.2.1
|
||||
github.com/libp2p/go-libp2p-core v0.3.0
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.4.1
|
||||
github.com/libp2p/go-libp2p-kbucket v0.2.2
|
||||
github.com/libp2p/go-libp2p-swarm v0.2.3-0.20200210151353-6e99a7602774
|
||||
github.com/libp2p/go-libp2p-transport-upgrader v0.1.1
|
||||
github.com/libp2p/go-libp2p-xor v0.0.0-20200330160054-7c8ff159b6e9
|
||||
github.com/libp2p/go-tcp-transport v0.1.1
|
||||
github.com/mattn/go-colorable v0.1.2 // indirect
|
||||
github.com/mattn/go-isatty v0.0.9 // indirect
|
||||
github.com/multiformats/go-multiaddr v0.2.0
|
||||
github.com/multiformats/go-multiaddr-net v0.1.2
|
||||
github.com/opentracing/opentracing-go v1.1.0 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/testground/sdk-go v0.1.1
|
||||
go.uber.org/zap v1.14.1
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
|
||||
)
|
||||
|
||||
//replace github.com/libp2p/go-libp2p-swarm => ../../../../libp2p/go-libp2p-swarm
|
||||
//replace github.com/libp2p/go-libp2p-autonat => github.com/willscott/go-libp2p-autonat v0.1.2-0.20200310184838-ce79942134d7
|
||||
//replace github.com/libp2p/go-libp2p-autonat-svc => github.com/libp2p/go-libp2p-autonat-svc v0.1.1-0.20200310185508-f21360000124
|
||||
//replace github.com/libp2p/go-libp2p-kad-dht => ../../../../libp2p/go-libp2p-kad-dht
|
||||
//replace github.com/libp2p/go-libp2p-kad-dht => github.com/libp2p/go-libp2p-kad-dht v0.5.2-0.20200310202241-7ada018b2a13
|
||||
//replace github.com/libp2p/go-libp2p => github.com/libp2p/go-libp2p v0.6.1-0.20200310185355-89c193e0ca37
|
||||
//replace github.com/libp2p/go-libp2p-core => github.com/libp2p/go-libp2p-core v0.5.0
|
||||
-502
@@ -1,502 +0,0 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/btcsuite/btcd v0.0.0-20190213025234-306aecffea32/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
|
||||
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
|
||||
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
|
||||
github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
|
||||
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
|
||||
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
|
||||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgraph-io/badger v1.5.5-0.20190226225317-8115aed38f8f/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=
|
||||
github.com/dgraph-io/badger v1.6.0-rc1/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
|
||||
github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
|
||||
github.com/dgryski/go-farm v0.0.0-20190104051053-3adb47b1fb0f/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-redis/redis/v7 v7.2.0 h1:CrCexy/jYWZjW0AyVoHlcJUeZN19VWlbepTh1Vq6dJs=
|
||||
github.com/go-redis/redis/v7 v7.2.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
|
||||
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=
|
||||
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huin/goupnp v1.0.0 h1:wg75sLpL6DZqwHQN6E1Cfk6mtfzS45z8OV+ic+DtHRo=
|
||||
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
|
||||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
|
||||
github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
|
||||
github.com/ipfs/go-cid v0.0.3 h1:UIAh32wymBpStoe83YCzwVQQ5Oy/H0FdxvUS6DJDzms=
|
||||
github.com/ipfs/go-cid v0.0.3/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM=
|
||||
github.com/ipfs/go-datastore v0.0.1/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
|
||||
github.com/ipfs/go-datastore v0.1.0/go.mod h1:d4KVXhMt913cLBEI/PXAy6ko+W7e9AhyAKBGh803qeE=
|
||||
github.com/ipfs/go-datastore v0.1.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw=
|
||||
github.com/ipfs/go-datastore v0.3.1/go.mod h1:w38XXW9kVFNp57Zj5knbKWM2T+KOZCGDRVNdgPHtbHw=
|
||||
github.com/ipfs/go-datastore v0.4.1 h1:W4ZfzyhNi3xmuU5dQhjfuRn/wFuqEE1KnOmmQiOevEY=
|
||||
github.com/ipfs/go-datastore v0.4.1/go.mod h1:SX/xMIKoCszPqp+z9JhPYCmoOoXTvaa13XEbGtsFUhA=
|
||||
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
|
||||
github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=
|
||||
github.com/ipfs/go-ds-badger v0.0.5/go.mod h1:g5AuuCGmr7efyzQhLL8MzwqcauPojGPUaHzfGTzuE3s=
|
||||
github.com/ipfs/go-ds-badger v0.0.7/go.mod h1:qt0/fWzZDoPW6jpQeqUjR5kBfhDNB65jd9YlmAvpQBk=
|
||||
github.com/ipfs/go-ds-leveldb v0.0.1/go.mod h1:feO8V3kubwsEF22n0YRQCffeb79OOYIykR4L04tMOYc=
|
||||
github.com/ipfs/go-ds-leveldb v0.1.0/go.mod h1:hqAW8y4bwX5LWcCtku2rFNX3vjDZCy5LZCg+cSZvYb8=
|
||||
github.com/ipfs/go-ds-leveldb v0.4.1 h1:zaoLcP8zs4Aj9k8fA4cowyOyNBIvy9Dnt6hf7mHRY7s=
|
||||
github.com/ipfs/go-ds-leveldb v0.4.1/go.mod h1:jpbku/YqBSsBc1qgME8BkWS4AxzF2cEu1Ii2r79Hh9s=
|
||||
github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
|
||||
github.com/ipfs/go-ipfs-util v0.0.1 h1:Wz9bL2wB2YBJqggkA4dD7oSmqB4cAnpNbGrlHJulv50=
|
||||
github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc=
|
||||
github.com/ipfs/go-ipns v0.0.2 h1:oq4ErrV4hNQ2Eim257RTYRgfOSV/s8BDaf9iIl4NwFs=
|
||||
github.com/ipfs/go-ipns v0.0.2/go.mod h1:WChil4e0/m9cIINWLxZe1Jtf77oz5L05rO2ei/uKJ5U=
|
||||
github.com/ipfs/go-log v0.0.1 h1:9XTUN/rW64BCG1YhPK9Hoy3q8nr4gOmHHBpgFdfw6Lc=
|
||||
github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
|
||||
github.com/ipfs/go-todocounter v0.0.2 h1:9UBngSQhylg2UDcxSAtpkT+rEWFr26hDPXVStE8LFyc=
|
||||
github.com/ipfs/go-todocounter v0.0.2/go.mod h1:l5aErvQc8qKE2r7NDMjmq5UNAvuZy0rC8BHOplkWvZ4=
|
||||
github.com/jackpal/gateway v1.0.5 h1:qzXWUJfuMdlLMtt0a3Dgt+xkWQiA5itDEITVJtuSwMc=
|
||||
github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
|
||||
github.com/jackpal/go-nat-pmp v1.0.1 h1:i0LektDkO1QlrTm/cSuP+PyBCDnYvjPLGl4LdWEMiaA=
|
||||
github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/jbenet/go-cienv v0.0.0-20150120210510-1bb1476777ec/go.mod h1:rGaEvXB4uRSZMmzKNLoXvTu1sfx+1kv/DojUlPrSZGs=
|
||||
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
|
||||
github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2 h1:vhC1OXXiT9R2pczegwz6moDvuRpggaroAXhPIseh57A=
|
||||
github.com/jbenet/go-temp-err-catcher v0.0.0-20150120210811-aac704a3f4f2/go.mod h1:8GXXJV31xl8whumTzdZsTt3RnUIiPqzkyf7mxToRCMs=
|
||||
github.com/jbenet/goprocess v0.0.0-20160826012719-b497e2f366b8/go.mod h1:Ly/wlsjFq/qrU3Rar62tu1gASgGw6chQbSh/XgIIXCY=
|
||||
github.com/jbenet/goprocess v0.1.3 h1:YKyIEECS/XvcfHtBzxtjBBbWK+MbvA6dG8ASiqwvr10=
|
||||
github.com/jbenet/goprocess v0.1.3/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d h1:68u9r4wEvL3gYg2jvAOgROwZ3H+Y3hIDk4tbbmIjcYQ=
|
||||
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/libp2p/go-addr-util v0.0.1 h1:TpTQm9cXVRVSKsYbgQ7GKc3KbbHVTnbostgGaDEP+88=
|
||||
github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ=
|
||||
github.com/libp2p/go-buffer-pool v0.0.1/go.mod h1:xtyIz9PMobb13WaxR6Zo1Pd1zXJKYg0a8KiIvDp3TzQ=
|
||||
github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=
|
||||
github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=
|
||||
github.com/libp2p/go-conn-security-multistream v0.1.0 h1:aqGmto+ttL/uJgX0JtQI0tD21CIEy5eYd1Hlp0juHY0=
|
||||
github.com/libp2p/go-conn-security-multistream v0.1.0/go.mod h1:aw6eD7LOsHEX7+2hJkDxw1MteijaVcI+/eP2/x3J1xc=
|
||||
github.com/libp2p/go-eventbus v0.1.0 h1:mlawomSAjjkk97QnYiEmHsLu7E136+2oCWSHRUvMfzQ=
|
||||
github.com/libp2p/go-eventbus v0.1.0/go.mod h1:vROgu5cs5T7cv7POWlWxBaVLxfSegC5UGQf8A2eEmx4=
|
||||
github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZxBdp967ls1g+k8=
|
||||
github.com/libp2p/go-flow-metrics v0.0.2/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
|
||||
github.com/libp2p/go-flow-metrics v0.0.3 h1:8tAs/hSdNvUiLgtlSy3mxwxWP4I9y/jlkPFT7epKdeM=
|
||||
github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
|
||||
github.com/libp2p/go-libp2p v0.4.2 h1:p0cthB0jDNHO4gH2HzS8/nAMMXbfUlFHs0jwZ4U+F2g=
|
||||
github.com/libp2p/go-libp2p v0.4.2/go.mod h1:MNmgUxUw5pMsdOzMlT0EE7oKjRasl+WyVwM0IBlpKgQ=
|
||||
github.com/libp2p/go-libp2p-autonat v0.1.1 h1:WLBZcIRsjZlWdAZj9CiBSvU2wQXoUOiS1Zk1tM7DTJI=
|
||||
github.com/libp2p/go-libp2p-autonat v0.1.1/go.mod h1:OXqkeGOY2xJVWKAGV2inNF5aKN/djNA3fdpCWloIudE=
|
||||
github.com/libp2p/go-libp2p-blankhost v0.1.1/go.mod h1:pf2fvdLJPsC1FsVrNP3DUUvMzUts2dsLLBEpo1vW1ro=
|
||||
github.com/libp2p/go-libp2p-blankhost v0.1.4/go.mod h1:oJF0saYsAXQCSfDq254GMNmLNz6ZTHTOvtF4ZydUvwU=
|
||||
github.com/libp2p/go-libp2p-circuit v0.1.4 h1:Phzbmrg3BkVzbqd4ZZ149JxCuUWu2wZcXf/Kr6hZJj8=
|
||||
github.com/libp2p/go-libp2p-circuit v0.1.4/go.mod h1:CY67BrEjKNDhdTk8UgBX1Y/H5c3xkAcs3gnksxY7osU=
|
||||
github.com/libp2p/go-libp2p-connmgr v0.2.1 h1:1ed0HFhCb39sIMK7QYgRBW0vibBBqFQMs4xt9a9AalY=
|
||||
github.com/libp2p/go-libp2p-connmgr v0.2.1/go.mod h1:JReKEFcgzSHKT9lL3rhYcUtXBs9uMIiMKJGM1tl3xJE=
|
||||
github.com/libp2p/go-libp2p-core v0.0.1/go.mod h1:g/VxnTZ/1ygHxH3dKok7Vno1VfpvGcGip57wjTU4fco=
|
||||
github.com/libp2p/go-libp2p-core v0.0.4/go.mod h1:jyuCQP356gzfCFtRKyvAbNkyeuxb7OlyhWZ3nls5d2I=
|
||||
github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI=
|
||||
github.com/libp2p/go-libp2p-core v0.2.2/go.mod h1:8fcwTbsG2B+lTgRJ1ICZtiM5GWCWZVoVrLaDRvIRng0=
|
||||
github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=
|
||||
github.com/libp2p/go-libp2p-core v0.2.5/go.mod h1:6+5zJmKhsf7yHn1RbmYDu08qDUpIUxGdqHuEZckmZOA=
|
||||
github.com/libp2p/go-libp2p-core v0.3.0 h1:F7PqduvrztDtFsAa/bcheQ3azmNo+Nq7m8hQY5GiUW8=
|
||||
github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw=
|
||||
github.com/libp2p/go-libp2p-crypto v0.1.0/go.mod h1:sPUokVISZiy+nNuTTH/TY+leRSxnFj/2GLjtOTW90hI=
|
||||
github.com/libp2p/go-libp2p-discovery v0.1.0 h1:j+R6cokKcGbnZLf4kcNwpx6mDEUPF3N6SrqMymQhmvs=
|
||||
github.com/libp2p/go-libp2p-discovery v0.1.0/go.mod h1:4F/x+aldVHjHDHuX85x1zWoFTGElt8HnoDzwkFZm29g=
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.4.1 h1:N++/IVD7KemtNqwoqBLsmpc1PxROW1cxi81ja+wsJCg=
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.4.1/go.mod h1:Qf5Ddk5Csgi657ja2u5+NugbWz/QOVeVfrM1HTRDcfQ=
|
||||
github.com/libp2p/go-libp2p-kbucket v0.2.2 h1:Jg/JUbQix6mvTnj+86FasRqkh01JFQNrN+H26Gxxsg0=
|
||||
github.com/libp2p/go-libp2p-kbucket v0.2.2/go.mod h1:opWrBZSWnBYPc315q497huxY3sz1t488X6OiXUEYWKA=
|
||||
github.com/libp2p/go-libp2p-loggables v0.1.0 h1:h3w8QFfCt2UJl/0/NW4K829HX/0S4KD31PQ7m8UXXO8=
|
||||
github.com/libp2p/go-libp2p-loggables v0.1.0/go.mod h1:EyumB2Y6PrYjr55Q3/tiJ/o3xoDasoRYM7nOzEpoa90=
|
||||
github.com/libp2p/go-libp2p-mplex v0.2.0/go.mod h1:Ejl9IyjvXJ0T9iqUTE1jpYATQ9NM3g+OtR+EMMODbKo=
|
||||
github.com/libp2p/go-libp2p-mplex v0.2.1 h1:E1xaJBQnbSiTHGI1gaBKmKhu1TUKkErKJnE8iGvirYI=
|
||||
github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiYdAWNYHrwImKLnE=
|
||||
github.com/libp2p/go-libp2p-nat v0.0.5 h1:/mH8pXFVKleflDL1YwqMg27W9GD8kjEx7NY0P6eGc98=
|
||||
github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE=
|
||||
github.com/libp2p/go-libp2p-netutil v0.1.0/go.mod h1:3Qv/aDqtMLTUyQeundkKsA+YCThNdbQD54k3TqjpbFU=
|
||||
github.com/libp2p/go-libp2p-peer v0.2.0/go.mod h1:RCffaCvUyW2CJmG2gAWVqwePwW7JMgxjsHm7+J5kjWY=
|
||||
github.com/libp2p/go-libp2p-peerstore v0.1.0/go.mod h1:2CeHkQsr8svp4fZ+Oi9ykN1HBb6u0MOvdJ7YIsmcwtY=
|
||||
github.com/libp2p/go-libp2p-peerstore v0.1.3/go.mod h1:BJ9sHlm59/80oSkpWgr1MyY1ciXAXV397W6h1GH/uKI=
|
||||
github.com/libp2p/go-libp2p-peerstore v0.1.4 h1:d23fvq5oYMJ/lkkbO4oTwBp/JP+I/1m5gZJobNXCE/k=
|
||||
github.com/libp2p/go-libp2p-peerstore v0.1.4/go.mod h1:+4BDbDiiKf4PzpANZDAT+knVdLxvqh7hXOujessqdzs=
|
||||
github.com/libp2p/go-libp2p-record v0.1.2 h1:M50VKzWnmUrk/M5/Dz99qO9Xh4vs8ijsK+7HkJvRP+0=
|
||||
github.com/libp2p/go-libp2p-record v0.1.2/go.mod h1:pal0eNcT5nqZaTV7UGhqeGqxFgGdsU/9W//C8dqjQDk=
|
||||
github.com/libp2p/go-libp2p-routing v0.1.0 h1:hFnj3WR3E2tOcKaGpyzfP4gvFZ3t8JkQmbapN0Ct+oU=
|
||||
github.com/libp2p/go-libp2p-routing v0.1.0/go.mod h1:zfLhI1RI8RLEzmEaaPwzonRvXeeSHddONWkcTcB54nE=
|
||||
github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=
|
||||
github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g=
|
||||
github.com/libp2p/go-libp2p-secio v0.2.1 h1:eNWbJTdyPA7NxhP7J3c5lT97DC5d+u+IldkgCYFTPVA=
|
||||
github.com/libp2p/go-libp2p-secio v0.2.1/go.mod h1:cWtZpILJqkqrSkiYcDBh5lA3wbT2Q+hz3rJQq3iftD8=
|
||||
github.com/libp2p/go-libp2p-swarm v0.1.0/go.mod h1:wQVsCdjsuZoc730CgOvh5ox6K8evllckjebkdiY5ta4=
|
||||
github.com/libp2p/go-libp2p-swarm v0.2.2/go.mod h1:fvmtQ0T1nErXym1/aa1uJEyN7JzaTNyBcHImCxRpPKU=
|
||||
github.com/libp2p/go-libp2p-swarm v0.2.3-0.20200210151353-6e99a7602774 h1:GRotlsHPT1Jl6qTzSNgNu4PjbCBBHxakAuUVBZKFrFI=
|
||||
github.com/libp2p/go-libp2p-swarm v0.2.3-0.20200210151353-6e99a7602774/go.mod h1:bUFsDXKZ2i5p45JxrNwZyFs/g5+vVZPbEHawgDbKpVo=
|
||||
github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
|
||||
github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
|
||||
github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
|
||||
github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
|
||||
github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
|
||||
github.com/libp2p/go-libp2p-transport-upgrader v0.1.1 h1:PZMS9lhjK9VytzMCW3tWHAXtKXmlURSc3ZdvwEcKCzw=
|
||||
github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA=
|
||||
github.com/libp2p/go-libp2p-xor v0.0.0-20200330160054-7c8ff159b6e9/go.mod h1:i0t7yEDID1o5va91VahoqBbJE8xDKdt0Rwd1uGFAM7A=
|
||||
github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8=
|
||||
github.com/libp2p/go-libp2p-yamux v0.2.1 h1:Q3XYNiKCC2vIxrvUJL+Jg1kiyeEaIDNKLjgEjo3VQdI=
|
||||
github.com/libp2p/go-libp2p-yamux v0.2.1/go.mod h1:1FBXiHDk1VyRM1C0aez2bCfHQ4vMZKkAQzZbkSQt5fI=
|
||||
github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=
|
||||
github.com/libp2p/go-maddr-filter v0.0.5 h1:CW3AgbMO6vUvT4kf87y4N+0P8KUl2aqLYhrGyDUbLSg=
|
||||
github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M=
|
||||
github.com/libp2p/go-mplex v0.0.3/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTWe7l4Yd0=
|
||||
github.com/libp2p/go-mplex v0.1.0 h1:/nBTy5+1yRyY82YaO6HXQRnO5IAGsXTjEJaR3LdTPc0=
|
||||
github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU=
|
||||
github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
|
||||
github.com/libp2p/go-msgio v0.0.4 h1:agEFehY3zWJFUHK6SEMR7UYmk2z6kC3oeCM7ybLhguA=
|
||||
github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
|
||||
github.com/libp2p/go-nat v0.0.4 h1:KbizNnq8YIf7+Hn7+VFL/xE0eDrkPru2zIO9NMwL8UQ=
|
||||
github.com/libp2p/go-nat v0.0.4/go.mod h1:Nmw50VAvKuk38jUBcmNh6p9lUJLoODbJRvYAa/+KSDo=
|
||||
github.com/libp2p/go-openssl v0.0.2/go.mod h1:v8Zw2ijCSWBQi8Pq5GAixw6DbFfa9u6VIYDXnvOXkc0=
|
||||
github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
|
||||
github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
|
||||
github.com/libp2p/go-reuseport v0.0.1 h1:7PhkfH73VXfPJYKQ6JwS5I/eVcoyYi9IMNGc6FWpFLw=
|
||||
github.com/libp2p/go-reuseport v0.0.1/go.mod h1:jn6RmB1ufnQwl0Q1f+YxAj8isJgDCQzaaxIFYDhcYEA=
|
||||
github.com/libp2p/go-reuseport-transport v0.0.2 h1:WglMwyXyBu61CMkjCCtnmqNqnjib0GIEjMiHTwR/KN4=
|
||||
github.com/libp2p/go-reuseport-transport v0.0.2/go.mod h1:YkbSDrvjUVDL6b8XqriyA20obEtsW9BLkuOUyQAOCbs=
|
||||
github.com/libp2p/go-stream-muxer v0.0.1/go.mod h1:bAo8x7YkSpadMTbtTaxGVHWUQsR/l5MEaHbKaliuT14=
|
||||
github.com/libp2p/go-stream-muxer-multistream v0.2.0 h1:714bRJ4Zy9mdhyTLJ+ZKiROmAFwUHpeRidG+q7LTQOg=
|
||||
github.com/libp2p/go-stream-muxer-multistream v0.2.0/go.mod h1:j9eyPol/LLRqT+GPLSxvimPhNph4sfYfMoDPd7HkzIc=
|
||||
github.com/libp2p/go-tcp-transport v0.1.0/go.mod h1:oJ8I5VXryj493DEJ7OsBieu8fcg2nHGctwtInJVpipc=
|
||||
github.com/libp2p/go-tcp-transport v0.1.1 h1:yGlqURmqgNA2fvzjSgZNlHcsd/IulAnKM8Ncu+vlqnw=
|
||||
github.com/libp2p/go-tcp-transport v0.1.1/go.mod h1:3HzGvLbx6etZjnFlERyakbaYPdfjg2pWP97dFZworkY=
|
||||
github.com/libp2p/go-ws-transport v0.1.2 h1:VnxQcLfSGtqupqPpBNu8fUiCv+IN1RJ2BcVqQEM+z8E=
|
||||
github.com/libp2p/go-ws-transport v0.1.2/go.mod h1:dsh2Ld8F+XNmzpkaAijmg5Is+e9l6/1tK/6VFOdN69Y=
|
||||
github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
|
||||
github.com/libp2p/go-yamux v1.2.3 h1:xX8A36vpXb59frIzWFdEgptLMsOANMFq2K7fPRlunYI=
|
||||
github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/miekg/dns v1.1.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
|
||||
github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
|
||||
github.com/minio/sha256-simd v0.0.0-20190328051042-05b4dd3047e5/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
|
||||
github.com/minio/sha256-simd v0.1.0/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U=
|
||||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
|
||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
||||
github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
||||
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mr-tron/base58 v1.1.3 h1:v+sk57XuaCKGXpWtVBX8YJzO7hMGx4Aajh4TQbdEFdc=
|
||||
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=
|
||||
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
|
||||
github.com/multiformats/go-multiaddr v0.0.1/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
|
||||
github.com/multiformats/go-multiaddr v0.0.2/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
|
||||
github.com/multiformats/go-multiaddr v0.0.4/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
|
||||
github.com/multiformats/go-multiaddr v0.1.0/go.mod h1:xKVEak1K9cS1VdmPZW3LSIb6lgmoS58qz/pzqmAxV44=
|
||||
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
|
||||
github.com/multiformats/go-multiaddr v0.2.0 h1:lR52sFwcTCuQb6bTfnXF6zA2XfyYvyd+5a9qECv/J90=
|
||||
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
|
||||
github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
|
||||
github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
|
||||
github.com/multiformats/go-multiaddr-dns v0.2.0 h1:YWJoIDwLePniH7OU5hBnDZV6SWuvJqJ0YtN6pLeH9zA=
|
||||
github.com/multiformats/go-multiaddr-dns v0.2.0/go.mod h1:TJ5pr5bBO7Y1B18djPuRsVkduhQH2YqYSbxWJzYGdK0=
|
||||
github.com/multiformats/go-multiaddr-fmt v0.0.1/go.mod h1:aBYjqL4T/7j4Qx+R73XSv/8JsgnRFlf0w2KGLCmXl3Q=
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
|
||||
github.com/multiformats/go-multiaddr-net v0.0.1/go.mod h1:nw6HSxNmCIQH27XPGBuX+d1tnvM7ihcFwHMSstNAVUU=
|
||||
github.com/multiformats/go-multiaddr-net v0.1.0/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=
|
||||
github.com/multiformats/go-multiaddr-net v0.1.1/go.mod h1:5JNbcfBOP4dnhoZOv10JJVkJO0pCCEf8mTnipAo2UZQ=
|
||||
github.com/multiformats/go-multiaddr-net v0.1.2 h1:P7zcBH9FRETdPkDrylcXVjQLQ2t1JQtNItZULWNWgeg=
|
||||
github.com/multiformats/go-multiaddr-net v0.1.2/go.mod h1:QsWt3XK/3hwvNxZJp92iMQKME1qHfpYmyIjFVsSOY6Y=
|
||||
github.com/multiformats/go-multibase v0.0.1 h1:PN9/v21eLywrFWdFNsFKaU04kLJzuYzmrJR+ubhT9qA=
|
||||
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
|
||||
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
|
||||
github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=
|
||||
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
|
||||
github.com/multiformats/go-multihash v0.0.9/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
|
||||
github.com/multiformats/go-multihash v0.0.10 h1:lMoNbh2Ssd9PUF74Nz008KGzGPlfeV6wH3rit5IIGCM=
|
||||
github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
|
||||
github.com/multiformats/go-multistream v0.1.0 h1:UpO6jrsjqs46mqAK3n6wKRYFhugss9ArzbyUzU+4wkQ=
|
||||
github.com/multiformats/go-multistream v0.1.0/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=
|
||||
github.com/multiformats/go-varint v0.0.1 h1:TR/0rdQtnNxuN2IhiB639xC3tWM4IUi7DkTBVTdGW/M=
|
||||
github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA=
|
||||
github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/smola/gocompat v0.2.0/go.mod h1:1B0MlxbmoZNo3h8guHp8HztB3BSYR5itql9qtVc0ypY=
|
||||
github.com/spacemonkeygo/openssl v0.0.0-20181017203307-c2dcc5cca94a/go.mod h1:7AyxJNCJ7SBZ1MfVQCWD6Uqo2oubI2Eq2y2eqf+A5r0=
|
||||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/testground/sdk-go v0.1.1 h1:PfBte3SGdslQ7sFTfHRCg+FqP7+IB8xT5aDjmMVRj4s=
|
||||
github.com/testground/sdk-go v0.1.1/go.mod h1:wsWyhI6GfdCk9GUyD7Wu5UKX3x3jZcRh/Wp1XoFOP+A=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k=
|
||||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1/go.mod h1:8UvriyWtv5Q5EOgjHaSseUEdkQfvwFv1I/In/O2M9gc=
|
||||
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc h1:9lDbC6Rz4bwmou+oE6Dt4Cb2BGMur5eR/GYptkKUVHo=
|
||||
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
|
||||
github.com/whyrusleeping/mafmt v1.2.8 h1:TCghSl5kkwEE0j+sU/gudyhVMRlpBin8fMBBHg59EbA=
|
||||
github.com/whyrusleeping/mafmt v1.2.8/go.mod h1:faQJFPbLSxzD9xpA02ttW/tS9vZykNvXwGvqIpk20FA=
|
||||
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9/go.mod h1:j4l84WPFclQPj320J9gp0XwNKBb3U0zt5CBqjPp22G4=
|
||||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 h1:E9S12nwJwEOXe2d6gT6qxdvqMnNq+VnSsKPgm2ZZNds=
|
||||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7/go.mod h1:X2c0RVCI1eSUFI8eLcY3c0423ykwiUdxLJtkDvruhjI=
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
|
||||
go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||
go.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=
|
||||
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181130052023-1c3d964395ce/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/src-d/go-cli.v0 v0.0.0-20181105080154-d492247bbc0d/go.mod h1:z+K8VcOYVYcSwSjGebuDL6176A1XskgbtNl64NSg+n8=
|
||||
gopkg.in/src-d/go-log.v1 v1.0.1/go.mod h1:GN34hKP0g305ysm2/hctJ0Y8nWP3zxXXJ8GFabTyABE=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
@@ -1,47 +0,0 @@
|
||||
package libp2p
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/libp2p/test-plans/dht/utils"
|
||||
"github.com/testground/sdk-go/sync"
|
||||
)
|
||||
|
||||
func ShareAddresses(ctx context.Context, ri *utils.RunInfo, nodeInfo *NodeInfo) (map[peer.ID]*NodeInfo, error) {
|
||||
otherNodes := make(map[peer.ID]*NodeInfo)
|
||||
|
||||
subCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
attribCh := make(chan *NodeInfo)
|
||||
if _, _, err := ri.Client.PublishSubscribe(subCtx, PeerAttribTopic, nodeInfo, attribCh); err != nil {
|
||||
return nil, errors.Wrap(err, "peer attrib publish/subscribe failure")
|
||||
}
|
||||
|
||||
for i := 0; i < ri.RunEnv.TestInstanceCount; i++ {
|
||||
select {
|
||||
case info := <-attribCh:
|
||||
if info.Seq == nodeInfo.Seq {
|
||||
continue
|
||||
}
|
||||
otherNodes[info.Addrs.ID] = info
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
return otherNodes, nil
|
||||
}
|
||||
|
||||
type NodeInfo struct {
|
||||
Seq int // sequence number within the test
|
||||
GroupSeq int // sequence number within the test group
|
||||
Group string
|
||||
Addrs *peer.AddrInfo
|
||||
}
|
||||
|
||||
// PeerAttribTopic represents a subtree under the test run's sync tree where peers
|
||||
// participating in this distributed test advertise their attributes.
|
||||
var PeerAttribTopic = sync.NewTopic("attribs", &NodeInfo{})
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
test "github.com/libp2p/test-plans/dht/test"
|
||||
"github.com/testground/sdk-go/runtime"
|
||||
)
|
||||
|
||||
var testCases = map[string]runtime.TestCaseFn{
|
||||
"find-peers": test.FindPeers,
|
||||
"find-providers": test.FindProviders,
|
||||
"provide-stress": test.ProvideStress,
|
||||
"store-get-value": test.StoreGetValue,
|
||||
"get-closest-peers": test.GetClosestPeers,
|
||||
"bootstrap-network": test.BootstrapNetwork,
|
||||
"all": test.All,
|
||||
}
|
||||
|
||||
func main() {
|
||||
runtime.InvokeMap(testCases)
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
name = "dht"
|
||||
|
||||
[defaults]
|
||||
builder = "exec:go"
|
||||
runner = "local:exec"
|
||||
|
||||
[builders."docker:go"]
|
||||
enabled = true
|
||||
go_version = "1.13"
|
||||
module_path = "github.com/libp2p/test-plans/dht"
|
||||
exec_pkg = "."
|
||||
|
||||
# TODO: exec:go is not ready yet
|
||||
[builders."exec:go"]
|
||||
enabled = true
|
||||
module_path = "github.com/libp2p/test-plans/dht"
|
||||
exec_pkg = "."
|
||||
|
||||
[runners."local:docker"]
|
||||
enabled = true
|
||||
|
||||
[runners."local:exec"]
|
||||
enabled = true
|
||||
|
||||
[runners."cluster:swarm"]
|
||||
enabled = true
|
||||
|
||||
[runners."cluster:k8s"]
|
||||
enabled = true
|
||||
|
||||
[[testcases]]
|
||||
name = "find-peers"
|
||||
instances = { min = 16, max = 10000, default = 16 }
|
||||
|
||||
[testcases.params]
|
||||
timeout_secs = { type = "int", desc = "test timeout", unit = "seconds", default = 300 }
|
||||
latency = { type = "int", desc = "latency between peers", unit = "ms", default = 100 }
|
||||
auto_refresh = { type = "bool", desc = "enable DHT routing table autorefresh", unit = "bool", default = true }
|
||||
random_walk = { type = "bool", desc = "run 5 random walks before the test", unit = "bool", default = false }
|
||||
bucket_size = { type = "int", desc = "routing table bucket size", unit = "peers", default = 2 }
|
||||
alpha = { type = "int", desc = "dht concurrency parameter", unit = "int", default = 3 }
|
||||
beta = { type = "int", desc = "dht resiliency parameter", unit = "int", default = 3 }
|
||||
client_mode = { type = "bool", desc = "all undialable nodes are clients", unit = "bool", default = "false" }
|
||||
datastore = { type = "int", desc = "datastore type", unit = "int", default = 0 }
|
||||
peer_id_seed = { type = "int", desc = "seed used to generate all peer IDs - must be smaller than MaxInt-instances", default = 0 }
|
||||
bootstrapper = { type = "bool", desc = "node is a bootstrapper", unit = "bool", default = false}
|
||||
bs_strategy = { type = "int", desc = "the identifier for the nodes bootstrap strategy", unit = "int", default = 0}
|
||||
undialable = { type = "bool", desc = "node is undialable", unit = "bool", default = false}
|
||||
group_order = { type = "int", desc = "the order in which the node is bootstrapped, may be tied with another node", unit ="int", default = 0}
|
||||
expect_dht = { type = "bool", desc = "the node expects to be a dht server", unit ="bool", default = true}
|
||||
|
||||
n_find_peers = { type = "int", desc = "number of peers to find", unit = "peers", default = 1 }
|
||||
|
||||
[[testcases]]
|
||||
name = "find-providers"
|
||||
instances = { min = 16, max = 10000, default = 16 }
|
||||
|
||||
[testcases.params]
|
||||
timeout_secs = { type = "int", desc = "test timeout", unit = "seconds", default = 300 }
|
||||
latency = { type = "int", desc = "latency between peers", unit = "ms", default = 100 }
|
||||
auto_refresh = { type = "bool", desc = "enable DHT routing table autorefresh", unit = "bool", default = true }
|
||||
random_walk = { type = "bool", desc = "run 5 random walks before the test", unit = "bool", default = false }
|
||||
bucket_size = { type = "int", desc = "routing table bucket size", unit = "peers", default = 2 }
|
||||
alpha = { type = "int", desc = "dht concurrency parameter", unit = "int", default = 3 }
|
||||
beta = { type = "int", desc = "dht resiliency parameter", unit = "int", default = 3 }
|
||||
client_mode = { type = "bool", desc = "all undialable nodes are clients", unit = "bool", default = "false" }
|
||||
datastore = { type = "int", desc = "datastore type", unit = "int", default = 0 }
|
||||
peer_id_seed = { type = "int", desc = "seed used to generate all peer IDs - must be smaller than MaxInt-instances", default = 0 }
|
||||
bootstrapper = { type = "bool", desc = "node is a bootstrapper", unit = "bool", default = false}
|
||||
bs_strategy = { type = "int", desc = "the identifier for the nodes bootstrap strategy", unit = "int", default = 0}
|
||||
undialable = { type = "bool", desc = "node is undialable", unit = "bool", default = false}
|
||||
group_order = { type = "int", desc = "the order in which the node is bootstrapped, may be tied with another node", unit ="int", default = 0}
|
||||
expect_dht = { type = "bool", desc = "the node expects to be a dht server", unit ="bool", default = true}
|
||||
|
||||
record_seed = { type = "int", desc = "the seed used to generate records", unit = "int", default = 0 }
|
||||
record_count = { type = "int", desc = "number of records a peer provides", unit = "int", default = 0 }
|
||||
search_records = { type = "bool", desc = "node will search for records", unit = "bool", default = false }
|
||||
#p_providing = { type = "int", desc = "", unit = "% of nodes" }
|
||||
#p_resolving = { type = "int", desc = "", unit = "% of nodes" }
|
||||
#p_failing = { type = "int", desc = "", unit = "% of nodes" }
|
||||
|
||||
[[testcases]]
|
||||
name = "provide-stress"
|
||||
instances = { min = 16, max = 250, default = 16 }
|
||||
|
||||
[testcases.params]
|
||||
bucket_size = { type = "int", desc = "bucket size", unit = "peers" }
|
||||
auto_refresh = { type = "bool", desc = "", unit = "bool" }
|
||||
random_walk = { type = "bool", desc = "", unit = "bool" }
|
||||
n_bootstrap = { type = "int", desc = "number of bootstrap nodes", unit = "int", default = 1 }
|
||||
n_provides = { type = "int", desc = "number of times to provide", unit = "int" }
|
||||
i_provides = { type = "int", desc = "interval between each provide", unit = "seconds" }
|
||||
|
||||
[[testcases]]
|
||||
name = "store-get-value"
|
||||
instances = { min = 16, max = 250, default = 16 }
|
||||
roles = ["storer", "fetcher"]
|
||||
|
||||
[testcases.params]
|
||||
bucket_size = { type = "int", desc = "bucket size", unit = "peers" }
|
||||
|
||||
[[testcases]]
|
||||
name = "get-closest-peers"
|
||||
instances = { min = 16, max = 10000, default = 16 }
|
||||
|
||||
[testcases.params]
|
||||
timeout_secs = { type = "int", desc = "test timeout", unit = "seconds", default = 300 }
|
||||
latency = { type = "int", desc = "latency between peers", unit = "ms", default = 100 }
|
||||
auto_refresh = { type = "bool", desc = "enable DHT routing table autorefresh", unit = "bool", default = true }
|
||||
random_walk = { type = "bool", desc = "run 5 random walks before the test", unit = "bool", default = false }
|
||||
bucket_size = { type = "int", desc = "routing table bucket size", unit = "peers", default = 2 }
|
||||
alpha = { type = "int", desc = "dht concurrency parameter", unit = "int", default = 3 }
|
||||
beta = { type = "int", desc = "dht resiliency parameter", unit = "int", default = 3 }
|
||||
client_mode = { type = "bool", desc = "all undialable nodes are clients", unit = "bool", default = "false" }
|
||||
datastore = { type = "int", desc = "datastore type", unit = "int", default = 0 }
|
||||
peer_id_seed = { type = "int", desc = "seed used to generate all peer IDs - must be smaller than MaxInt-instances", default = 0 }
|
||||
bootstrapper = { type = "bool", desc = "node is a bootstrapper", unit = "bool", default = false}
|
||||
bs_strategy = { type = "int", desc = "the identifier for the nodes bootstrap strategy", unit = "int", default = 0}
|
||||
undialable = { type = "bool", desc = "node is undialable", unit = "bool", default = false}
|
||||
group_order = { type = "int", desc = "the order in which the node is bootstrapped, may be tied with another node", unit ="int", default = 0}
|
||||
expect_dht = { type = "bool", desc = "the node expects to be a dht server", unit ="bool", default = true}
|
||||
|
||||
record_seed = { type = "int", desc = "the seed used to generate records", unit = "int", default = 0 }
|
||||
record_count = { type = "int", desc = "number of records a peer provides", unit = "int", default = 0 }
|
||||
search_records = { type = "bool", desc = "node will search for records", unit = "bool", default = false }
|
||||
|
||||
[[testcases]]
|
||||
name = "bootstrap-network"
|
||||
instances = { min = 16, max = 10000, default = 16 }
|
||||
|
||||
[testcases.params]
|
||||
timeout_secs = { type = "int", desc = "test timeout", unit = "seconds", default = 300 }
|
||||
latency = { type = "int", desc = "latency between peers", unit = "ms", default = 100 }
|
||||
auto_refresh = { type = "bool", desc = "enable DHT routing table autorefresh", unit = "bool", default = true }
|
||||
random_walk = { type = "bool", desc = "run 5 random walks before the test", unit = "bool", default = false }
|
||||
bucket_size = { type = "int", desc = "routing table bucket size", unit = "peers", default = 2 }
|
||||
alpha = { type = "int", desc = "dht concurrency parameter", unit = "int", default = 3 }
|
||||
beta = { type = "int", desc = "dht resiliency parameter", unit = "int", default = 3 }
|
||||
client_mode = { type = "bool", desc = "all undialable nodes are clients", unit = "bool", default = "false" }
|
||||
datastore = { type = "int", desc = "datastore type", unit = "int", default = 0 }
|
||||
peer_id_seed = { type = "int", desc = "seed used to generate all peer IDs - must be smaller than MaxInt-instances", default = 0 }
|
||||
bootstrapper = { type = "bool", desc = "node is a bootstrapper", unit = "bool", default = false}
|
||||
bs_strategy = { type = "int", desc = "the identifier for the nodes bootstrap strategy", unit = "int", default = 0}
|
||||
undialable = { type = "bool", desc = "node is undialable", unit = "bool", default = false}
|
||||
group_order = { type = "int", desc = "the order in which the node is bootstrapped, may be tied with another node", unit ="int", default = 0}
|
||||
expect_dht = { type = "bool", desc = "the node expects to be a dht server", unit ="bool", default = true}
|
||||
|
||||
[[testcases]]
|
||||
name = "all"
|
||||
instances = { min = 16, max = 10000, default = 16 }
|
||||
|
||||
[testcases.params]
|
||||
timeout_secs = { type = "int", desc = "test timeout", unit = "seconds", default = 300 }
|
||||
latency = { type = "int", desc = "latency between peers", unit = "ms", default = 100 }
|
||||
auto_refresh = { type = "bool", desc = "enable DHT routing table autorefresh", unit = "bool", default = true }
|
||||
random_walk = { type = "bool", desc = "run 5 random walks before the test", unit = "bool", default = false }
|
||||
bucket_size = { type = "int", desc = "routing table bucket size", unit = "peers", default = 2 }
|
||||
alpha = { type = "int", desc = "dht concurrency parameter", unit = "int", default = 3 }
|
||||
beta = { type = "int", desc = "dht resiliency parameter", unit = "int", default = 3 }
|
||||
client_mode = { type = "bool", desc = "all undialable nodes are clients", unit = "bool", default = "false" }
|
||||
datastore = { type = "int", desc = "datastore type", unit = "int", default = 0 }
|
||||
peer_id_seed = { type = "int", desc = "seed used to generate all peer IDs - must be smaller than MaxInt-instances", default = 0 }
|
||||
bootstrapper = { type = "bool", desc = "node is a bootstrapper", unit = "bool", default = false}
|
||||
bs_strategy = { type = "int", desc = "the identifier for the nodes bootstrap strategy", unit = "int", default = 0}
|
||||
undialable = { type = "bool", desc = "node is undialable", unit = "bool", default = false}
|
||||
group_order = { type = "int", desc = "the order in which the node is bootstrapped, may be tied with another node", unit ="int", default = 0}
|
||||
expect_dht = { type = "bool", desc = "the node expects to be a dht server", unit ="bool", default = true}
|
||||
|
||||
record_seed = { type = "int", desc = "the seed used to generate records", unit = "int", default = 0 }
|
||||
record_count = { type = "int", desc = "number of records a peer provides", unit = "int", default = 0 }
|
||||
search_records = { type = "bool", desc = "node will search for records", unit = "bool", default = false }
|
||||
n_find_peers = { type = "int", desc = "number of peers to find", unit = "peers", default = 0 }
|
||||
@@ -1,29 +0,0 @@
|
||||
param($graphID,$dataDir)
|
||||
|
||||
$allGraphs = @("br", "bt", "at", "ab", "end")
|
||||
$fmt = "png"
|
||||
|
||||
if (!$dataDir) {
|
||||
$dataDir = gci $HOME/.testground/results/dht | Sort LastWriteTime | select -Last 1
|
||||
}
|
||||
|
||||
if ($graphID) {
|
||||
$allGraphs = @($graphID)
|
||||
}
|
||||
|
||||
$allGraphs | %{
|
||||
$g = $_
|
||||
$data = gci $dataDir -recurse | ?{$_.Name -eq "stderr.json"} | Get-Content |
|
||||
ConvertFrom-Json
|
||||
|
||||
$gdataz = $data | ?{$_.N -eq "Graph" -and $_.M -eq $g}
|
||||
$gdata = $gdataz | %{"Z{0} -> Z{1};`n" -f $_.From, $_.To}
|
||||
$file = "digraph D {`n " + $gdata + "}"
|
||||
$file > "$g-conn.dot"
|
||||
|
||||
$rtdata = $data | ?{$_.N -eq "RT" -and $_.M -eq "$g"} | %{"Z{0} -> Z{1};`n" -f $_.From, $_.To}
|
||||
$rtfile = "digraph D {`n " + $rtdata + "}"
|
||||
$rtfile > "$g-rt.dot"
|
||||
|
||||
#$file | circo "-T$fmt" -o "$g.$fmt"
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
param($dataDir)
|
||||
|
||||
$allFiles = $dataDir | gci -Recurse -File
|
||||
$connGraphs = $allFiles | ?{$_.Name -eq "dht_graphs.out"}
|
||||
$rts = $allFiles | ?{$_.Name -eq "dht_rt.out"}
|
||||
$errs = $allFiles | ?{$_.Name -eq "run.err"}
|
||||
|
||||
$ns = 1000000000
|
||||
|
||||
function basicStats ($values, $reverse) {
|
||||
if ($null -eq $values) {
|
||||
return [PSCustomObject]@{
|
||||
Average = 0
|
||||
Percentile95 = 0
|
||||
}
|
||||
}
|
||||
$obj = $values | measure-object -Average -Sum -Maximum -Minimum -StandardDeviation
|
||||
if ($null -eq $reverse || $false -eq $reverse) {
|
||||
$sorted = $values | Sort-Object
|
||||
} else {
|
||||
$sorted = $values | Sort-Object -Descending
|
||||
}
|
||||
$95percentile = $sorted[[math]::Ceiling(95 / 100 * ($sorted.Count - 1))]
|
||||
|
||||
if ($null -eq $95percentile) {
|
||||
return "ASDFASFASF"
|
||||
}
|
||||
|
||||
return [PSCustomObject]@{
|
||||
Average = [math]::Round([double]$obj.Average,2)
|
||||
Percentile95 = [math]::Round([double]$95percentile, 2)
|
||||
}
|
||||
}
|
||||
|
||||
function groupStats ($metrics, $groupIndex, $reverse) {
|
||||
$fields = @{}
|
||||
$grouped = $metrics | Group-Object -Property {$_.Name.Split("|")[$groupIndex]}
|
||||
foreach ($g in $grouped) {
|
||||
$v = basicStats ($g.Group | %{$_.Value}) $reverse
|
||||
$fields.Add($g.Name, $v)
|
||||
}
|
||||
$ret = New-Object -TypeName psobject -Property $fields
|
||||
return $ret
|
||||
}
|
||||
|
||||
function run($groupDir) {
|
||||
$groupID = $groupDir.Name
|
||||
|
||||
$files = $groupDir | gci -Recurse -File
|
||||
|
||||
$queries = $files | ?{$_.Name -eq "dht_queries.out"}
|
||||
$lookups = $files | ?{$_.Name -eq "dht_lookup.out"}
|
||||
$out = $files | ?{$_.Name -eq "run.out"}
|
||||
|
||||
$metrics = $out | Get-Content | ConvertFrom-Json | %{$_.event.metric} | ?{$_}
|
||||
$mset =
|
||||
|
||||
$provs = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("time-to-provide") -and $_.value -gt 0} |
|
||||
%{$_.value/$ns}
|
||||
|
||||
$findfirst = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("time-to-find-first")} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value/$ns; }}
|
||||
|
||||
$findlast = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("time-to-find-last")} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value/$ns; }}
|
||||
|
||||
$findall = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("time-to-find|")} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value/$ns; }}
|
||||
|
||||
$findgood = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("time-to-find|done")} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value/$ns; }}
|
||||
|
||||
$findfail = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("time-to-find|fail")} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value/$ns; }}
|
||||
|
||||
$found = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("peers-found") -and $_.value -gt 0} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value; }}
|
||||
|
||||
$missing = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("peers-missing")} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value; }}
|
||||
|
||||
$failures = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("peers-found") -and $_.value -eq 0} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value; }}
|
||||
|
||||
$dials = $queries | %{Get-Content $_ | ConvertFrom-Json | ?{$_.msg -eq "dialing"} | measure-object } |
|
||||
%{$_.Count}
|
||||
|
||||
$msgs = $queries | %{Get-Content $_ | ConvertFrom-Json | ?{$_.msg -eq "send"} | measure-object } |
|
||||
%{$_.Count}
|
||||
|
||||
echo "Group $groupID :"
|
||||
|
||||
if ($null -ne $provs) {
|
||||
echo "Time-to-Provide"
|
||||
basicStats($provs) | Format-Table
|
||||
}
|
||||
|
||||
if ($null -ne $findfirst) {
|
||||
echo "Time-to-Find-First"
|
||||
groupStats $findfirst 1 | Format-Table
|
||||
|
||||
echo "Time-to-Find-Last"
|
||||
groupStats $findlast 2 | Format-Table
|
||||
|
||||
if ($null -ne $findgood) {
|
||||
echo "Time-to-Find Success"
|
||||
groupStats $findgood 2 | Format-Table
|
||||
}
|
||||
|
||||
if ($null -ne $findfail) {
|
||||
echo "Time-to-Find Fail"
|
||||
groupStats $findfail 2 | Format-Table
|
||||
|
||||
echo "Number of Failures"
|
||||
groupStats $failures 2 | Format-Table
|
||||
}
|
||||
|
||||
if (($null -ne $findgood) -and ($null -ne $findfail)) {
|
||||
echo "Time-to-Find"
|
||||
groupStats $findall 2 | Format-Table
|
||||
}
|
||||
|
||||
echo "Peers Found"
|
||||
groupStats $found 2 $true | Format-Table
|
||||
|
||||
echo "Peers Missing"
|
||||
groupStats $missing 2 | Format-Table
|
||||
|
||||
#if ($failures -ne $null) {
|
||||
# echo "Peers Failures"
|
||||
# groupStats $failures 2 | Format-Table
|
||||
#} else {
|
||||
# echo "No Peer Failures"
|
||||
#}
|
||||
}
|
||||
|
||||
if ($dials -ne $null) {
|
||||
echo "Total number of dials"
|
||||
basicStats($dials) | Format-Table
|
||||
} else {
|
||||
echo "No DHT query dials performed"
|
||||
}
|
||||
|
||||
if ($msgs -ne $null) {
|
||||
echo "Total number of messages sent"
|
||||
basicStats($msgs) | Format-Table
|
||||
} else {
|
||||
echo "No DHT query messages sent"
|
||||
}
|
||||
}
|
||||
|
||||
function condense($fileDir) {
|
||||
Remove-Item $fileDir/lookupcmp.json -ErrorAction Ignore
|
||||
Remove-Item $fileDir/runcmp.json -ErrorAction Ignore
|
||||
|
||||
$lookupOut = gci $fileDir/dht_lookups.out | gc | ConvertFrom-Json
|
||||
$start = $lookupOut | Select-Object -First 1 -ExpandProperty ts
|
||||
$lookupOut | %{
|
||||
$_.ts = ($_.ts - $start)/$ns;
|
||||
$_.node = -join $_.node[-4..-1];
|
||||
$_.nodeKad = -join $_.nodeKad[0..4];
|
||||
$_.target = -join $_.target[-4..-1];
|
||||
$_.info.ID = -join $_.info.ID[0..4];
|
||||
#$_.targetKad = -join $_.targetKad[0..4];
|
||||
|
||||
if ($null -ne $_.cause) {
|
||||
sliceLast $_ cause
|
||||
sliceLast $_ source
|
||||
sliceFirst $_ causeKad
|
||||
sliceFirst $_ sourceKad
|
||||
arrslice $_ heard $false
|
||||
arrslice $_ waiting $false
|
||||
arrslice $_ queried $false
|
||||
arrslice $_ unreachable $false
|
||||
arrslice $_ heardKad $true
|
||||
arrslice $_ waitingKad $true
|
||||
arrslice $_ queriedKad $true
|
||||
arrslice $_ unreachableKad $true
|
||||
|
||||
}
|
||||
$_} | Select-Object -Property * -ExcludeProperty heard,waiting,queried,unreachable |
|
||||
%{ $_ | ConvertTo-Json -Compress -Depth 10 | Add-Content $fileDir/lookupcmp.json }
|
||||
|
||||
$runOut = gci $fileDir/run.out | gc | ConvertFrom-Json
|
||||
$runOut | %{$_.ts = ($_.ts - $start)/$ns; $_} |
|
||||
%{ $_ | ConvertTo-Json -Compress -Depth 10 | Add-Content $fileDir/runcmp.json }
|
||||
}
|
||||
|
||||
function sliceFirst($obj, $field) {
|
||||
if ($null -eq $obj.$field) {
|
||||
return
|
||||
}
|
||||
$obj.$field = -join $obj.$field[0..4]
|
||||
}
|
||||
|
||||
function sliceLast($obj, $field) {
|
||||
if ($null -eq $obj.$field) {
|
||||
return
|
||||
}
|
||||
$obj.$field = -join $obj.$field[-4..-1]
|
||||
}
|
||||
|
||||
function arrslice($obj, $field, $first) {
|
||||
if ($null -eq $obj.$field) {
|
||||
return
|
||||
}
|
||||
if ($first) {
|
||||
$obj.$field = $obj.$field | %{-join $_[0..4]}
|
||||
} else {
|
||||
$obj.$field = $obj.$field | %{-join $_[-4..-1]}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
run $dataDir
|
||||
condense $dataDir
|
||||
@@ -1,204 +0,0 @@
|
||||
param($runID)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$env:TESTGROUND_SRCDIR="$env:USERPROFILE/go/src/github.com/ipfs/testground"
|
||||
$outputDir = "$env:USERPROFILE/workspace/testground/stats"
|
||||
$runner = "cluster:k8s"
|
||||
#$runner = "local:docker"
|
||||
$graphs = $true
|
||||
|
||||
if (-not [System.IO.Directory]::Exists("$outputDir/$runID")) {
|
||||
$outname = "$outputDir/$runID.tar.gz"
|
||||
testground collect $runID --runner $runner -o $outname
|
||||
tar -C $outputDir -zxvf $outname
|
||||
}
|
||||
$groupDirs = gci $outputDir/$runID
|
||||
|
||||
$allFiles = $groupDirs | gci -Recurse -File
|
||||
$connGraphs = $allFiles | ?{$_.Name -eq "dht_graphs.out"}
|
||||
$rts = $allFiles | ?{$_.Name -eq "dht_rt.out"}
|
||||
$errs = $allFiles | ?{$_.Name -eq "run.err"}
|
||||
|
||||
$ns = 1000000000
|
||||
|
||||
function basicStats ($values, $reverse) {
|
||||
if ($null -eq $values) {
|
||||
return [PSCustomObject]@{
|
||||
Average = 0
|
||||
Percentile95 = 0
|
||||
}
|
||||
}
|
||||
$obj = $values | measure-object -Average -Sum -Maximum -Minimum -StandardDeviation
|
||||
if ($null -eq $reverse || $false -eq $reverse) {
|
||||
$sorted = $values | Sort-Object
|
||||
} else {
|
||||
$sorted = $values | Sort-Object -Descending
|
||||
}
|
||||
$95percentile = $sorted[[math]::Ceiling(95 / 100 * ($sorted.Count - 1))]
|
||||
|
||||
if ($null -eq $95percentile) {
|
||||
return "ASDFASFASF"
|
||||
}
|
||||
|
||||
return [PSCustomObject]@{
|
||||
Average = [math]::Round([double]$obj.Average,2)
|
||||
Percentile95 = [math]::Round([double]$95percentile, 2)
|
||||
}
|
||||
}
|
||||
|
||||
function groupStats ($metrics, $groupIndex, $reverse) {
|
||||
$fields = @{}
|
||||
$grouped = $metrics | Group-Object -Property {$_.Name.Split("|")[$groupIndex]}
|
||||
foreach ($g in $grouped) {
|
||||
$v = basicStats ($g.Group | %{$_.Value}) $reverse
|
||||
$fields.Add($g.Name, $v)
|
||||
}
|
||||
$ret = New-Object -TypeName psobject -Property $fields
|
||||
return $ret
|
||||
}
|
||||
|
||||
foreach ($groupDir in $groupDirs) {
|
||||
$groupID = $groupDir.Name
|
||||
|
||||
$files = $groupDir | gci -Recurse -File
|
||||
|
||||
$queries = $files | ?{$_.Name -eq "dht_queries.out"}
|
||||
$lookups = $files | ?{$_.Name -eq "dht_lookup.out"}
|
||||
$out = $files | ?{$_.Name -eq "run.out"}
|
||||
|
||||
$metrics = $out | Get-Content | ConvertFrom-Json | %{$_.event.metric} | ?{$_}
|
||||
$mset =
|
||||
|
||||
$provs = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("time-to-provide") -and $_.value -gt 0} |
|
||||
%{$_.value/$ns}
|
||||
|
||||
$findfirst = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("time-to-find-first")} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value/$ns; }}
|
||||
|
||||
$findlast = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("time-to-find-last")} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value/$ns; }}
|
||||
|
||||
$findall = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("time-to-find|")} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value/$ns; }}
|
||||
|
||||
$findgood = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("time-to-find|done")} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value/$ns; }}
|
||||
|
||||
$findfail = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("time-to-find|fail")} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value/$ns; }}
|
||||
|
||||
$found = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("peers-found") -and $_.value -gt 0} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value; }}
|
||||
|
||||
$missing = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("peers-missing")} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value; }}
|
||||
|
||||
$failures = $metrics |
|
||||
?{$_.name -and $_.name.StartsWith("peers-found") -and $_.value -eq 0} |
|
||||
%{ [pscustomobject]@{ Name=$_.name; Value= $_.value; }}
|
||||
|
||||
$dials = $queries | %{Get-Content $_ | ConvertFrom-Json | ?{$_.msg -eq "dialing"} | measure-object } |
|
||||
%{$_.Count}
|
||||
|
||||
$msgs = $queries | %{Get-Content $_ | ConvertFrom-Json | ?{$_.msg -eq "send"} | measure-object } |
|
||||
%{$_.Count}
|
||||
|
||||
echo "Group $groupID :"
|
||||
|
||||
if ($null -ne $provs) {
|
||||
echo "Time-to-Provide"
|
||||
basicStats($provs) | Format-Table
|
||||
}
|
||||
|
||||
if ($null -ne $findfirst) {
|
||||
echo "Time-to-Find-First"
|
||||
groupStats $findfirst 1 | Format-Table
|
||||
|
||||
echo "Time-to-Find-Last"
|
||||
groupStats $findlast 2 | Format-Table
|
||||
|
||||
if ($null -ne $findgood) {
|
||||
echo "Time-to-Find Success"
|
||||
groupStats $findgood 2 | Format-Table
|
||||
}
|
||||
|
||||
if ($null -ne $findfail) {
|
||||
echo "Time-to-Find Fail"
|
||||
groupStats $findfail 2 | Format-Table
|
||||
|
||||
echo "Number of Failures"
|
||||
groupStats $failures 2 | Format-Table
|
||||
}
|
||||
|
||||
if (($null -ne $findgood) -and ($null -ne $findfail)) {
|
||||
echo "Time-to-Find"
|
||||
groupStats $findall 2 | Format-Table
|
||||
}
|
||||
|
||||
echo "Peers Found"
|
||||
groupStats $found 2 $true | Format-Table
|
||||
|
||||
echo "Peers Missing"
|
||||
groupStats $missing 2 | Format-Table
|
||||
|
||||
#if ($failures -ne $null) {
|
||||
# echo "Peers Failures"
|
||||
# groupStats $failures 2 | Format-Table
|
||||
#} else {
|
||||
# echo "No Peer Failures"
|
||||
#}
|
||||
}
|
||||
|
||||
if ($dials -ne $null) {
|
||||
echo "Total number of dials"
|
||||
basicStats($dials) | Format-Table
|
||||
} else {
|
||||
echo "No DHT query dials performed"
|
||||
}
|
||||
|
||||
if ($msgs -ne $null) {
|
||||
echo "Total number of messages sent"
|
||||
basicStats($msgs) | Format-Table
|
||||
} else {
|
||||
echo "No DHT query messages sent"
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $graphs) {
|
||||
return
|
||||
}
|
||||
|
||||
$allGraphs = $connGraphs | Get-Content | ConvertFrom-Json | Group-Object -Property msg
|
||||
|
||||
$allGraphs | %{
|
||||
$g = $_.Name
|
||||
$obj = $_.Group
|
||||
|
||||
$gdata = $obj | %{"Z{0} -> Z{1};`n" -f $_.From, $_.To}
|
||||
$file = "digraph D {`n " + $gdata + "}"
|
||||
$file > "$outputDir/$runID/$g-conn.dot"
|
||||
|
||||
#$file | circo "-T$fmt" -o "$g.$fmt"
|
||||
}
|
||||
|
||||
$allRTs = $rts | Get-Content | ConvertFrom-Json | Group-Object -Property msg
|
||||
|
||||
$allRTs | %{
|
||||
$g = $_.Name
|
||||
$obj = $_.Group
|
||||
|
||||
$gdata = $obj | %{"Z{0} -> Z{1};`n" -f $_.Node, $_.Peer}
|
||||
$file = "digraph D {`n " + $gdata + "}"
|
||||
$file > "$outputDir/$runID/$g-rt.dot"
|
||||
|
||||
#$file | circo "-T$fmt" -o "$g.$fmt"
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/testground/sdk-go/runtime"
|
||||
)
|
||||
|
||||
func All(runenv *runtime.RunEnv) error {
|
||||
commonOpts := GetCommonOpts(runenv)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), commonOpts.Timeout)
|
||||
defer cancel()
|
||||
|
||||
ri, err := Base(ctx, runenv, commonOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := TestFindPeers(ctx, ri); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := TestGetClosestPeers(ctx, ri); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := TestProviderRecords(ctx, ri); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := TestIPNSRecords(ctx, ri); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Teardown(ctx, ri.RunInfo)
|
||||
return nil
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/testground/sdk-go/runtime"
|
||||
)
|
||||
|
||||
func BootstrapNetwork(runenv *runtime.RunEnv) error {
|
||||
commonOpts := GetCommonOpts(runenv)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), commonOpts.Timeout)
|
||||
defer cancel()
|
||||
|
||||
_, err := Base(ctx, runenv, commonOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,946 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
gosync "sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/testground/sdk-go/runtime"
|
||||
"github.com/testground/sdk-go/sync"
|
||||
|
||||
tglibp2p "github.com/libp2p/test-plans/dht/libp2p"
|
||||
"github.com/libp2p/test-plans/dht/utils"
|
||||
|
||||
leveldb "github.com/ipfs/go-ds-leveldb"
|
||||
|
||||
"github.com/ipfs/go-datastore"
|
||||
dssync "github.com/ipfs/go-datastore/sync"
|
||||
"github.com/libp2p/go-libp2p"
|
||||
connmgr "github.com/libp2p/go-libp2p-connmgr"
|
||||
"github.com/libp2p/go-libp2p-core/crypto"
|
||||
"github.com/libp2p/go-libp2p-core/host"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
kaddht "github.com/libp2p/go-libp2p-kad-dht"
|
||||
swarm "github.com/libp2p/go-libp2p-swarm"
|
||||
tptu "github.com/libp2p/go-libp2p-transport-upgrader"
|
||||
tcp "github.com/libp2p/go-tcp-transport"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
"github.com/multiformats/go-multiaddr-net"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func init() {
|
||||
os.Setenv("LIBP2P_TCP_REUSEPORT", "false")
|
||||
swarm.BackoffBase = 0
|
||||
}
|
||||
|
||||
const minTestInstances = 16
|
||||
|
||||
type OptDatastore int
|
||||
|
||||
const (
|
||||
OptDatastoreMemory OptDatastore = iota
|
||||
OptDatastoreLeveldb
|
||||
)
|
||||
|
||||
type SetupOpts struct {
|
||||
Timeout time.Duration
|
||||
Latency time.Duration
|
||||
AutoRefresh bool
|
||||
RandomWalk bool
|
||||
|
||||
BucketSize int
|
||||
Alpha int
|
||||
Beta int
|
||||
NDisjointPaths int
|
||||
|
||||
ClientMode bool
|
||||
Datastore OptDatastore
|
||||
|
||||
PeerIDSeed int
|
||||
Bootstrapper bool
|
||||
BootstrapStrategy int
|
||||
Undialable bool
|
||||
GroupOrder int
|
||||
ExpectedServer bool
|
||||
}
|
||||
|
||||
type DHTRunInfo struct {
|
||||
*utils.RunInfo
|
||||
DHTGroupProperties map[string]*SetupOpts
|
||||
Node *NodeParams
|
||||
Others map[peer.ID]*DHTNodeInfo
|
||||
}
|
||||
|
||||
func GetCommonOpts(runenv *runtime.RunEnv) *SetupOpts {
|
||||
opts := &SetupOpts{
|
||||
Timeout: time.Duration(runenv.IntParam("timeout_secs")) * time.Second,
|
||||
Latency: time.Duration(runenv.IntParam("latency")) * time.Millisecond,
|
||||
AutoRefresh: runenv.BooleanParam("auto_refresh"),
|
||||
RandomWalk: runenv.BooleanParam("random_walk"),
|
||||
|
||||
BucketSize: runenv.IntParam("bucket_size"),
|
||||
Alpha: runenv.IntParam("alpha"),
|
||||
Beta: runenv.IntParam("beta"),
|
||||
|
||||
ClientMode: runenv.BooleanParam("client_mode"),
|
||||
Datastore: OptDatastore(runenv.IntParam("datastore")),
|
||||
|
||||
PeerIDSeed: runenv.IntParam("peer_id_seed"),
|
||||
Bootstrapper: runenv.BooleanParam("bootstrapper"),
|
||||
BootstrapStrategy: runenv.IntParam("bs_strategy"),
|
||||
Undialable: runenv.BooleanParam("undialable"),
|
||||
GroupOrder: runenv.IntParam("group_order"),
|
||||
ExpectedServer: runenv.BooleanParam("expect_dht"),
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
type NodeParams struct {
|
||||
host host.Host
|
||||
dht *kaddht.IpfsDHT
|
||||
info *DHTNodeInfo
|
||||
}
|
||||
|
||||
type DHTNodeInfo struct {
|
||||
*tglibp2p.NodeInfo
|
||||
Properties *SetupOpts
|
||||
}
|
||||
|
||||
type NodeProperties struct {
|
||||
Bootstrapper bool
|
||||
Undialable bool
|
||||
ExpectedServer bool
|
||||
}
|
||||
|
||||
var ConnManagerGracePeriod = 1 * time.Second
|
||||
|
||||
// NewDHTNode creates a libp2p Host, and a DHT instance on top of it.
|
||||
func NewDHTNode(ctx context.Context, runenv *runtime.RunEnv, opts *SetupOpts, idKey crypto.PrivKey, info *DHTNodeInfo) (host.Host, *kaddht.IpfsDHT, error) {
|
||||
swarm.DialTimeoutLocal = opts.Timeout
|
||||
var min, max int
|
||||
|
||||
if info.Properties.Bootstrapper {
|
||||
// TODO: Assumes only 1 bootstrapper group
|
||||
min = (runenv.TestInstanceCount / runenv.TestGroupInstanceCount) *
|
||||
int(math.Ceil(math.Log2(float64(runenv.TestInstanceCount))))
|
||||
max = min * 2
|
||||
} else {
|
||||
min = int(math.Ceil(math.Log2(float64(runenv.TestInstanceCount))) * 5)
|
||||
max = min * 2
|
||||
}
|
||||
|
||||
// We need enough connections to be able to trim some and still have a
|
||||
// few peers.
|
||||
//
|
||||
// Note: this check is redundant just to be explicit. If we have over 16
|
||||
// peers, we're above this limit.
|
||||
// if min < 3 || max >= runenv.TestInstanceCount {
|
||||
if min < 3 {
|
||||
return nil, nil, fmt.Errorf("not enough peers")
|
||||
}
|
||||
|
||||
runenv.RecordMessage("connmgr parameters: hi=%d, lo=%d", max, min)
|
||||
|
||||
// Generate bogus advertising address
|
||||
tcpAddr, err := getSubnetAddr(runenv.TestSubnet)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
libp2pOpts := []libp2p.Option{
|
||||
libp2p.Identity(idKey),
|
||||
// Use only the TCP transport without reuseport.
|
||||
libp2p.Transport(func(u *tptu.Upgrader) *tcp.TcpTransport {
|
||||
tpt := tcp.NewTCPTransport(u)
|
||||
tpt.DisableReuseport = true
|
||||
return tpt
|
||||
}),
|
||||
// Setup the connection manager to trim to
|
||||
libp2p.ConnectionManager(connmgr.NewConnManager(min, max, ConnManagerGracePeriod)),
|
||||
}
|
||||
|
||||
if info.Properties.Undialable {
|
||||
tcpAddr.Port = rand.Intn(1024) + 1024
|
||||
bogusAddr, err := manet.FromNetAddr(tcpAddr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
bogusAddrLst := []multiaddr.Multiaddr{bogusAddr}
|
||||
|
||||
libp2pOpts = append(libp2pOpts,
|
||||
libp2p.NoListenAddrs,
|
||||
libp2p.AddrsFactory(func(listeningAddrs []multiaddr.Multiaddr) []multiaddr.Multiaddr {
|
||||
return bogusAddrLst
|
||||
}))
|
||||
|
||||
l, err := net.ListenTCP("tcp", tcpAddr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
go func() {
|
||||
for ctx.Err() == nil {
|
||||
c, err := l.Accept()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
go func() {
|
||||
time.Sleep(time.Second * 5)
|
||||
_ = c.Close()
|
||||
}()
|
||||
}
|
||||
}()
|
||||
|
||||
} else {
|
||||
addr, err := manet.FromNetAddr(tcpAddr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
libp2pOpts = append(libp2pOpts,
|
||||
libp2p.ListenAddrs(addr))
|
||||
}
|
||||
|
||||
libp2pOpts = append(libp2pOpts, getTaggedLibp2pOpts(opts, info)...)
|
||||
|
||||
node, err := libp2p.New(ctx, libp2pOpts...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var ds datastore.Batching
|
||||
switch opts.Datastore {
|
||||
case OptDatastoreMemory:
|
||||
ds = dssync.MutexWrap(datastore.NewMapDatastore())
|
||||
case OptDatastoreLeveldb:
|
||||
ds, err = leveldb.NewDatastore("", nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("invalid datastore type")
|
||||
}
|
||||
|
||||
runenv.RecordMessage("creating DHT")
|
||||
|
||||
dht, err := createDHT(ctx, node, ds, opts, info)
|
||||
if err != nil {
|
||||
runenv.RecordMessage("creating DHT error %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
runenv.RecordMessage("creating DHT successful")
|
||||
return node, dht, nil
|
||||
}
|
||||
|
||||
func getSubnetAddr(subnet *runtime.IPNet) (*net.TCPAddr, error) {
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
if ip, ok := addr.(*net.IPNet); ok {
|
||||
if subnet.Contains(ip.IP) {
|
||||
tcpAddr := &net.TCPAddr{IP: ip.IP}
|
||||
return tcpAddr, nil
|
||||
}
|
||||
} else {
|
||||
panic(fmt.Sprintf("%T", addr))
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("no network interface found. Addrs: %v", addrs)
|
||||
}
|
||||
|
||||
var networkSetupNum int
|
||||
var networkSetupMx gosync.Mutex
|
||||
|
||||
// SetupNetwork instructs the sidecar (if enabled) to setup the network for this
|
||||
// test case.
|
||||
func SetupNetwork(ctx context.Context, ri *DHTRunInfo, latency time.Duration) error {
|
||||
if !ri.RunEnv.TestSidecar {
|
||||
return nil
|
||||
}
|
||||
networkSetupMx.Lock()
|
||||
defer networkSetupMx.Unlock()
|
||||
|
||||
if networkSetupNum == 0 {
|
||||
// Wait for the network to be initialized.
|
||||
if err := ri.Client.WaitNetworkInitialized(ctx, ri.RunEnv); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
networkSetupNum++
|
||||
|
||||
// TODO: just put the unique testplan id inside the runenv?
|
||||
hostname, err := os.Hostname()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
state := sync.State(fmt.Sprintf("network-configured-%d", networkSetupNum))
|
||||
|
||||
_, _ = ri.Client.Publish(ctx, sync.NetworkTopic(hostname), &sync.NetworkConfig{
|
||||
Network: "default",
|
||||
Enable: true,
|
||||
Default: sync.LinkShape{
|
||||
Latency: latency,
|
||||
Bandwidth: 10 << 20, // 10Mib
|
||||
},
|
||||
State: state,
|
||||
})
|
||||
|
||||
ri.RunEnv.RecordMessage("finished resetting network latency")
|
||||
|
||||
err = <-ri.Client.MustBarrier(ctx, state, ri.RunEnv.TestInstanceCount).C
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to configure network: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Setup sets up the elements necessary for the test cases
|
||||
func Setup(ctx context.Context, runenv *runtime.RunEnv, opts *SetupOpts) (*DHTRunInfo, error) {
|
||||
if err := initAssets(runenv); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := sync.MustBoundClient(ctx, runenv)
|
||||
//defer watcher.Close()
|
||||
//defer writer.Close()
|
||||
|
||||
ri := &DHTRunInfo{
|
||||
RunInfo: &utils.RunInfo{
|
||||
RunEnv: runenv,
|
||||
Client: client,
|
||||
},
|
||||
DHTGroupProperties: make(map[string]*SetupOpts),
|
||||
}
|
||||
|
||||
// TODO: Take opts.NFindPeers into account when setting a minimum?
|
||||
if ri.RunEnv.TestInstanceCount < minTestInstances {
|
||||
return nil, fmt.Errorf(
|
||||
"requires at least %d instances, only %d started",
|
||||
minTestInstances, ri.RunEnv.TestInstanceCount,
|
||||
)
|
||||
}
|
||||
|
||||
err := SetupNetwork(ctx, ri, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ri.RunEnv.RecordMessage("past the setup network barrier")
|
||||
|
||||
groupSeq, testSeq, err := utils.GetGroupsAndSeqs(ctx, ri.RunInfo, opts.GroupOrder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for g, props := range ri.GroupProperties {
|
||||
fakeEnv := &runtime.RunEnv{
|
||||
RunParams: runtime.RunParams{TestInstanceParams: props.Params},
|
||||
}
|
||||
ri.DHTGroupProperties[g] = GetCommonOpts(fakeEnv)
|
||||
}
|
||||
|
||||
ri.RunEnv.RecordMessage("past nodeid")
|
||||
|
||||
rng := rand.New(rand.NewSource(int64(testSeq)))
|
||||
priv, _, err := crypto.GenerateEd25519Key(rng)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
testNode := &NodeParams{
|
||||
host: nil,
|
||||
dht: nil,
|
||||
info: &DHTNodeInfo{
|
||||
NodeInfo: &tglibp2p.NodeInfo{
|
||||
Seq: testSeq,
|
||||
GroupSeq: groupSeq,
|
||||
Group: ri.RunEnv.TestGroupID,
|
||||
Addrs: nil,
|
||||
},
|
||||
Properties: opts,
|
||||
},
|
||||
}
|
||||
|
||||
testNode.host, testNode.dht, err = NewDHTNode(ctx, ri.RunEnv, opts, priv, testNode.info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
testNode.info.Addrs = host.InfoFromHost(testNode.host)
|
||||
|
||||
otherNodes, err := tglibp2p.ShareAddresses(ctx, ri.RunInfo, testNode.info.NodeInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ri.RunEnv.RecordMessage("finished setup function")
|
||||
|
||||
outputStart(testNode)
|
||||
|
||||
otherDHTNodes := make(map[peer.ID]*DHTNodeInfo, len(otherNodes))
|
||||
for pid, nodeInfo := range otherNodes {
|
||||
otherDHTNodes[pid] = &DHTNodeInfo{
|
||||
NodeInfo: nodeInfo,
|
||||
Properties: ri.DHTGroupProperties[nodeInfo.Group],
|
||||
}
|
||||
}
|
||||
|
||||
ri.Node = testNode
|
||||
ri.Others = otherDHTNodes
|
||||
return ri, nil
|
||||
}
|
||||
|
||||
func GetBootstrapNodes(ri *DHTRunInfo) []peer.AddrInfo {
|
||||
var toDial []peer.AddrInfo
|
||||
nodeInfo := ri.Node.info
|
||||
otherNodes := ri.Others
|
||||
|
||||
switch nodeInfo.Properties.BootstrapStrategy {
|
||||
case 0: // Do nothing
|
||||
return toDial
|
||||
case 1: // Connect to all bootstrappers
|
||||
for _, info := range otherNodes {
|
||||
if info.Properties.Bootstrapper {
|
||||
toDial = append(toDial, *info.Addrs)
|
||||
}
|
||||
}
|
||||
case 2: // Connect to a random bootstrapper (based on our sequence number)
|
||||
// List all the bootstrappers.
|
||||
var bootstrappers []peer.AddrInfo
|
||||
for _, info := range otherNodes {
|
||||
if info.Properties.Bootstrapper {
|
||||
bootstrappers = append(bootstrappers, *info.Addrs)
|
||||
}
|
||||
}
|
||||
|
||||
if len(bootstrappers) > 0 {
|
||||
toDial = append(toDial, bootstrappers[nodeInfo.Seq%len(bootstrappers)])
|
||||
}
|
||||
case 3: // Connect to log(n) random bootstrappers (based on our sequence number)
|
||||
// List all the bootstrappers.
|
||||
var bootstrappers []peer.AddrInfo
|
||||
for _, info := range otherNodes {
|
||||
if info.Properties.Bootstrapper {
|
||||
bootstrappers = append(bootstrappers, *info.Addrs)
|
||||
}
|
||||
}
|
||||
|
||||
added := make(map[int]struct{})
|
||||
if len(bootstrappers) > 0 {
|
||||
targetSize := int(math.Log2(float64(len(bootstrappers)))/2) + 1
|
||||
rng := rand.New(rand.NewSource(int64(nodeInfo.Seq)))
|
||||
for i := 0; i < targetSize; i++ {
|
||||
bsIndex := rng.Int() % len(bootstrappers)
|
||||
if _, found := added[bsIndex]; found {
|
||||
i--
|
||||
continue
|
||||
}
|
||||
toDial = append(toDial, bootstrappers[bsIndex])
|
||||
}
|
||||
}
|
||||
case 4: // dial the _next_ peer in the ring
|
||||
mySeqNo := nodeInfo.Seq
|
||||
var targetSeqNo int
|
||||
if mySeqNo == len(otherNodes) {
|
||||
targetSeqNo = 0
|
||||
} else {
|
||||
targetSeqNo = mySeqNo + 1
|
||||
}
|
||||
// look for the node with sequence number 0
|
||||
for _, info := range otherNodes {
|
||||
if info.Seq == targetSeqNo {
|
||||
toDial = append(toDial, *info.Addrs)
|
||||
break
|
||||
}
|
||||
}
|
||||
case 5: // Connect to all dialable peers
|
||||
toDial = make([]peer.AddrInfo, 0, len(otherNodes))
|
||||
for _, info := range otherNodes {
|
||||
if !info.Properties.Undialable {
|
||||
toDial = append(toDial, *info.Addrs)
|
||||
}
|
||||
}
|
||||
return toDial
|
||||
case 6: // connect to log(n) of the network, where n is the number of dialable nodes
|
||||
plist := make([]*DHTNodeInfo, len(otherNodes)+1)
|
||||
for _, info := range otherNodes {
|
||||
plist[info.Seq] = info
|
||||
}
|
||||
plist[nodeInfo.Seq] = nodeInfo
|
||||
|
||||
numDialable := 0
|
||||
for _, info := range plist {
|
||||
if !info.Properties.Undialable {
|
||||
numDialable++
|
||||
}
|
||||
}
|
||||
|
||||
targetSize := int(math.Log2(float64(numDialable)/2)) + 1
|
||||
|
||||
nodeLst := make([]*DHTNodeInfo, len(plist))
|
||||
copy(nodeLst, plist)
|
||||
rng := rand.New(rand.NewSource(0))
|
||||
rng = rand.New(rand.NewSource(int64(rng.Int31()) + int64(nodeInfo.Seq)))
|
||||
rng.Shuffle(len(nodeLst), func(i, j int) {
|
||||
nodeLst[i], nodeLst[j] = nodeLst[j], nodeLst[i]
|
||||
})
|
||||
|
||||
for _, info := range nodeLst {
|
||||
if len(toDial) > targetSize {
|
||||
break
|
||||
}
|
||||
if info.Seq != nodeInfo.Seq && !info.Properties.Undialable {
|
||||
toDial = append(toDial, *info.Addrs)
|
||||
}
|
||||
}
|
||||
case 7: // connect to log(server nodes) and log(other dialable nodes)
|
||||
plist := make([]*DHTNodeInfo, len(otherNodes)+1)
|
||||
for _, info := range otherNodes {
|
||||
plist[info.Seq] = info
|
||||
}
|
||||
plist[nodeInfo.Seq] = nodeInfo
|
||||
|
||||
numServer := 0
|
||||
numOtherDialable := 0
|
||||
for _, info := range plist {
|
||||
if info.Properties.ExpectedServer {
|
||||
numServer++
|
||||
} else if !info.Properties.Undialable {
|
||||
numOtherDialable++
|
||||
}
|
||||
}
|
||||
|
||||
targetServerNodes := int(math.Log2(float64(numServer/2))) + 1
|
||||
targetOtherNodes := int(math.Log2(float64(numOtherDialable/2))) + 1
|
||||
|
||||
serverAddrs := getBootstrapAddrs(plist, nodeInfo, targetServerNodes, 0, func(info *DHTNodeInfo) bool {
|
||||
if info.Seq != nodeInfo.Seq && info.Properties.ExpectedServer {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
otherAddrs := getBootstrapAddrs(plist, nodeInfo, targetOtherNodes, 0, func(info *DHTNodeInfo) bool {
|
||||
if info.Seq != nodeInfo.Seq && info.Properties.ExpectedServer {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
toDial = append(toDial, serverAddrs...)
|
||||
toDial = append(toDial, otherAddrs...)
|
||||
default:
|
||||
panic(fmt.Errorf("invalid number of bootstrap strategy %d", ri.Node.info.Properties.BootstrapStrategy))
|
||||
}
|
||||
|
||||
return toDial
|
||||
}
|
||||
|
||||
func getBootstrapAddrs(plist []*DHTNodeInfo, nodeInfo *DHTNodeInfo, targetSize int, rngSeed int64, valid func(info *DHTNodeInfo) bool) (toDial []peer.AddrInfo) {
|
||||
nodeLst := make([]*DHTNodeInfo, len(plist))
|
||||
copy(nodeLst, plist)
|
||||
rng := rand.New(rand.NewSource(rngSeed))
|
||||
rng = rand.New(rand.NewSource(int64(rng.Int31()) + int64(nodeInfo.Seq)))
|
||||
rng.Shuffle(len(nodeLst), func(i, j int) {
|
||||
nodeLst[i], nodeLst[j] = nodeLst[j], nodeLst[i]
|
||||
})
|
||||
|
||||
for _, info := range nodeLst {
|
||||
if len(toDial) > targetSize {
|
||||
break
|
||||
}
|
||||
if valid(info) {
|
||||
toDial = append(toDial, *info.Addrs)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Bootstrap brings the network into a completely bootstrapped and ready state.
|
||||
//
|
||||
// 1. Connect:
|
||||
// a. If any bootstrappers are defined, it connects them together and connects all other peers to one of the bootstrappers (deterministically).
|
||||
// b. Otherwise, every peer is connected to the next peer (in lexicographical peer ID order).
|
||||
// 2. Routing: Refresh all the routing tables.
|
||||
// 3. Trim: Wait out the grace period then invoke the connection manager to simulate a running network with connection churn.
|
||||
// 4. Forget & Reconnect:
|
||||
// a. Forget the addresses of all peers we've disconnected from. Otherwise, FindPeer is useless.
|
||||
// b. Re-connect to at least one node if we've disconnected from _all_ nodes.
|
||||
// We may want to make this an error in the future?
|
||||
func Bootstrap(ctx context.Context, ri *DHTRunInfo, bootstrapNodes []peer.AddrInfo) error {
|
||||
runenv := ri.RunEnv
|
||||
|
||||
defer runenv.RecordMessage("bootstrap phase ended")
|
||||
|
||||
node := ri.Node
|
||||
dht := node.dht
|
||||
|
||||
stager := utils.NewBatchStager(ctx, node.info.Seq, runenv.TestInstanceCount, "bootstrapping", ri.RunInfo)
|
||||
|
||||
////////////////
|
||||
// 1: CONNECT //
|
||||
////////////////
|
||||
|
||||
runenv.RecordMessage("bootstrap: begin connect")
|
||||
|
||||
// Wait until it's our turn to bootstrap
|
||||
|
||||
gradualBsStager := utils.NewGradualStager(ctx, node.info.Seq, runenv.TestInstanceCount,
|
||||
"boostrap-gradual", ri.RunInfo, utils.LinearGradualStaging(100))
|
||||
if err := gradualBsStager.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runenv.RecordMessage("bootstrap: dialing %v", bootstrapNodes)
|
||||
|
||||
// Connect to our peers.
|
||||
if err := Connect(ctx, runenv, dht, bootstrapNodes...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runenv.RecordMessage("bootstrap: dialed %d other peers", len(bootstrapNodes))
|
||||
|
||||
// TODO: Use an updated autonat that doesn't require this
|
||||
// Wait for Autonat to kick in
|
||||
time.Sleep(time.Second * 30)
|
||||
|
||||
if err := Connect(ctx, runenv, dht, bootstrapNodes...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Second * 5)
|
||||
for {
|
||||
<-ticker.C
|
||||
if node.dht.RoutingTable().Size() < 2 {
|
||||
_ = Connect(ctx, runenv, dht, bootstrapNodes...)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
////////////////
|
||||
// 2: ROUTING //
|
||||
////////////////
|
||||
|
||||
// Wait for these peers to be added to the routing table.
|
||||
if err := WaitRoutingTable(ctx, runenv, dht); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runenv.RecordMessage("bootstrap: have peer in routing table")
|
||||
|
||||
runenv.RecordMessage("bootstrap: begin routing")
|
||||
|
||||
outputGraph(node.dht, "br")
|
||||
|
||||
rrt := func() error {
|
||||
if err := <-dht.RefreshRoutingTable(); err != nil {
|
||||
runenv.RecordMessage("bootstrap: refresh failure - rt size %d", dht.RoutingTable().Size())
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Setup our routing tables.
|
||||
ready := false
|
||||
numTries, maxNumTries := 1, 3
|
||||
for !ready {
|
||||
if err := rrt(); err != nil {
|
||||
if numTries >= maxNumTries {
|
||||
outputGraph(dht, "failedrefresh")
|
||||
return err
|
||||
}
|
||||
numTries++
|
||||
if err := Connect(ctx, runenv, dht, bootstrapNodes...); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
ready = true
|
||||
}
|
||||
}
|
||||
|
||||
runenv.RecordMessage("bootstrap: table ready")
|
||||
|
||||
// TODO: Repeat this a few times until our tables have stabilized? That
|
||||
// _shouldn't_ be necessary.
|
||||
|
||||
runenv.RecordMessage("bootstrap: everyone table ready")
|
||||
|
||||
outputGraph(node.dht, "ar")
|
||||
|
||||
/////////////
|
||||
// 3: TRIM //
|
||||
/////////////
|
||||
|
||||
if err := gradualBsStager.End(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Need to wait for connections to exit the grace period.
|
||||
time.Sleep(2 * ConnManagerGracePeriod)
|
||||
|
||||
runenv.RecordMessage("bootstrap: begin trim")
|
||||
|
||||
// Force the connection manager to do it's dirty work. DIE CONNECTIONS
|
||||
// DIE!
|
||||
dht.Host().ConnManager().TrimOpenConns(ctx)
|
||||
|
||||
outputGraph(node.dht, "at")
|
||||
|
||||
///////////////////////////
|
||||
// 4: FORGET & RECONNECT //
|
||||
///////////////////////////
|
||||
|
||||
if err := stager.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Forget all peers we're no longer connected to. We need to do this
|
||||
// _after_ we wait for everyone to trim so we can forget peers that
|
||||
// disconnected from us.
|
||||
forgotten := 0
|
||||
for _, p := range dht.Host().Peerstore().Peers() {
|
||||
if dht.RoutingTable().Find(p) == "" && dht.Host().Network().Connectedness(p) != network.Connected {
|
||||
forgotten++
|
||||
dht.Host().Peerstore().ClearAddrs(p)
|
||||
}
|
||||
}
|
||||
|
||||
runenv.RecordMessage("bootstrap: forgotten %d peers", forgotten)
|
||||
|
||||
// Make sure we have at least one peer. If not, reconnect to a
|
||||
// bootstrapper and log a warning.
|
||||
if len(dht.Host().Network().Peers()) == 0 {
|
||||
// TODO: Report this as an error?
|
||||
runenv.RecordMessage("bootstrap: fully disconnected, reconnecting.")
|
||||
if err := Connect(ctx, runenv, dht, bootstrapNodes...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := WaitRoutingTable(ctx, runenv, dht); err != nil {
|
||||
return err
|
||||
}
|
||||
runenv.RecordMessage("bootstrap: finished reconnecting to %d peers", len(bootstrapNodes))
|
||||
}
|
||||
|
||||
tmpCtx, tmpc := context.WithTimeout(ctx, time.Second*10)
|
||||
if err := WaitRoutingTable(tmpCtx, runenv, dht); err != nil {
|
||||
tmpc()
|
||||
return err
|
||||
}
|
||||
if tmpCtx.Err() != nil {
|
||||
runenv.RecordMessage("peer %s failed with rt of size %d", node.host.ID().Pretty(), node.dht.RoutingTable().Size())
|
||||
}
|
||||
tmpc()
|
||||
|
||||
if err := stager.End(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
outputGraph(node.dht, "ab")
|
||||
|
||||
runenv.RecordMessage(
|
||||
"bootstrap: finished with %d connections, %d in the routing table",
|
||||
len(dht.Host().Network().Peers()),
|
||||
dht.RoutingTable().Size(),
|
||||
)
|
||||
|
||||
TableHealth(dht, ri.Others, ri)
|
||||
|
||||
runenv.RecordMessage("bootstrap: done")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Connect connects a host to a set of peers.
|
||||
//
|
||||
// Automatically skips our own peer.
|
||||
func Connect(ctx context.Context, runenv *runtime.RunEnv, dht *kaddht.IpfsDHT, toDial ...peer.AddrInfo) error {
|
||||
tryConnect := func(ctx context.Context, ai peer.AddrInfo, attempts int) error {
|
||||
var err error
|
||||
for i := 1; i <= attempts; i++ {
|
||||
runenv.RecordMessage("dialling peer %s (attempt %d)", ai.ID, i)
|
||||
if err = dht.Host().Connect(ctx, ai); err == nil {
|
||||
return nil
|
||||
} else {
|
||||
runenv.RecordMessage("failed to dial peer %v (attempt %d), err: %s", ai.ID, i, err)
|
||||
}
|
||||
select {
|
||||
case <-time.After(time.Duration(rand.Intn(3000))*time.Millisecond + 2*time.Second):
|
||||
case <-ctx.Done():
|
||||
return fmt.Errorf("error while dialing peer %v, attempts made: %d: %w", ai.Addrs, i, ctx.Err())
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("failed while dialing peer %v, attempts: %d: %w", ai.Addrs, attempts, err)
|
||||
}
|
||||
|
||||
// Dial to all the other peers.
|
||||
var err error
|
||||
numFailedConnections := 0
|
||||
numAttemptedConnections := 0
|
||||
for _, ai := range toDial {
|
||||
if ai.ID == dht.Host().ID() {
|
||||
continue
|
||||
}
|
||||
numAttemptedConnections++
|
||||
if err = tryConnect(ctx, ai, 3); err != nil {
|
||||
numFailedConnections++
|
||||
}
|
||||
}
|
||||
if float64(numFailedConnections)/float64(numAttemptedConnections) > 0.75 {
|
||||
return errors.Wrap(err, "too high percentage of failed connections")
|
||||
}
|
||||
if numAttemptedConnections-numFailedConnections <= 1 {
|
||||
return errors.Wrap(err, "insufficient connections formed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RandomWalk performs 5 random walks.
|
||||
func RandomWalk(ctx context.Context, runenv *runtime.RunEnv, dht *kaddht.IpfsDHT) error {
|
||||
for i := 0; i < 5; i++ {
|
||||
if err := dht.Bootstrap(ctx); err != nil {
|
||||
return fmt.Errorf("Could not run a random-walk: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Base(ctx context.Context, runenv *runtime.RunEnv, commonOpts *SetupOpts) (*DHTRunInfo, error) {
|
||||
ectx := specializedTraceQuery(ctx, runenv, "bootstrap-network")
|
||||
ri, err := Setup(ectx, runenv, commonOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Bring the network into a nice, stable, bootstrapped state.
|
||||
if err = Bootstrap(ectx, ri, GetBootstrapNodes(ri)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if commonOpts.RandomWalk {
|
||||
if err = RandomWalk(ectx, runenv, ri.Node.dht); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := SetupNetwork(ectx, ri, commonOpts.Latency); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ri, nil
|
||||
}
|
||||
|
||||
// Sync synchronizes all test instances around a single sync point.
|
||||
func Sync(
|
||||
ctx context.Context,
|
||||
ri *utils.RunInfo,
|
||||
state sync.State,
|
||||
) error {
|
||||
// Set a state barrier.
|
||||
doneCh := ri.Client.MustBarrier(ctx, state, ri.RunEnv.TestInstanceCount).C
|
||||
|
||||
// Signal we're in the same state.
|
||||
_, err := ri.Client.SignalEntry(ctx, state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait until all others have signalled.
|
||||
return <-doneCh
|
||||
}
|
||||
|
||||
// WaitRoutingTable waits until the routing table is not empty.
|
||||
func WaitRoutingTable(ctx context.Context, runenv *runtime.RunEnv, dht *kaddht.IpfsDHT) error {
|
||||
//ctxt, cancel := context.WithTimeout(ctx, time.Second*10)
|
||||
//defer cancel()
|
||||
for {
|
||||
if dht.RoutingTable().Size() > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
t := time.NewTimer(time.Second * 10)
|
||||
|
||||
select {
|
||||
case <-time.After(200 * time.Millisecond):
|
||||
case <-t.C:
|
||||
runenv.RecordMessage("waiting on routing table")
|
||||
case <-ctx.Done():
|
||||
peers := dht.Host().Network().Peers()
|
||||
errStr := fmt.Sprintf("empty rt. %d peer conns. they are %v", len(peers), peers)
|
||||
runenv.RecordMessage(errStr)
|
||||
return fmt.Errorf(errStr)
|
||||
//return fmt.Errorf("got no peers in routing table")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Teardown concludes this test case, waiting for all other instances to reach
|
||||
// the 'end' state first.
|
||||
func Teardown(ctx context.Context, ri *utils.RunInfo) {
|
||||
err := Sync(ctx, ri, "end")
|
||||
if err != nil {
|
||||
ri.RunEnv.RecordFailure(fmt.Errorf("end sync failed: %w", err))
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
var graphLogger, rtLogger, nodeLogger *zap.SugaredLogger
|
||||
|
||||
func initAssets(runenv *runtime.RunEnv) error {
|
||||
var err error
|
||||
_, graphLogger, err = runenv.CreateStructuredAsset("dht_graphs.out", runtime.StandardJSONConfig())
|
||||
if err != nil {
|
||||
runenv.RecordMessage("failed to initialize dht_graphs.out asset; nooping logger: %s", err)
|
||||
graphLogger = zap.NewNop().Sugar()
|
||||
return err
|
||||
}
|
||||
|
||||
_, rtLogger, err = runenv.CreateStructuredAsset("dht_rt.out", runtime.StandardJSONConfig())
|
||||
if err != nil {
|
||||
runenv.RecordMessage("failed to initialize dht_rt.out asset; nooping logger: %s", err)
|
||||
rtLogger = zap.NewNop().Sugar()
|
||||
return err
|
||||
}
|
||||
|
||||
_, nodeLogger, err = runenv.CreateStructuredAsset("node.out", runtime.StandardJSONConfig())
|
||||
if err != nil {
|
||||
runenv.RecordMessage("failed to initialize node.out asset; nooping logger: %s", err)
|
||||
nodeLogger = zap.NewNop().Sugar()
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func outputGraph(dht *kaddht.IpfsDHT, graphID string) {
|
||||
for _, c := range dht.Host().Network().Conns() {
|
||||
if c.Stat().Direction == network.DirOutbound {
|
||||
graphLogger.Infow(graphID, "From", c.LocalPeer().Pretty(), "To", c.RemotePeer().Pretty())
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range dht.RoutingTable().ListPeers() {
|
||||
rtLogger.Infow(graphID, "Node", dht.PeerID().Pretty(), "Peer", p.Pretty())
|
||||
}
|
||||
}
|
||||
|
||||
func outputStart(node *NodeParams) {
|
||||
nodeLogger.Infow("nodeparams",
|
||||
"seq", node.info.Seq,
|
||||
"dialable", !node.info.Properties.Undialable,
|
||||
"peerID", node.info.Addrs.ID.Pretty(),
|
||||
"addrs", node.info.Addrs.Addrs,
|
||||
)
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
// +build balsam
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-ipns"
|
||||
"github.com/testground/sdk-go/runtime"
|
||||
"github.com/libp2p/go-libp2p"
|
||||
"github.com/libp2p/go-libp2p-core/host"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
kaddht "github.com/libp2p/go-libp2p-kad-dht"
|
||||
dhtopts "github.com/libp2p/go-libp2p-kad-dht/opts"
|
||||
)
|
||||
|
||||
func createDHT(ctx context.Context, h host.Host, ds datastore.Batching, opts *SetupOpts, info *DHTNodeInfo) (*kaddht.IpfsDHT, error) {
|
||||
dhtOptions := []dhtopts.Option{
|
||||
dhtopts.Protocols("/testground/kad/1.0.0"),
|
||||
dhtopts.Datastore(ds),
|
||||
dhtopts.BucketSize(opts.BucketSize),
|
||||
dhtopts.RoutingTableRefreshQueryTimeout(opts.Timeout),
|
||||
dhtopts.NamespacedValidator("ipns", ipns.Validator{KeyBook: h.Peerstore()}),
|
||||
}
|
||||
|
||||
if !opts.AutoRefresh {
|
||||
dhtOptions = append(dhtOptions, dhtopts.DisableAutoRefresh())
|
||||
}
|
||||
|
||||
if info.Properties.Undialable && opts.ClientMode {
|
||||
dhtOptions = append(dhtOptions, dhtopts.Client(true))
|
||||
}
|
||||
|
||||
dht, err := kaddht.New(ctx, h, dhtOptions...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dht, nil
|
||||
}
|
||||
|
||||
func getTaggedLibp2pOpts(opts *SetupOpts, info *DHTNodeInfo) []libp2p.Option { return nil }
|
||||
|
||||
func getAllProvRecordsNum() int { return 1000 }
|
||||
|
||||
func specializedTraceQuery(ctx context.Context, runenv *runtime.RunEnv, tag string) context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func TableHealth(dht *kaddht.IpfsDHT, peers map[peer.ID]*DHTNodeInfo, ri *DHTRunInfo) {}
|
||||
@@ -1,134 +0,0 @@
|
||||
// +build cypress
|
||||
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/testground/sdk-go/runtime"
|
||||
|
||||
"github.com/libp2p/go-libp2p"
|
||||
"github.com/libp2p/go-libp2p-core/host"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/ipfs/go-ipns"
|
||||
|
||||
kaddht "github.com/libp2p/go-libp2p-kad-dht"
|
||||
kbucket "github.com/libp2p/go-libp2p-kbucket"
|
||||
"github.com/libp2p/go-libp2p-xor/kademlia"
|
||||
"github.com/libp2p/go-libp2p-xor/key"
|
||||
"github.com/libp2p/go-libp2p-xor/trie"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func createDHT(ctx context.Context, h host.Host, ds datastore.Batching, opts *SetupOpts, info *DHTNodeInfo) (*kaddht.IpfsDHT, error) {
|
||||
dhtOptions := []kaddht.Option{
|
||||
kaddht.ProtocolPrefix("/testground"),
|
||||
kaddht.V1CompatibleMode(false),
|
||||
kaddht.Datastore(ds),
|
||||
kaddht.BucketSize(opts.BucketSize),
|
||||
kaddht.RoutingTableRefreshQueryTimeout(opts.Timeout),
|
||||
kaddht.Concurrency(opts.Alpha),
|
||||
kaddht.Resiliency(opts.Beta),
|
||||
kaddht.NamespacedValidator("ipns", ipns.Validator{KeyBook: h.Peerstore()}),
|
||||
}
|
||||
|
||||
if !opts.AutoRefresh {
|
||||
dhtOptions = append(dhtOptions, kaddht.DisableAutoRefresh())
|
||||
}
|
||||
|
||||
if info.Properties.Bootstrapper {
|
||||
dhtOptions = append(dhtOptions, kaddht.Mode(kaddht.ModeServer))
|
||||
} else if info.Properties.Undialable && opts.ClientMode {
|
||||
dhtOptions = append(dhtOptions, kaddht.Mode(kaddht.ModeClient))
|
||||
}
|
||||
|
||||
dht, err := kaddht.New(ctx, h, dhtOptions...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dht, nil
|
||||
}
|
||||
|
||||
func getTaggedLibp2pOpts(opts *SetupOpts, info *DHTNodeInfo) []libp2p.Option {
|
||||
if info.Properties.Bootstrapper {
|
||||
return []libp2p.Option{libp2p.EnableNATService(), libp2p.WithReachability(true)}
|
||||
} else {
|
||||
return []libp2p.Option{libp2p.EnableNATService()}
|
||||
}
|
||||
}
|
||||
|
||||
func getAllProvRecordsNum() int { return 0 }
|
||||
|
||||
var (
|
||||
sqonce sync.Once
|
||||
sqlogger, rtlogger *zap.SugaredLogger
|
||||
)
|
||||
|
||||
func specializedTraceQuery(ctx context.Context, runenv *runtime.RunEnv, tag string) context.Context {
|
||||
sqonce.Do(func() {
|
||||
var err error
|
||||
_, sqlogger, err = runenv.CreateStructuredAsset("dht_lookups.out", runtime.StandardJSONConfig())
|
||||
if err != nil {
|
||||
runenv.RecordMessage("failed to initialize dht_lookups.out asset; nooping logger: %s", err)
|
||||
sqlogger = zap.NewNop().Sugar()
|
||||
}
|
||||
_, rtlogger, err = runenv.CreateStructuredAsset("rt_evts.out", runtime.StandardJSONConfig())
|
||||
if err != nil {
|
||||
runenv.RecordMessage("failed to initialize dht_lookups.out asset; nooping logger: %s", err)
|
||||
rtlogger = zap.NewNop().Sugar()
|
||||
}
|
||||
})
|
||||
|
||||
ectx, events := kaddht.RegisterForLookupEvents(ctx)
|
||||
ectx, rtEvts := kaddht.RegisterForRoutingTableEvents(ectx)
|
||||
|
||||
lookupLogger := sqlogger.With("tag", tag)
|
||||
routingTableLogger := rtlogger.With("tag", tag)
|
||||
|
||||
go func() {
|
||||
for e := range events {
|
||||
lookupLogger.Infow("lookup event", "info", e)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for e := range rtEvts {
|
||||
routingTableLogger.Infow("rt event", "info", e)
|
||||
}
|
||||
}()
|
||||
|
||||
return ectx
|
||||
}
|
||||
|
||||
// TableHealth computes health reports for a network of nodes, whose routing contacts are given.
|
||||
func TableHealth(dht *kaddht.IpfsDHT, peers map[peer.ID]*DHTNodeInfo, ri *DHTRunInfo) {
|
||||
// Construct global network view trie
|
||||
var kn []key.Key
|
||||
knownNodes := trie.New()
|
||||
for p, info := range peers {
|
||||
if info.Properties.ExpectedServer {
|
||||
k := kadPeerID(p)
|
||||
kn = append(kn, k)
|
||||
knownNodes.Add(k)
|
||||
}
|
||||
}
|
||||
|
||||
rtPeerIDs := dht.RoutingTable().ListPeers()
|
||||
rtPeers := make([]key.Key, len(rtPeerIDs))
|
||||
for i, p := range rtPeerIDs {
|
||||
rtPeers[i] = kadPeerID(p)
|
||||
}
|
||||
|
||||
report := kademlia.TableHealth(kadPeerID(dht.PeerID()), rtPeers, knownNodes)
|
||||
ri.RunEnv.RecordMessage("table health: %s", report.String())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func kadPeerID(p peer.ID) key.Key {
|
||||
return key.KbucketIDToKey(kbucket.ConvertPeerID(p))
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/libp2p/test-plans/dht/utils"
|
||||
"time"
|
||||
|
||||
"github.com/testground/sdk-go/runtime"
|
||||
)
|
||||
|
||||
func FindPeers(runenv *runtime.RunEnv) error {
|
||||
commonOpts := GetCommonOpts(runenv)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), commonOpts.Timeout)
|
||||
defer cancel()
|
||||
|
||||
ri, err := Base(ctx, runenv, commonOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := TestFindPeers(ctx, ri); err != nil {
|
||||
return err
|
||||
}
|
||||
Teardown(ctx, ri.RunInfo)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestFindPeers(ctx context.Context, ri *DHTRunInfo) error {
|
||||
runenv := ri.RunEnv
|
||||
|
||||
nFindPeers := runenv.IntParam("n_find_peers")
|
||||
|
||||
if nFindPeers > runenv.TestInstanceCount {
|
||||
return fmt.Errorf("NFindPeers greater than the number of test instances")
|
||||
}
|
||||
|
||||
node := ri.Node
|
||||
peers := ri.Others
|
||||
|
||||
stager := utils.NewBatchStager(ctx, node.info.Seq, runenv.TestInstanceCount, "peer-records", ri.RunInfo)
|
||||
|
||||
// Ok, we're _finally_ ready.
|
||||
// TODO: Dump routing table stats. We should dump:
|
||||
//
|
||||
// * How full our "closest" bucket is. That is, look at the "all peers"
|
||||
// list, find the BucketSize closest peers, and determine the % of those
|
||||
// peers to which we're connected. It should be close to 100%.
|
||||
// * How many peers we're actually connected to?
|
||||
// * How many of our connected peers are actually useful to us?
|
||||
|
||||
// Perform FIND_PEER N times.
|
||||
|
||||
if err := stager.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
found := 0
|
||||
for p, info := range peers {
|
||||
if found >= nFindPeers {
|
||||
break
|
||||
}
|
||||
if len(node.host.Peerstore().Addrs(p)) > 0 {
|
||||
// Skip peer's we've already found (even if we've
|
||||
// disconnected for some reason).
|
||||
continue
|
||||
}
|
||||
|
||||
if info.Properties.Undialable || node.info.Addrs.ID == info.Addrs.ID {
|
||||
continue
|
||||
}
|
||||
|
||||
runenv.RecordMessage("start find peer number %d", found+1)
|
||||
|
||||
ectx, cancel := context.WithCancel(ctx)
|
||||
ectx = TraceQuery(ectx, runenv, node, p.Pretty(), "peer-records")
|
||||
|
||||
t := time.Now()
|
||||
|
||||
// TODO: Instrument libp2p dht to get:
|
||||
// - Number of peers dialed
|
||||
// - Number of dials along the way that failed
|
||||
_, err := node.dht.FindPeer(ectx, p)
|
||||
cancel()
|
||||
if err != nil {
|
||||
runenv.RecordMessage("find peer failed: peer %s : %s", p, err)
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("time-to-failed-peer-%d", found),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(time.Since(t).Nanoseconds()))
|
||||
} else {
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("time-to-peer-%d", found),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(time.Since(t).Nanoseconds()))
|
||||
}
|
||||
|
||||
found++
|
||||
}
|
||||
|
||||
if err := stager.End(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,242 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/libp2p/test-plans/dht/utils"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
u "github.com/ipfs/go-ipfs-util"
|
||||
"github.com/testground/sdk-go/runtime"
|
||||
)
|
||||
|
||||
type findProvsParams struct {
|
||||
RecordSeed int
|
||||
RecordCount int
|
||||
SearchRecords bool
|
||||
}
|
||||
|
||||
func getFindProvsParams(params map[string]string) findProvsParams {
|
||||
tmpRunEnv := runtime.RunEnv{RunParams: runtime.RunParams{
|
||||
TestInstanceParams: params,
|
||||
}}
|
||||
|
||||
fpOpts := findProvsParams{
|
||||
RecordSeed: tmpRunEnv.IntParam("record_seed"),
|
||||
RecordCount: tmpRunEnv.IntParam("record_count"),
|
||||
SearchRecords: tmpRunEnv.BooleanParam("search_records"),
|
||||
}
|
||||
|
||||
return fpOpts
|
||||
}
|
||||
|
||||
func FindProviders(runenv *runtime.RunEnv) error {
|
||||
commonOpts := GetCommonOpts(runenv)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), commonOpts.Timeout)
|
||||
defer cancel()
|
||||
|
||||
ri, err := Base(ctx, runenv, commonOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := TestProviderRecords(ctx, ri); err != nil {
|
||||
return err
|
||||
}
|
||||
Teardown(ctx, ri.RunInfo)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestProviderRecords(ctx context.Context, ri *DHTRunInfo) error {
|
||||
runenv := ri.RunEnv
|
||||
node := ri.Node
|
||||
|
||||
fpOpts := getFindProvsParams(ri.RunEnv.RunParams.TestInstanceParams)
|
||||
|
||||
stager := utils.NewBatchStager(ctx, node.info.Seq, runenv.TestInstanceCount, "provider-records", ri.RunInfo)
|
||||
|
||||
emitRecords, searchRecords := getRecords(ri, fpOpts)
|
||||
|
||||
if err := stager.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runenv.RecordMessage("start provide loop")
|
||||
|
||||
// If we're a member of the providing cohort, let's provide those CIDs to
|
||||
// the network.
|
||||
if fpOpts.RecordCount > 0 {
|
||||
g := errgroup.Group{}
|
||||
for index, cid := range emitRecords {
|
||||
i := index
|
||||
c := cid
|
||||
g.Go(func() error {
|
||||
p := peer.ID(c.Bytes())
|
||||
ectx, cancel := context.WithCancel(ctx) //nolint
|
||||
ectx = TraceQuery(ctx, runenv, node, p.Pretty(), "provider-records")
|
||||
t := time.Now()
|
||||
err := node.dht.Provide(ectx, c, true)
|
||||
cancel()
|
||||
if err == nil {
|
||||
runenv.RecordMessage("Provided CID: %s", c)
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("time-to-provide-%d", i),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(time.Since(t).Nanoseconds()))
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
_ = stager.End()
|
||||
return fmt.Errorf("failed while providing: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := stager.End(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
outputGraph(node.dht, "after_provide")
|
||||
|
||||
if err := stager.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fpOpts.SearchRecords {
|
||||
g := errgroup.Group{}
|
||||
for _, record := range searchRecords {
|
||||
for index, cid := range record.RecordIDs {
|
||||
i := index
|
||||
c := cid
|
||||
groupID := record.GroupID
|
||||
g.Go(func() error {
|
||||
p := peer.ID(c.Bytes())
|
||||
ectx, cancel := context.WithCancel(ctx) //nolint
|
||||
ectx = TraceQuery(ctx, runenv, node, p.Pretty(), "provider-records")
|
||||
t := time.Now()
|
||||
|
||||
numProvs := 0
|
||||
provsCh := node.dht.FindProvidersAsync(ectx, c, getAllProvRecordsNum())
|
||||
status := "done"
|
||||
|
||||
var tLastFound time.Time
|
||||
provLoop:
|
||||
for {
|
||||
select {
|
||||
case _, ok := <-provsCh:
|
||||
if !ok {
|
||||
break provLoop
|
||||
}
|
||||
|
||||
tLastFound = time.Now()
|
||||
|
||||
if numProvs == 0 {
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("time-to-find-first|%s|%d", groupID, i),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(tLastFound.Sub(t).Nanoseconds()))
|
||||
}
|
||||
|
||||
numProvs++
|
||||
case <-ctx.Done():
|
||||
status = "incomplete"
|
||||
break provLoop
|
||||
}
|
||||
}
|
||||
cancel()
|
||||
|
||||
if numProvs > 0 {
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("time-to-find-last|%s|%s|%d", status, groupID, i),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(tLastFound.Sub(t).Nanoseconds()))
|
||||
} else if status != "incomplete" {
|
||||
status = "fail"
|
||||
}
|
||||
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("time-to-find|%s|%s|%d", status, groupID, i),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(time.Since(t).Nanoseconds()))
|
||||
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("peers-found|%s|%s|%d", status, groupID, i),
|
||||
Unit: "peers",
|
||||
ImprovementDir: 1,
|
||||
}, float64(numProvs))
|
||||
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("peers-missing|%s|%s|%d", status, groupID, i),
|
||||
Unit: "peers",
|
||||
ImprovementDir: -1,
|
||||
}, float64(ri.GroupProperties[groupID].Size-numProvs))
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
_ = stager.End()
|
||||
return fmt.Errorf("failed while finding providerss: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := stager.End(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getRecords returns the records we plan to store and those we plan to search for. It also tells other nodes via the
|
||||
// sync service which nodes our group plans on advertising
|
||||
func getRecords(ri *DHTRunInfo, fpOpts findProvsParams) ([]cid.Cid, []*ProviderRecordSubmission) {
|
||||
recGen := func(groupID string, groupFPOpts findProvsParams) (out []cid.Cid) {
|
||||
for i := 0; i < groupFPOpts.RecordCount; i++ {
|
||||
c := fmt.Sprintf("CID %d - group %s - seeded with %d", i, groupID, groupFPOpts.RecordSeed)
|
||||
out = append(out, cid.NewCidV0(u.Hash([]byte(c))))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
var emitRecords []cid.Cid
|
||||
if fpOpts.RecordCount > 0 {
|
||||
// Calculate the CIDs we're dealing with.
|
||||
emitRecords = recGen(ri.Node.info.Group, fpOpts)
|
||||
}
|
||||
|
||||
var searchRecords []*ProviderRecordSubmission
|
||||
if fpOpts.SearchRecords {
|
||||
for _, g := range ri.Groups {
|
||||
gOpts := ri.GroupProperties[g]
|
||||
groupFPOpts := getFindProvsParams(gOpts.Params)
|
||||
if groupFPOpts.RecordCount > 0 {
|
||||
searchRecords = append(searchRecords, &ProviderRecordSubmission{
|
||||
RecordIDs: recGen(g, groupFPOpts),
|
||||
GroupID: g,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return emitRecords, searchRecords
|
||||
}
|
||||
|
||||
type ProviderRecordSubmission struct {
|
||||
RecordIDs []cid.Cid
|
||||
GroupID string
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/libp2p/test-plans/dht/utils"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
u "github.com/ipfs/go-ipfs-util"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
kbucket "github.com/libp2p/go-libp2p-kbucket"
|
||||
|
||||
"github.com/testground/sdk-go/runtime"
|
||||
)
|
||||
|
||||
func GetClosestPeers(runenv *runtime.RunEnv) error {
|
||||
commonOpts := GetCommonOpts(runenv)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), commonOpts.Timeout)
|
||||
defer cancel()
|
||||
|
||||
ri, err := Base(ctx, runenv, commonOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := TestGetClosestPeers(ctx, ri); err != nil {
|
||||
return err
|
||||
}
|
||||
Teardown(ctx, ri.RunInfo)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestGetClosestPeers(ctx context.Context, ri *DHTRunInfo) error {
|
||||
fpOpts := getFindProvsParams(ri.RunEnv.RunParams.TestInstanceParams)
|
||||
runenv := ri.RunEnv
|
||||
|
||||
// TODO: This is hacky we should probably thread through a separate GCPRecordCount variable
|
||||
maxRecCount := 0
|
||||
for _, g := range ri.GroupProperties {
|
||||
gOpts := getFindProvsParams(g.Params)
|
||||
if gOpts.RecordCount > maxRecCount {
|
||||
maxRecCount = gOpts.RecordCount
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the CIDs we're dealing with.
|
||||
cids := func() (out []cid.Cid) {
|
||||
for i := 0; i < maxRecCount; i++ {
|
||||
c := fmt.Sprintf("CID %d - seeded with %d", i, fpOpts.RecordSeed)
|
||||
out = append(out, cid.NewCidV0(u.Hash([]byte(c))))
|
||||
}
|
||||
return out
|
||||
}()
|
||||
|
||||
node := ri.Node
|
||||
others := ri.Others
|
||||
|
||||
stager := utils.NewBatchStager(ctx, node.info.Seq, runenv.TestInstanceCount, "get-closest-peers", ri.RunInfo)
|
||||
if err := stager.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
runenv.RecordMessage("start gcp loop")
|
||||
if fpOpts.SearchRecords {
|
||||
g := errgroup.Group{}
|
||||
for index, cid := range cids {
|
||||
i := index
|
||||
c := cid
|
||||
g.Go(func() error {
|
||||
p := peer.ID(c.Bytes())
|
||||
ectx, cancel := context.WithCancel(ctx)
|
||||
ectx = TraceQuery(ectx, runenv, node, p.Pretty(), "get-closest-peers")
|
||||
t := time.Now()
|
||||
pids, err := node.dht.GetClosestPeers(ectx, c.KeyString())
|
||||
cancel()
|
||||
|
||||
peers := make([]peer.ID, 0, node.info.Properties.BucketSize)
|
||||
for p := range pids {
|
||||
peers = append(peers, p)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("time-to-gcp-%d", i),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(time.Since(t).Nanoseconds()))
|
||||
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("gcp-peers-found-%d", i),
|
||||
Unit: "peers",
|
||||
ImprovementDir: 1,
|
||||
}, float64(len(pids)))
|
||||
|
||||
actualClosest := getClosestPeerRanking(node, others, c)
|
||||
outputGCP(runenv, node.info.Addrs.ID, c, peers, actualClosest)
|
||||
} else {
|
||||
runenv.RecordMessage("Error during GCP %w", err)
|
||||
}
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
_ = stager.End()
|
||||
return fmt.Errorf("failed while finding providerss: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
runenv.RecordMessage("done gcp loop")
|
||||
|
||||
if err := stager.End(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getClosestPeerRanking(me *NodeParams, others map[peer.ID]*DHTNodeInfo, target cid.Cid) []peer.ID {
|
||||
var allPeers []peer.ID
|
||||
allPeers = append(allPeers, me.dht.PeerID())
|
||||
for p := range others {
|
||||
allPeers = append(allPeers, p)
|
||||
}
|
||||
|
||||
kadTarget := kbucket.ConvertKey(target.KeyString())
|
||||
return kbucket.SortClosestPeers(allPeers, kadTarget)
|
||||
}
|
||||
|
||||
func outputGCP(runenv *runtime.RunEnv, me peer.ID, target cid.Cid, peers, rankedPeers []peer.ID) {
|
||||
peerStrs := make([]string, len(peers))
|
||||
kadPeerStrs := make([]string, len(peers))
|
||||
|
||||
for i, p := range peers {
|
||||
peerStrs[i] = p.String()
|
||||
kadPeerStrs[i] = hex.EncodeToString(kbucket.ConvertKey(string(p)))
|
||||
}
|
||||
|
||||
actualClosest := rankedPeers[:len(peers)]
|
||||
|
||||
nodeLogger.Infow("gcp-results",
|
||||
"me", me.String(),
|
||||
"KadMe", kbucket.ConvertKey(string(me)),
|
||||
"target", target,
|
||||
"peers", peers,
|
||||
"actual", actualClosest,
|
||||
"KadTarget", kbucket.ConvertKey(target.KeyString()),
|
||||
"KadPeers", peerIDsToKadIDs(peers),
|
||||
"KadActual", peerIDsToKadIDs(actualClosest),
|
||||
"Scores", gcpScore(peers, rankedPeers),
|
||||
)
|
||||
|
||||
_ = nodeLogger.Sync()
|
||||
}
|
||||
|
||||
func gcpScore(peers, rankedPeers []peer.ID) []int {
|
||||
getIndex := func(peers []peer.ID, target peer.ID) int {
|
||||
for i, p := range peers {
|
||||
if p == target {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// score is distance between actual ranking and our ranking
|
||||
var scores []int
|
||||
for i, p := range peers {
|
||||
diff := getIndex(rankedPeers, p) - i
|
||||
scores = append(scores, diff)
|
||||
}
|
||||
return scores
|
||||
}
|
||||
|
||||
func peerIDsToKadIDs(peers []peer.ID) []kbucket.ID {
|
||||
kadIDs := make([]kbucket.ID, len(peers))
|
||||
for i, p := range peers {
|
||||
kadIDs[i] = kbucket.ConvertPeerID(p)
|
||||
}
|
||||
return kadIDs
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/testground/sdk-go/runtime"
|
||||
)
|
||||
|
||||
// TODO this entire test needs to be revisited.
|
||||
// ProvideStress implements the Provide Stress test case
|
||||
func ProvideStress(runenv *runtime.RunEnv) error {
|
||||
// // Test Parameters
|
||||
// var (
|
||||
// timeout = time.Duration(runenv.IntParamD("timeout_secs", 60)) * time.Second
|
||||
// randomWalk = runenv.BooleanParamD("random_walk", false)
|
||||
// bucketSize = runenv.IntParamD("bucket_size", 20)
|
||||
// autoRefresh = runenv.BooleanParamD("auto_refresh", true)
|
||||
// nProvides = runenv.IntParamD("n_provides", 10)
|
||||
// iProvides = time.Duration(runenv.IntParamD("i-provides", 1)) * time.Second
|
||||
// )
|
||||
|
||||
// ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
// defer cancel()
|
||||
|
||||
// watcher, writer := sync.MustWatcherWriter(runenv)
|
||||
// defer watcher.Close()
|
||||
// defer writer.Close()
|
||||
|
||||
// _, dht, _, err := SetUp(ctx, runenv, timeout, randomWalk, bucketSize, autoRefresh, watcher, writer)
|
||||
// if err != nil {
|
||||
// runenv.Abort(err)
|
||||
// return
|
||||
// }
|
||||
|
||||
// defer TearDown(ctx, runenv, watcher, writer)
|
||||
|
||||
// /// --- Act I
|
||||
// // Each node calls Provide for `i-provides` until it reaches a total of `n-provides`
|
||||
|
||||
// var (
|
||||
// seed = 0
|
||||
// counter = 0
|
||||
// )
|
||||
|
||||
// Loop:
|
||||
// for {
|
||||
// select {
|
||||
// case <-time.After(iProvides):
|
||||
// v := fmt.Sprintf("%d -- something random", seed)
|
||||
// mhv := ipfsUtil.Hash([]byte(v))
|
||||
// cidToPublish := cid.NewCidV0(mhv)
|
||||
// err := dht.Provide(ctx, cidToPublish, true)
|
||||
// if err != nil {
|
||||
// runenv.Abort(fmt.Errorf("Failed on .Provide - %w", err))
|
||||
// return
|
||||
// }
|
||||
// runenv.RecordMessage("Provided a CID")
|
||||
|
||||
// counter++
|
||||
// if counter == nProvides {
|
||||
// break Loop
|
||||
// }
|
||||
// case <-ctx.Done():
|
||||
// runenv.Abort(fmt.Errorf("Context closed before ending the test"))
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
|
||||
// runenv.RecordMessage("Provided all scheduled CIDs")
|
||||
|
||||
// runenv.OK()
|
||||
return fmt.Errorf("unimplemented")
|
||||
}
|
||||
@@ -1,319 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/test-plans/dht/utils"
|
||||
"github.com/testground/sdk-go/runtime"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/crypto"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/ipfs/go-ipns"
|
||||
ipns_pb "github.com/ipfs/go-ipns/pb"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
func StoreGetValue(runenv *runtime.RunEnv) error {
|
||||
commonOpts := GetCommonOpts(runenv)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), commonOpts.Timeout)
|
||||
defer cancel()
|
||||
|
||||
ri, err := Base(ctx, runenv, commonOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := TestIPNSRecords(ctx, ri); err != nil {
|
||||
return err
|
||||
}
|
||||
Teardown(ctx, ri.RunInfo)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestIPNSRecords(ctx context.Context, ri *DHTRunInfo) error {
|
||||
runenv := ri.RunEnv
|
||||
node := ri.Node
|
||||
|
||||
fpOpts := getFindProvsParams(ri.RunEnv.RunParams.TestInstanceParams)
|
||||
|
||||
stager := utils.NewBatchStager(ctx, node.info.Seq, runenv.TestInstanceCount, "ipns-records", ri.RunInfo)
|
||||
|
||||
emitRecords, searchRecords, err := generateIPNSRecords(ri, fpOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
emitRecordsKeys := make([]string, len(emitRecords))
|
||||
for i, privKey := range emitRecords {
|
||||
pid, err := peer.IDFromPrivateKey(privKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
emitRecordsKeys[i] = ipns.RecordKey(pid)
|
||||
}
|
||||
|
||||
runenv.RecordMessage("start put loop")
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
if err := putIPNSRecord(ctx, ri, fpOpts, stager, i, emitRecords, emitRecordsKeys); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := getIPNSRecord(ctx, ri, fpOpts, stager, i, searchRecords); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func putIPNSRecord(ctx context.Context, ri *DHTRunInfo, fpOpts findProvsParams, stager utils.Stager, recNum int, emitRecords []crypto.PrivKey, emitRecordsKeys []string) error {
|
||||
runenv := ri.RunEnv
|
||||
node := ri.Node
|
||||
|
||||
if err := stager.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we're a member of the putting cohort, let's put those IPNS records to the network.
|
||||
if fpOpts.RecordCount > 0 {
|
||||
g := errgroup.Group{}
|
||||
for index, privKey := range emitRecords {
|
||||
i := index
|
||||
record, err := ipns.Create(privKey, []byte(fmt.Sprintf("/path/to/stuff/%d", recNum)), uint64(recNum), time.Now().Add(time.Hour))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ipns.EmbedPublicKey(privKey.GetPublic(), record); err != nil {
|
||||
return err
|
||||
}
|
||||
recordKey := emitRecordsKeys[i]
|
||||
recordBytes, err := proto.Marshal(record)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
g.Go(func() error {
|
||||
ectx, cancel := context.WithCancel(ctx) //nolint
|
||||
ectx = TraceQuery(ctx, runenv, node, recordKey, "ipns-records")
|
||||
t := time.Now()
|
||||
err := node.dht.PutValue(ectx, recordKey, recordBytes)
|
||||
cancel()
|
||||
if err == nil {
|
||||
runenv.RecordMessage("Put IPNS Key: %s", recordKey)
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("time-to-put-%d", i),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(time.Since(t).Nanoseconds()))
|
||||
} else {
|
||||
runenv.RecordMessage("Failed to Put IPNS Key: %s : err: %s", recordKey, err)
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("time-to-failed-put-%d", i),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(time.Since(t).Nanoseconds()))
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
panic("how is there an error here?")
|
||||
}
|
||||
}
|
||||
|
||||
if err := stager.End(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getIPNSRecord(ctx context.Context, ri *DHTRunInfo, fpOpts findProvsParams, stager utils.Stager, recNum int, searchRecords []*RecordSubmission) error {
|
||||
runenv := ri.RunEnv
|
||||
node := ri.Node
|
||||
|
||||
if err := stager.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fpOpts.SearchRecords {
|
||||
g := errgroup.Group{}
|
||||
for _, record := range searchRecords {
|
||||
for index, key := range record.RecordIDs {
|
||||
i := index
|
||||
k := key
|
||||
groupID := record.GroupID
|
||||
g.Go(func() error {
|
||||
ectx, cancel := context.WithCancel(ctx) //nolint
|
||||
ectx = TraceQuery(ctx, runenv, node, k, "ipns-records")
|
||||
t := time.Now()
|
||||
|
||||
runenv.RecordMessage("Searching for IPNS Key: %s", k)
|
||||
numRecs := 0
|
||||
recordCh, err := node.dht.SearchValue(ectx, k)
|
||||
if err != nil {
|
||||
runenv.RecordMessage("Failed to Search for IPNS Key: %s : err: %s", k, err)
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("time-to-failed-put-%d", i),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(time.Since(t).Nanoseconds()))
|
||||
return nil //nolint
|
||||
}
|
||||
status := "done"
|
||||
|
||||
var tLastFound time.Time
|
||||
var lastRec []byte
|
||||
searchLoop:
|
||||
for {
|
||||
select {
|
||||
case rec, ok := <-recordCh:
|
||||
if !ok {
|
||||
break searchLoop
|
||||
}
|
||||
lastRec = rec
|
||||
|
||||
tLastFound = time.Now()
|
||||
|
||||
if numRecs == 0 {
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("time-to-get-first|%s|%d", groupID, i),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(tLastFound.Sub(t).Nanoseconds()))
|
||||
}
|
||||
|
||||
numRecs++
|
||||
case <-ctx.Done():
|
||||
break searchLoop
|
||||
}
|
||||
}
|
||||
cancel()
|
||||
|
||||
if numRecs > 0 {
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("time-to-get-last|%s|%s|%d", status, groupID, i),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(tLastFound.Sub(t).Nanoseconds()))
|
||||
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("record-updates|%s|%s|%d|%d", status, groupID, recNum, i),
|
||||
Unit: "records",
|
||||
ImprovementDir: -1,
|
||||
}, float64(numRecs))
|
||||
|
||||
if len(lastRec) == 0 {
|
||||
panic("this should not be possible")
|
||||
}
|
||||
|
||||
recordResult := &ipns_pb.IpnsEntry{}
|
||||
if err := recordResult.Unmarshal(lastRec); err != nil {
|
||||
panic(fmt.Errorf("received invalid IPNS record: err %v", err))
|
||||
}
|
||||
|
||||
if diff := int(*recordResult.Sequence) - recNum; diff > 0 {
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("incomplete-get|%s|%d|%d", groupID, recNum, i),
|
||||
Unit: "records",
|
||||
ImprovementDir: -1,
|
||||
}, float64(diff))
|
||||
status = "fail"
|
||||
}
|
||||
|
||||
} else {
|
||||
status = "fail"
|
||||
}
|
||||
|
||||
runenv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: fmt.Sprintf("time-to-get|%s|%s|%d|%d", status, groupID, recNum, i),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(time.Since(t).Nanoseconds()))
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if err := g.Wait(); err != nil {
|
||||
panic("how is this possible?")
|
||||
}
|
||||
}
|
||||
|
||||
if err := stager.End(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateIPNSRecords returns the records we plan to store and those we plan to search for
|
||||
func generateIPNSRecords(ri *DHTRunInfo, fpOpts findProvsParams) (emitRecords []crypto.PrivKey, searchRecords []*RecordSubmission, err error) {
|
||||
recGen := func(groupID string, groupFPOpts findProvsParams) (out []crypto.PrivKey, err error) {
|
||||
// Calculate key based on seed
|
||||
rng := rand.New(rand.NewSource(int64(fpOpts.RecordSeed)))
|
||||
// Calculate key based on group (run through the rng to do this)
|
||||
for _, g := range ri.Groups {
|
||||
rng.Int63()
|
||||
if g == groupID {
|
||||
break
|
||||
}
|
||||
}
|
||||
// Unique key per record is generated since the rng is mutated by creating the new key
|
||||
for i := 0; i < groupFPOpts.RecordCount; i++ {
|
||||
priv, _, err := crypto.GenerateEd25519Key(rng)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, priv)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
if fpOpts.RecordCount > 0 && ri.Node.info.GroupSeq == 0 {
|
||||
// Calculate the CIDs we're dealing with.
|
||||
emitRecords, err = recGen(ri.Node.info.Group, fpOpts)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if fpOpts.SearchRecords {
|
||||
for _, g := range ri.Groups {
|
||||
gOpts := ri.GroupProperties[g]
|
||||
groupFPOpts := getFindProvsParams(gOpts.Params)
|
||||
if groupFPOpts.RecordCount > 0 {
|
||||
recs, err := recGen(g, groupFPOpts)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ipnsKeys := make([]string, len(recs))
|
||||
for i, k := range recs {
|
||||
pid, err := peer.IDFromPrivateKey(k)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
ipnsKeys[i] = ipns.RecordKey(pid)
|
||||
}
|
||||
searchRecords = append(searchRecords, &RecordSubmission{
|
||||
RecordIDs: ipnsKeys,
|
||||
GroupID: g,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type RecordSubmission struct {
|
||||
RecordIDs []string
|
||||
GroupID string
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"github.com/testground/sdk-go/sync"
|
||||
)
|
||||
|
||||
// PeerAttribTopic represents a subtree under the test run's sync tree where peers
|
||||
// participating in this distributed test advertise their attributes.
|
||||
var PeerAttribTopic = sync.NewTopic("attribs", &DHTNodeInfo{})
|
||||
@@ -1,79 +0,0 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/testground/sdk-go/runtime"
|
||||
"github.com/libp2p/go-libp2p-core/host"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
routing "github.com/libp2p/go-libp2p-core/routing"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var (
|
||||
qonce sync.Once
|
||||
qlogger *zap.SugaredLogger
|
||||
)
|
||||
|
||||
// TraceConnections starts tracing connections into an output asset with name
|
||||
// conn_trace.out.
|
||||
func TraceConnections(runenv *runtime.RunEnv, node host.Host) error {
|
||||
_, trace, err := runenv.CreateStructuredAsset("conn_trace.out", runtime.StandardJSONConfig())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trace = trace.With("id", node.ID())
|
||||
|
||||
node.Network().Notify(&network.NotifyBundle{
|
||||
ConnectedF: func(n network.Network, c network.Conn) {
|
||||
trace.Infow("connect", "peer", c.RemotePeer(), "dir", c.Stat().Direction)
|
||||
},
|
||||
DisconnectedF: func(n network.Network, c network.Conn) {
|
||||
trace.Infow("disconnect", "peer", c.RemotePeer())
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TraceQuery returns a context.Context that can be used in a DHT query to
|
||||
// cause query events to be traced. It initialises the output asset once.
|
||||
func TraceQuery(ctx context.Context, runenv *runtime.RunEnv, node *NodeParams, target string, tag string) context.Context {
|
||||
qonce.Do(func() {
|
||||
var err error
|
||||
_, qlogger, err = runenv.CreateStructuredAsset("dht_queries.out", runtime.StandardJSONConfig())
|
||||
if err != nil {
|
||||
runenv.RecordMessage("failed to initialize dht_queries.out asset; nooping logger: %s", err)
|
||||
qlogger = zap.NewNop().Sugar()
|
||||
}
|
||||
})
|
||||
|
||||
ectx, events := routing.RegisterForQueryEvents(ctx)
|
||||
log := qlogger.With("tag", tag, "node", node.host.ID().Pretty(), "target", target)
|
||||
|
||||
go func() {
|
||||
for e := range events {
|
||||
var msg string
|
||||
switch e.Type {
|
||||
case routing.SendingQuery:
|
||||
msg = "send"
|
||||
case routing.PeerResponse:
|
||||
msg = "receive"
|
||||
case routing.AddingPeer:
|
||||
msg = "adding"
|
||||
case routing.DialingPeer:
|
||||
msg = "dialing"
|
||||
case routing.QueryError:
|
||||
msg = "error"
|
||||
case routing.Provider, routing.Value:
|
||||
msg = "result"
|
||||
}
|
||||
log.Infow(msg, "peer", e.ID, "closer", e.Responses, "value", e.Extra)
|
||||
}
|
||||
}()
|
||||
|
||||
retCtx := specializedTraceQuery(ectx, runenv, tag)
|
||||
return retCtx
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
|
||||
"github.com/testground/sdk-go/sync"
|
||||
)
|
||||
|
||||
func GetGroupsAndSeqs(ctx context.Context, ri *RunInfo, groupOrder int) (groupSeq, testSeq int, err error) {
|
||||
groupSeq, err = getGroupSeq(ctx, ri)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = setGroupInfo(ctx, ri, groupOrder); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ri.RunEnv.RecordMessage("past group info")
|
||||
|
||||
testSeq = getNodeID(ri, groupSeq)
|
||||
return
|
||||
}
|
||||
|
||||
// getGroupSeq returns the sequence number of this test instance within its group
|
||||
func getGroupSeq(ctx context.Context, ri *RunInfo) (int, error) {
|
||||
seq, err := ri.Client.SignalAndWait(ctx, sync.State(ri.RunEnv.TestGroupID), ri.RunEnv.TestGroupInstanceCount)
|
||||
seq-- // make 0-indexed
|
||||
return int(seq), err
|
||||
}
|
||||
|
||||
// setGroupInfo uses the sync service to determine which groups are part of the test and to get their sizes.
|
||||
// This information is set on the passed in RunInfo.
|
||||
func setGroupInfo(ctx context.Context, ri *RunInfo, groupOrder int) error {
|
||||
gi := &GroupInfo{
|
||||
ID: ri.RunEnv.TestGroupID,
|
||||
Size: ri.RunEnv.TestGroupInstanceCount,
|
||||
Order: groupOrder,
|
||||
Params: ri.RunEnv.TestInstanceParams,
|
||||
}
|
||||
|
||||
subCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
groupInfoCh := make(chan *GroupInfo)
|
||||
ri.Client.MustPublishSubscribe(subCtx, GroupIDTopic, gi, groupInfoCh)
|
||||
|
||||
groupOrderMap := make(map[int][]string)
|
||||
groups := make(map[string]*GroupInfo)
|
||||
for i := 0; i < ri.RunEnv.TestInstanceCount; i++ {
|
||||
select {
|
||||
case g, more := <-groupInfoCh:
|
||||
if !more {
|
||||
break
|
||||
}
|
||||
if _, ok := groups[g.ID]; !ok {
|
||||
groups[g.ID] = g
|
||||
groupOrderMap[g.Order] = append(groupOrderMap[g.Order], g.ID)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
ri.RunEnv.RecordMessage("there are %d groups %v", len(groups), groups)
|
||||
|
||||
sortedGroups := make([]string, 0, len(groups))
|
||||
sortedOrderNums := make([]int, 0, len(groupOrderMap))
|
||||
for order := range groupOrderMap {
|
||||
sortedOrderNums = append(sortedOrderNums, order)
|
||||
}
|
||||
sort.Ints(sortedOrderNums)
|
||||
|
||||
for i := 0; i < len(sortedOrderNums); i++ {
|
||||
sort.Strings(groupOrderMap[i])
|
||||
sortedGroups = append(sortedGroups, groupOrderMap[i]...)
|
||||
}
|
||||
|
||||
ri.Groups = sortedGroups
|
||||
ri.GroupProperties = groups
|
||||
|
||||
ri.RunEnv.RecordMessage("sortedGroup order %v", sortedGroups)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// getNodeID returns the sequence number of this test instance within the test
|
||||
func getNodeID(ri *RunInfo, seq int) int {
|
||||
id := seq
|
||||
for _, g := range ri.Groups {
|
||||
if g == ri.RunEnv.TestGroupID {
|
||||
break
|
||||
}
|
||||
id += ri.GroupProperties[g].Size
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
// GroupIDTopic represents a subtree under the test run's sync tree where peers
|
||||
// participating in this distributed test advertise their groups.
|
||||
var GroupIDTopic = sync.NewTopic("groupIDs", &GroupInfo{})
|
||||
|
||||
type GroupInfo struct {
|
||||
ID string
|
||||
Size int
|
||||
Order int
|
||||
Params map[string]string
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/testground/sdk-go/runtime"
|
||||
"github.com/testground/sdk-go/sync"
|
||||
)
|
||||
|
||||
type RunInfo struct {
|
||||
RunEnv *runtime.RunEnv
|
||||
Client *sync.Client
|
||||
|
||||
Groups []string
|
||||
GroupProperties map[string]*GroupInfo
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/testground/sdk-go/runtime"
|
||||
"github.com/testground/sdk-go/sync"
|
||||
)
|
||||
|
||||
type Stager interface {
|
||||
Begin() error
|
||||
End() error
|
||||
Reset(name string)
|
||||
}
|
||||
|
||||
type stager struct {
|
||||
ctx context.Context
|
||||
seq int
|
||||
total int
|
||||
name string
|
||||
stage int
|
||||
ri *RunInfo
|
||||
t time.Time
|
||||
}
|
||||
|
||||
func (s *stager) Reset(name string) {
|
||||
s.name = name
|
||||
s.stage = 0
|
||||
}
|
||||
|
||||
func NewBatchStager(ctx context.Context, seq int, total int, name string, ri *RunInfo) *BatchStager {
|
||||
return &BatchStager{stager{
|
||||
ctx: ctx,
|
||||
seq: seq,
|
||||
total: total,
|
||||
name: name,
|
||||
stage: 0,
|
||||
ri: ri,
|
||||
t: time.Now(),
|
||||
}}
|
||||
}
|
||||
|
||||
type BatchStager struct{ stager }
|
||||
|
||||
func (s *BatchStager) Begin() error {
|
||||
s.stage += 1
|
||||
s.t = time.Now()
|
||||
return nil
|
||||
}
|
||||
func (s *BatchStager) End() error {
|
||||
// Signal that we're done
|
||||
stage := sync.State(s.name + strconv.Itoa(s.stage))
|
||||
|
||||
t := time.Now()
|
||||
_, err := s.ri.Client.SignalEntry(s.ctx, stage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.ri.RunEnv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: "signal " + string(stage),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(time.Since(t).Nanoseconds()))
|
||||
|
||||
t = time.Now()
|
||||
|
||||
err = <-s.ri.Client.MustBarrier(s.ctx, stage, s.total).C
|
||||
s.ri.RunEnv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: "barrier" + string(stage),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(time.Since(t).Nanoseconds()))
|
||||
|
||||
s.ri.RunEnv.RecordMetric(&runtime.MetricDefinition{
|
||||
Name: "full " + string(stage),
|
||||
Unit: "ns",
|
||||
ImprovementDir: -1,
|
||||
}, float64(time.Since(s.t).Nanoseconds()))
|
||||
return err
|
||||
}
|
||||
func (s *BatchStager) Reset(name string) { s.stager.Reset(name) }
|
||||
|
||||
func NewSinglePeerStager(ctx context.Context, seq int, total int, name string, ri *RunInfo) *SinglePeerStager {
|
||||
return &SinglePeerStager{BatchStager{stager{
|
||||
ctx: ctx,
|
||||
seq: seq,
|
||||
total: total,
|
||||
name: name,
|
||||
stage: 0,
|
||||
ri: ri,
|
||||
t: time.Now(),
|
||||
}}}
|
||||
}
|
||||
|
||||
type SinglePeerStager struct{ BatchStager }
|
||||
|
||||
func (s *SinglePeerStager) Begin() error {
|
||||
if err := s.BatchStager.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait until it's out turn
|
||||
stage := sync.State(s.name + string(s.stage))
|
||||
return <-s.ri.Client.MustBarrier(s.ctx, stage, s.seq).C
|
||||
}
|
||||
func (s *SinglePeerStager) End() error {
|
||||
return s.BatchStager.End()
|
||||
}
|
||||
func (s *SinglePeerStager) Reset(name string) { s.stager.Reset(name) }
|
||||
|
||||
func NewGradualStager(ctx context.Context, seq int, total int, name string, ri *RunInfo, gradFn gradualFn) *GradualStager {
|
||||
return &GradualStager{BatchStager{stager{
|
||||
ctx: ctx,
|
||||
seq: seq,
|
||||
total: total,
|
||||
name: name,
|
||||
stage: 0,
|
||||
ri: ri,
|
||||
t: time.Now(),
|
||||
}}, gradFn}
|
||||
}
|
||||
|
||||
type gradualFn func(seq int) (int, int)
|
||||
|
||||
type GradualStager struct {
|
||||
BatchStager
|
||||
gradualFn
|
||||
}
|
||||
|
||||
func (s *GradualStager) Begin() error {
|
||||
if err := s.BatchStager.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait until it's out turn
|
||||
ourTurn, waitFor := s.gradualFn(s.seq)
|
||||
|
||||
stageWait := sync.State(fmt.Sprintf("%s%d-%d", s.name, s.stage, ourTurn))
|
||||
stageNext := sync.State(fmt.Sprintf("%s%d-%d", s.name, s.stage, ourTurn+1))
|
||||
s.ri.RunEnv.RecordMessage("%d is waiting on %d from state %d", s.seq, waitFor, ourTurn)
|
||||
err := <-s.ri.Client.MustBarrier(s.ctx, stageWait, waitFor).C
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.ri.RunEnv.RecordMessage("%d is running", s.seq)
|
||||
_, err = s.ri.Client.SignalEntry(s.ctx, stageNext)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *GradualStager) End() error {
|
||||
lastStage := sync.State(fmt.Sprintf("%s%d-end", s.name, s.stage))
|
||||
_, err := s.ri.Client.SignalEntry(s.ctx, lastStage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
total := s.ri.RunEnv.TestInstanceCount - 1
|
||||
s.ri.RunEnv.RecordMessage("%d is done - waiting for %d", s.seq, total)
|
||||
err = <-s.ri.Client.MustBarrier(s.ctx, lastStage, total).C
|
||||
s.ri.RunEnv.RecordMessage("%d passed the barrier", s.seq)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *GradualStager) Reset(name string) { s.stager.Reset(name) }
|
||||
|
||||
func LinearGradualStaging(slope int) gradualFn {
|
||||
return func(seq int) (int, int) {
|
||||
slope := slope
|
||||
turnNum := int(math.Floor(float64(seq) / float64(slope)))
|
||||
waitFor := slope
|
||||
if turnNum == 0 {
|
||||
waitFor = 0
|
||||
}
|
||||
return turnNum, waitFor
|
||||
}
|
||||
}
|
||||
|
||||
func ExponentialGradualStaging() gradualFn {
|
||||
return func(seq int) (int, int) {
|
||||
switch seq {
|
||||
case 0:
|
||||
return 0, 0
|
||||
case 1:
|
||||
return 1, 1
|
||||
default:
|
||||
turnNum := int(math.Floor(math.Log2(float64(seq)))) + 1
|
||||
waitFor := int(math.Exp2(float64(turnNum - 2)))
|
||||
return turnNum, waitFor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type NoStager struct{}
|
||||
|
||||
func (s *NoStager) Begin() error { return nil }
|
||||
func (s *NoStager) End() error { return nil }
|
||||
func (s *NoStager) Reset(name string) {}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"opRetro": {
|
||||
"projectId": "0x966804cb492e1a4bde5d781a676a44a23d69aa5dd2562fa7a4f95bb606021c8b"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# For now, not committing image.json files
|
||||
image.json
|
||||
|
||||
results.csv
|
||||
runs/
|
||||
|
||||
node_modules/
|
||||
@@ -0,0 +1,19 @@
|
||||
RUST_SUBDIRS := $(wildcard impl/rust/*/.)
|
||||
GO_SUBDIRS := $(wildcard impl/go/*/.)
|
||||
|
||||
all: rust-relay router $(RUST_SUBDIRS) $(GO_SUBDIRS)
|
||||
rust-relay:
|
||||
$(MAKE) -C rust-relay
|
||||
router:
|
||||
$(MAKE) -C router
|
||||
$(RUST_SUBDIRS):
|
||||
$(MAKE) -C $@
|
||||
$(GO_SUBDIRS):
|
||||
$(MAKE) -C $@
|
||||
clean:
|
||||
$(MAKE) -C rust-relay clean
|
||||
$(MAKE) -C router clean
|
||||
$(MAKE) -C $(RUST_SUBDIRS) clean
|
||||
$(MAKE) -C $(GO_SUBDIRS) clean
|
||||
|
||||
.PHONY: rust-relay router all $(RUST_SUBDIRS) $(GO_SUBDIRS)
|
||||
@@ -0,0 +1,84 @@
|
||||
# Hole punch tests
|
||||
|
||||
## How to run locally
|
||||
|
||||
1. `npm install`
|
||||
2. `make`
|
||||
3. `npm run test`
|
||||
|
||||
## Client configuration
|
||||
|
||||
| env variable | possible values |
|
||||
|--------------|-----------------|
|
||||
| MODE | listen \| dial |
|
||||
| TRANSPORT | tcp \| quic |
|
||||
|
||||
- For TCP, the client MUST use noise + yamux to upgrade the connection.
|
||||
- The relayed connection MUST use noise + yamux.
|
||||
|
||||
## Test flow
|
||||
|
||||
1. The relay starts and pushes its address to the following redis keys:
|
||||
- `RELAY_TCP_ADDRESS` for the TCP test
|
||||
- `RELAY_QUIC_ADDRESS` for the QUIC test
|
||||
1. Upon start-up, clients connect to a redis server at `redis:6379` and block until this redis key comes available.
|
||||
They then dial the relay on the provided address.
|
||||
1. The relay supports identify.
|
||||
Implementations SHOULD use that to figure out their external address next.
|
||||
1. Once connected to the relay, a client in `MODE=listen` should listen on the relay and make a reservation.
|
||||
Once the reservation is made, it pushes its `PeerId` to the redis key `LISTEN_CLIENT_PEER_ID`.
|
||||
1. A client in `MODE=dial` blocks on the availability of `LISTEN_CLIENT_PEER_ID`.
|
||||
Once available, it dials `<relay_addr>/p2p-circuit/<listen-client-peer-id>`.
|
||||
1. Upon a successful hole-punch, the peer in `MODE=dial` measures the RTT across the newly established connection.
|
||||
1. The RTT MUST be printed to stdout in the following format:
|
||||
```json
|
||||
{ "rtt_to_holepunched_peer_millis": 12 }
|
||||
```
|
||||
1. Once printed, the dialer MUST exit with `0`.
|
||||
|
||||
## Requirements for implementations
|
||||
|
||||
- Docker containers MUST have a binary called `hole-punch-client` in their $PATH
|
||||
- MUST have `dig`, `curl`, `jq` and `tcpdump` installed
|
||||
- Listener MUST NOT early-exit but wait to be killed by test runner
|
||||
- Logs MUST go to stderr, RTT json MUST go to stdout
|
||||
- Dialer and lister both MUST use 0RTT negotiation for protocols
|
||||
- Implementations SHOULD disable timeouts on the redis client, i.e. use `0`
|
||||
- Implementations SHOULD exit early with a non-zero exit code if anything goes wrong
|
||||
- Implementations MUST set `TCP_NODELAY` for the TCP transport
|
||||
- Implements MUST make sure connections are being kept alive
|
||||
|
||||
## Design notes
|
||||
|
||||
The design of this test runner is heavily influenced by [multidim-interop](../multidim-interop) but differs in several ways.
|
||||
|
||||
All files related to test runs will be written to the [./runs](./runs) directory.
|
||||
This includes the `docker-compose.yml` files of each individual run as well as logs and `tcpdump`'s for the dialer and listener.
|
||||
|
||||
The docker-compose file uses 6 containers in total:
|
||||
|
||||
- 1 redis container for orchestrating the test
|
||||
- 1 [relay](./rust-relay)
|
||||
- 1 hole-punch client in `MODE=dial`
|
||||
- 1 hole-punch client in `MODE=listen`
|
||||
- 2 [routers](./router): 1 per client
|
||||
|
||||
The networks are allocated by docker-compose.
|
||||
We dynamically fetch the IPs and subnets as part of a startup script to set the correct IP routes.
|
||||
|
||||
In total, we have three networks:
|
||||
|
||||
1. `lan_dialer`
|
||||
2. `lan_listener`
|
||||
3. `internet`
|
||||
|
||||
The two LANs host a router and a client each whereas the relay is connected (without a router) to the `internet` network.
|
||||
On startup of the clients, we add an `ip route` that redirects all traffic to the corresponding `router` container.
|
||||
The router container masquerades all traffic upon forwarding, see the [README](./router/README.md) for details.
|
||||
|
||||
## Running a single test
|
||||
|
||||
1. Build all containers using `make`
|
||||
1. Generate all test definitions using `npm run test -- --no-run`
|
||||
1. Pick the desired test from the [runs](./runs) directory
|
||||
1. Execute it using `docker compose up`
|
||||
@@ -0,0 +1,818 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft/2019-09/schema#",
|
||||
"id": "compose_spec.json",
|
||||
"type": "object",
|
||||
"title": "Compose Specification",
|
||||
"description": "The Compose file is a YAML file defining a multi-containers based application.",
|
||||
|
||||
"properties": {
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "declared for backward compatibility, ignored."
|
||||
},
|
||||
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "define the Compose project name, until user defines one explicitly."
|
||||
},
|
||||
|
||||
"services": {
|
||||
"id": "#/properties/services",
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9._-]+$": {
|
||||
"$ref": "#/definitions/service"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"networks": {
|
||||
"id": "#/properties/networks",
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9._-]+$": {
|
||||
"$ref": "#/definitions/network"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"volumes": {
|
||||
"id": "#/properties/volumes",
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9._-]+$": {
|
||||
"$ref": "#/definitions/volume"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"secrets": {
|
||||
"id": "#/properties/secrets",
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9._-]+$": {
|
||||
"$ref": "#/definitions/secret"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"configs": {
|
||||
"id": "#/properties/configs",
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9._-]+$": {
|
||||
"$ref": "#/definitions/config"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
|
||||
"patternProperties": {"^x-": {}},
|
||||
"additionalProperties": false,
|
||||
|
||||
"definitions": {
|
||||
|
||||
"service": {
|
||||
"id": "#/definitions/service",
|
||||
"type": "object",
|
||||
|
||||
"properties": {
|
||||
"deploy": {"$ref": "#/definitions/deployment"},
|
||||
"build": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"context": {"type": "string"},
|
||||
"dockerfile": {"type": "string"},
|
||||
"args": {"$ref": "#/definitions/list_or_dict"},
|
||||
"ssh": {"$ref": "#/definitions/list_or_dict"},
|
||||
"labels": {"$ref": "#/definitions/list_or_dict"},
|
||||
"cache_from": {"type": "array", "items": {"type": "string"}},
|
||||
"cache_to": {"type": "array", "items": {"type": "string"}},
|
||||
"no_cache": {"type": "boolean"},
|
||||
"network": {"type": "string"},
|
||||
"pull": {"type": "boolean"},
|
||||
"target": {"type": "string"},
|
||||
"shm_size": {"type": ["integer", "string"]},
|
||||
"extra_hosts": {"$ref": "#/definitions/list_or_dict"},
|
||||
"isolation": {"type": "string"},
|
||||
"privileged": {"type": "boolean"},
|
||||
"secrets": {"$ref": "#/definitions/service_config_or_secret"},
|
||||
"tags": {"type": "array", "items": {"type": "string"}},
|
||||
"platforms": {"type": "array", "items": {"type": "string"}}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
}
|
||||
]
|
||||
},
|
||||
"blkio_config": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"device_read_bps": {
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||
},
|
||||
"device_read_iops": {
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||
},
|
||||
"device_write_bps": {
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||
},
|
||||
"device_write_iops": {
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/definitions/blkio_limit"}
|
||||
},
|
||||
"weight": {"type": "integer"},
|
||||
"weight_device": {
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/definitions/blkio_weight"}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"cap_add": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"cap_drop": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"cgroup": {"type": "string", "enum": ["host", "private"]},
|
||||
"cgroup_parent": {"type": "string"},
|
||||
"command": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "array", "items": {"type": "string"}}
|
||||
]
|
||||
},
|
||||
"configs": {"$ref": "#/definitions/service_config_or_secret"},
|
||||
"container_name": {"type": "string"},
|
||||
"cpu_count": {"type": "integer", "minimum": 0},
|
||||
"cpu_percent": {"type": "integer", "minimum": 0, "maximum": 100},
|
||||
"cpu_shares": {"type": ["number", "string"]},
|
||||
"cpu_quota": {"type": ["number", "string"]},
|
||||
"cpu_period": {"type": ["number", "string"]},
|
||||
"cpu_rt_period": {"type": ["number", "string"]},
|
||||
"cpu_rt_runtime": {"type": ["number", "string"]},
|
||||
"cpus": {"type": ["number", "string"]},
|
||||
"cpuset": {"type": "string"},
|
||||
"credential_spec": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"config": {"type": "string"},
|
||||
"file": {"type": "string"},
|
||||
"registry": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
"depends_on": {
|
||||
"oneOf": [
|
||||
{"$ref": "#/definitions/list_of_strings"},
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9._-]+$": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"condition": {
|
||||
"type": "string",
|
||||
"enum": ["service_started", "service_healthy", "service_completed_successfully"]
|
||||
}
|
||||
},
|
||||
"required": ["condition"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"device_cgroup_rules": {"$ref": "#/definitions/list_of_strings"},
|
||||
"devices": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"dns": {"$ref": "#/definitions/string_or_list"},
|
||||
"dns_opt": {"type": "array","items": {"type": "string"}, "uniqueItems": true},
|
||||
"dns_search": {"$ref": "#/definitions/string_or_list"},
|
||||
"domainname": {"type": "string"},
|
||||
"entrypoint": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "array", "items": {"type": "string"}}
|
||||
]
|
||||
},
|
||||
"env_file": {"$ref": "#/definitions/string_or_list"},
|
||||
"environment": {"$ref": "#/definitions/list_or_dict"},
|
||||
|
||||
"expose": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": ["string", "number"],
|
||||
"format": "expose"
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"extends": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{
|
||||
"type": "object",
|
||||
|
||||
"properties": {
|
||||
"service": {"type": "string"},
|
||||
"file": {"type": "string"}
|
||||
},
|
||||
"required": ["service"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"external_links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"extra_hosts": {"$ref": "#/definitions/list_or_dict"},
|
||||
"group_add": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": ["string", "number"]
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"healthcheck": {"$ref": "#/definitions/healthcheck"},
|
||||
"hostname": {"type": "string"},
|
||||
"image": {"type": "string"},
|
||||
"init": {"type": "boolean"},
|
||||
"ipc": {"type": "string"},
|
||||
"isolation": {"type": "string"},
|
||||
"labels": {"$ref": "#/definitions/list_or_dict"},
|
||||
"links": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"logging": {
|
||||
"type": "object",
|
||||
|
||||
"properties": {
|
||||
"driver": {"type": "string"},
|
||||
"options": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.+$": {"type": ["string", "number", "null"]}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
"mac_address": {"type": "string"},
|
||||
"mem_limit": {"type": ["number", "string"]},
|
||||
"mem_reservation": {"type": ["string", "integer"]},
|
||||
"mem_swappiness": {"type": "integer"},
|
||||
"memswap_limit": {"type": ["number", "string"]},
|
||||
"network_mode": {"type": "string"},
|
||||
"networks": {
|
||||
"oneOf": [
|
||||
{"$ref": "#/definitions/list_of_strings"},
|
||||
{
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z0-9._-]+$": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"aliases": {"$ref": "#/definitions/list_of_strings"},
|
||||
"ipv4_address": {"type": "string"},
|
||||
"ipv6_address": {"type": "string"},
|
||||
"link_local_ips": {"$ref": "#/definitions/list_of_strings"},
|
||||
"priority": {"type": "number"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
{"type": "null"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"oom_kill_disable": {"type": "boolean"},
|
||||
"oom_score_adj": {"type": "integer", "minimum": -1000, "maximum": 1000},
|
||||
"pid": {"type": ["string", "null"]},
|
||||
"pids_limit": {"type": ["number", "string"]},
|
||||
"platform": {"type": "string"},
|
||||
"ports": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{"type": "number", "format": "ports"},
|
||||
{"type": "string", "format": "ports"},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"mode": {"type": "string"},
|
||||
"host_ip": {"type": "string"},
|
||||
"target": {"type": "integer"},
|
||||
"published": {"type": ["string", "integer"]},
|
||||
"protocol": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
}
|
||||
]
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"privileged": {"type": "boolean"},
|
||||
"profiles": {"$ref": "#/definitions/list_of_strings"},
|
||||
"pull_policy": {"type": "string", "enum": [
|
||||
"always", "never", "if_not_present", "build", "missing"
|
||||
]},
|
||||
"read_only": {"type": "boolean"},
|
||||
"restart": {"type": "string"},
|
||||
"runtime": {
|
||||
"type": "string"
|
||||
},
|
||||
"scale": {
|
||||
"type": "integer"
|
||||
},
|
||||
"security_opt": {"type": "array", "items": {"type": "string"}, "uniqueItems": true},
|
||||
"shm_size": {"type": ["number", "string"]},
|
||||
"secrets": {"$ref": "#/definitions/service_config_or_secret"},
|
||||
"sysctls": {"$ref": "#/definitions/list_or_dict"},
|
||||
"stdin_open": {"type": "boolean"},
|
||||
"stop_grace_period": {"type": "string", "format": "duration"},
|
||||
"stop_signal": {"type": "string"},
|
||||
"storage_opt": {"type": "object"},
|
||||
"tmpfs": {"$ref": "#/definitions/string_or_list"},
|
||||
"tty": {"type": "boolean"},
|
||||
"ulimits": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-z]+$": {
|
||||
"oneOf": [
|
||||
{"type": "integer"},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hard": {"type": "integer"},
|
||||
"soft": {"type": "integer"}
|
||||
},
|
||||
"required": ["soft", "hard"],
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"user": {"type": "string"},
|
||||
"uts": {"type": "string"},
|
||||
"userns_mode": {"type": "string"},
|
||||
"volumes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["type"],
|
||||
"properties": {
|
||||
"type": {"type": "string"},
|
||||
"source": {"type": "string"},
|
||||
"target": {"type": "string"},
|
||||
"read_only": {"type": "boolean"},
|
||||
"consistency": {"type": "string"},
|
||||
"bind": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"propagation": {"type": "string"},
|
||||
"create_host_path": {"type": "boolean"},
|
||||
"selinux": {"type": "string", "enum": ["z", "Z"]}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
"volume": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"nocopy": {"type": "boolean"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
"tmpfs": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"size": {
|
||||
"oneOf": [
|
||||
{"type": "integer", "minimum": 0},
|
||||
{"type": "string"}
|
||||
]
|
||||
},
|
||||
"mode": {"type": "number"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
}
|
||||
]
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"volumes_from": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"working_dir": {"type": "string"}
|
||||
},
|
||||
"patternProperties": {"^x-": {}},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"healthcheck": {
|
||||
"id": "#/definitions/healthcheck",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"disable": {"type": "boolean"},
|
||||
"interval": {"type": "string", "format": "duration"},
|
||||
"retries": {"type": "number"},
|
||||
"test": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"type": "array", "items": {"type": "string"}}
|
||||
]
|
||||
},
|
||||
"timeout": {"type": "string", "format": "duration"},
|
||||
"start_period": {"type": "string", "format": "duration"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
"deployment": {
|
||||
"id": "#/definitions/deployment",
|
||||
"type": ["object", "null"],
|
||||
"properties": {
|
||||
"mode": {"type": "string"},
|
||||
"endpoint_mode": {"type": "string"},
|
||||
"replicas": {"type": "integer"},
|
||||
"labels": {"$ref": "#/definitions/list_or_dict"},
|
||||
"rollback_config": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"parallelism": {"type": "integer"},
|
||||
"delay": {"type": "string", "format": "duration"},
|
||||
"failure_action": {"type": "string"},
|
||||
"monitor": {"type": "string", "format": "duration"},
|
||||
"max_failure_ratio": {"type": "number"},
|
||||
"order": {"type": "string", "enum": [
|
||||
"start-first", "stop-first"
|
||||
]}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
"update_config": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"parallelism": {"type": "integer"},
|
||||
"delay": {"type": "string", "format": "duration"},
|
||||
"failure_action": {"type": "string"},
|
||||
"monitor": {"type": "string", "format": "duration"},
|
||||
"max_failure_ratio": {"type": "number"},
|
||||
"order": {"type": "string", "enum": [
|
||||
"start-first", "stop-first"
|
||||
]}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
"resources": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"limits": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cpus": {"type": ["number", "string"]},
|
||||
"memory": {"type": "string"},
|
||||
"pids": {"type": "integer"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
"reservations": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cpus": {"type": ["number", "string"]},
|
||||
"memory": {"type": "string"},
|
||||
"generic_resources": {"$ref": "#/definitions/generic_resources"},
|
||||
"devices": {"$ref": "#/definitions/devices"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
"restart_policy": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"condition": {"type": "string"},
|
||||
"delay": {"type": "string", "format": "duration"},
|
||||
"max_attempts": {"type": "integer"},
|
||||
"window": {"type": "string", "format": "duration"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
"placement": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"constraints": {"type": "array", "items": {"type": "string"}},
|
||||
"preferences": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"spread": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
}
|
||||
},
|
||||
"max_replicas_per_node": {"type": "integer"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
|
||||
"generic_resources": {
|
||||
"id": "#/definitions/generic_resources",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"discrete_resource_spec": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"kind": {"type": "string"},
|
||||
"value": {"type": "number"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
}
|
||||
},
|
||||
|
||||
"devices": {
|
||||
"id": "#/definitions/devices",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"capabilities": {"$ref": "#/definitions/list_of_strings"},
|
||||
"count": {"type": ["string", "integer"]},
|
||||
"device_ids": {"$ref": "#/definitions/list_of_strings"},
|
||||
"driver":{"type": "string"},
|
||||
"options":{"$ref": "#/definitions/list_or_dict"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
}
|
||||
},
|
||||
|
||||
"network": {
|
||||
"id": "#/definitions/network",
|
||||
"type": ["object", "null"],
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"driver": {"type": "string"},
|
||||
"driver_opts": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.+$": {"type": ["string", "number"]}
|
||||
}
|
||||
},
|
||||
"ipam": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"driver": {"type": "string"},
|
||||
"config": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"subnet": {"type": "string", "format": "subnet_ip_address"},
|
||||
"ip_range": {"type": "string"},
|
||||
"gateway": {"type": "string"},
|
||||
"aux_addresses": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^.+$": {"type": "string"}}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^.+$": {"type": "string"}}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
"external": {
|
||||
"type": ["boolean", "object"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"deprecated": true,
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
"internal": {"type": "boolean"},
|
||||
"enable_ipv6": {"type": "boolean"},
|
||||
"attachable": {"type": "boolean"},
|
||||
"labels": {"$ref": "#/definitions/list_or_dict"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
|
||||
"volume": {
|
||||
"id": "#/definitions/volume",
|
||||
"type": ["object", "null"],
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"driver": {"type": "string"},
|
||||
"driver_opts": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.+$": {"type": ["string", "number"]}
|
||||
}
|
||||
},
|
||||
"external": {
|
||||
"type": ["boolean", "object"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"deprecated": true,
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
"labels": {"$ref": "#/definitions/list_or_dict"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
|
||||
"secret": {
|
||||
"id": "#/definitions/secret",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"environment": {"type": "string"},
|
||||
"file": {"type": "string"},
|
||||
"external": {
|
||||
"type": ["boolean", "object"],
|
||||
"properties": {
|
||||
"name": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"labels": {"$ref": "#/definitions/list_or_dict"},
|
||||
"driver": {"type": "string"},
|
||||
"driver_opts": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^.+$": {"type": ["string", "number"]}
|
||||
}
|
||||
},
|
||||
"template_driver": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
|
||||
"config": {
|
||||
"id": "#/definitions/config",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"file": {"type": "string"},
|
||||
"external": {
|
||||
"type": ["boolean", "object"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"deprecated": true,
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"labels": {"$ref": "#/definitions/list_or_dict"},
|
||||
"template_driver": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
},
|
||||
|
||||
"string_or_list": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{"$ref": "#/definitions/list_of_strings"}
|
||||
]
|
||||
},
|
||||
|
||||
"list_of_strings": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"uniqueItems": true
|
||||
},
|
||||
|
||||
"list_or_dict": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
".+": {
|
||||
"type": ["string", "number", "boolean", "null"]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{"type": "array", "items": {"type": "string"}, "uniqueItems": true}
|
||||
]
|
||||
},
|
||||
|
||||
"blkio_limit": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {"type": "string"},
|
||||
"rate": {"type": ["integer", "string"]}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"blkio_weight": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {"type": "string"},
|
||||
"weight": {"type": "integer"}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"service_config_or_secret": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{"type": "string"},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"source": {"type": "string"},
|
||||
"target": {"type": "string"},
|
||||
"uid": {"type": "string"},
|
||||
"gid": {"type": "string"},
|
||||
"mode": {"type": "number"}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {"^x-": {}}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"constraints": {
|
||||
"service": {
|
||||
"id": "#/definitions/constraints/service",
|
||||
"anyOf": [
|
||||
{"required": ["build"]},
|
||||
{"required": ["image"]}
|
||||
],
|
||||
"properties": {
|
||||
"build": {
|
||||
"required": ["context"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,818 @@
|
||||
/* tslint:disable */
|
||||
/**
|
||||
* This file was automatically generated by json-schema-to-typescript.
|
||||
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
|
||||
* and run json-schema-to-typescript to regenerate this file.
|
||||
*/
|
||||
|
||||
export type DefinitionsDeployment = {
|
||||
mode?: string;
|
||||
endpoint_mode?: string;
|
||||
replicas?: number;
|
||||
labels?: ListOrDict;
|
||||
rollback_config?: {
|
||||
parallelism?: number;
|
||||
delay?: string;
|
||||
failure_action?: string;
|
||||
monitor?: string;
|
||||
max_failure_ratio?: number;
|
||||
order?: "start-first" | "stop-first";
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
update_config?: {
|
||||
parallelism?: number;
|
||||
delay?: string;
|
||||
failure_action?: string;
|
||||
monitor?: string;
|
||||
max_failure_ratio?: number;
|
||||
order?: "start-first" | "stop-first";
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
resources?: {
|
||||
limits?: {
|
||||
cpus?: number | string;
|
||||
memory?: string;
|
||||
pids?: number;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
reservations?: {
|
||||
cpus?: number | string;
|
||||
memory?: string;
|
||||
generic_resources?: DefinitionsGenericResources;
|
||||
devices?: DefinitionsDevices;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
restart_policy?: {
|
||||
condition?: string;
|
||||
delay?: string;
|
||||
max_attempts?: number;
|
||||
window?: string;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
placement?: {
|
||||
constraints?: string[];
|
||||
preferences?: {
|
||||
spread?: string;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
max_replicas_per_node?: number;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
} & Deployment;
|
||||
export type ListOrDict =
|
||||
| {
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` ".+".
|
||||
*/
|
||||
[k: string]: string | number | boolean | null;
|
||||
}
|
||||
| string[];
|
||||
export type DefinitionsGenericResources = {
|
||||
discrete_resource_spec?: {
|
||||
kind?: string;
|
||||
value?: number;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
export type ListOfStrings = string[];
|
||||
export type DefinitionsDevices = {
|
||||
capabilities?: ListOfStrings;
|
||||
count?: string | number;
|
||||
device_ids?: ListOfStrings;
|
||||
driver?: string;
|
||||
options?: ListOrDict;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
export type Deployment = {
|
||||
mode?: string;
|
||||
endpoint_mode?: string;
|
||||
replicas?: number;
|
||||
labels?: ListOrDict;
|
||||
rollback_config?: {
|
||||
parallelism?: number;
|
||||
delay?: string;
|
||||
failure_action?: string;
|
||||
monitor?: string;
|
||||
max_failure_ratio?: number;
|
||||
order?: "start-first" | "stop-first";
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
update_config?: {
|
||||
parallelism?: number;
|
||||
delay?: string;
|
||||
failure_action?: string;
|
||||
monitor?: string;
|
||||
max_failure_ratio?: number;
|
||||
order?: "start-first" | "stop-first";
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
resources?: {
|
||||
limits?: {
|
||||
cpus?: number | string;
|
||||
memory?: string;
|
||||
pids?: number;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
reservations?: {
|
||||
cpus?: number | string;
|
||||
memory?: string;
|
||||
generic_resources?: DefinitionsGenericResources;
|
||||
devices?: DefinitionsDevices;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
restart_policy?: {
|
||||
condition?: string;
|
||||
delay?: string;
|
||||
max_attempts?: number;
|
||||
window?: string;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
placement?: {
|
||||
constraints?: string[];
|
||||
preferences?: {
|
||||
spread?: string;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
max_replicas_per_node?: number;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
export type ServiceConfigOrSecret = (
|
||||
| string
|
||||
| {
|
||||
source?: string;
|
||||
target?: string;
|
||||
uid?: string;
|
||||
gid?: string;
|
||||
mode?: number;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}
|
||||
)[];
|
||||
export type StringOrList = string | ListOfStrings;
|
||||
/**
|
||||
* This interface was referenced by `PropertiesNetworks`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^[a-zA-Z0-9._-]+$".
|
||||
*/
|
||||
export type DefinitionsNetwork = {
|
||||
name?: string;
|
||||
driver?: string;
|
||||
driver_opts?: {
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^.+$".
|
||||
*/
|
||||
[k: string]: string | number;
|
||||
};
|
||||
ipam?: {
|
||||
driver?: string;
|
||||
config?: {
|
||||
subnet?: string;
|
||||
ip_range?: string;
|
||||
gateway?: string;
|
||||
aux_addresses?: {
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^.+$".
|
||||
*/
|
||||
[k: string]: string;
|
||||
};
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
options?: {
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^.+$".
|
||||
*/
|
||||
[k: string]: string;
|
||||
};
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
external?:
|
||||
| boolean
|
||||
| {
|
||||
name?: string;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
internal?: boolean;
|
||||
enable_ipv6?: boolean;
|
||||
attachable?: boolean;
|
||||
labels?: ListOrDict;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
} & Network;
|
||||
export type Network = {
|
||||
name?: string;
|
||||
driver?: string;
|
||||
driver_opts?: {
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^.+$".
|
||||
*/
|
||||
[k: string]: string | number;
|
||||
};
|
||||
ipam?: {
|
||||
driver?: string;
|
||||
config?: {
|
||||
subnet?: string;
|
||||
ip_range?: string;
|
||||
gateway?: string;
|
||||
aux_addresses?: {
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^.+$".
|
||||
*/
|
||||
[k: string]: string;
|
||||
};
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
options?: {
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^.+$".
|
||||
*/
|
||||
[k: string]: string;
|
||||
};
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
external?:
|
||||
| boolean
|
||||
| {
|
||||
name?: string;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
internal?: boolean;
|
||||
enable_ipv6?: boolean;
|
||||
attachable?: boolean;
|
||||
labels?: ListOrDict;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
/**
|
||||
* This interface was referenced by `PropertiesVolumes`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^[a-zA-Z0-9._-]+$".
|
||||
*/
|
||||
export type DefinitionsVolume = {
|
||||
name?: string;
|
||||
driver?: string;
|
||||
driver_opts?: {
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^.+$".
|
||||
*/
|
||||
[k: string]: string | number;
|
||||
};
|
||||
external?:
|
||||
| boolean
|
||||
| {
|
||||
name?: string;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labels?: ListOrDict;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
} & Volume;
|
||||
export type Volume = {
|
||||
name?: string;
|
||||
driver?: string;
|
||||
driver_opts?: {
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^.+$".
|
||||
*/
|
||||
[k: string]: string | number;
|
||||
};
|
||||
external?:
|
||||
| boolean
|
||||
| {
|
||||
name?: string;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labels?: ListOrDict;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
|
||||
/**
|
||||
* The Compose file is a YAML file defining a multi-containers based application.
|
||||
*/
|
||||
export interface ComposeSpecification {
|
||||
/**
|
||||
* declared for backward compatibility, ignored.
|
||||
*/
|
||||
version?: string;
|
||||
/**
|
||||
* define the Compose project name, until user defines one explicitly.
|
||||
*/
|
||||
name?: string;
|
||||
services?: PropertiesServices;
|
||||
networks?: PropertiesNetworks;
|
||||
volumes?: PropertiesVolumes;
|
||||
secrets?: PropertiesSecrets;
|
||||
configs?: PropertiesConfigs;
|
||||
/**
|
||||
* This interface was referenced by `ComposeSpecification`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface PropertiesServices {
|
||||
[k: string]: DefinitionsService;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `PropertiesServices`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^[a-zA-Z0-9._-]+$".
|
||||
*/
|
||||
export interface DefinitionsService {
|
||||
deploy?: DefinitionsDeployment;
|
||||
build?:
|
||||
| string
|
||||
| {
|
||||
context?: string;
|
||||
dockerfile?: string;
|
||||
args?: ListOrDict;
|
||||
ssh?: ListOrDict;
|
||||
labels?: ListOrDict;
|
||||
cache_from?: string[];
|
||||
cache_to?: string[];
|
||||
no_cache?: boolean;
|
||||
network?: string;
|
||||
pull?: boolean;
|
||||
target?: string;
|
||||
shm_size?: number | string;
|
||||
extra_hosts?: ListOrDict;
|
||||
isolation?: string;
|
||||
privileged?: boolean;
|
||||
secrets?: ServiceConfigOrSecret;
|
||||
tags?: string[];
|
||||
platforms?: string[];
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
blkio_config?: {
|
||||
device_read_bps?: BlkioLimit[];
|
||||
device_read_iops?: BlkioLimit[];
|
||||
device_write_bps?: BlkioLimit[];
|
||||
device_write_iops?: BlkioLimit[];
|
||||
weight?: number;
|
||||
weight_device?: BlkioWeight[];
|
||||
};
|
||||
cap_add?: string[];
|
||||
cap_drop?: string[];
|
||||
cgroup?: "host" | "private";
|
||||
cgroup_parent?: string;
|
||||
command?: string | string[];
|
||||
configs?: ServiceConfigOrSecret;
|
||||
container_name?: string;
|
||||
cpu_count?: number;
|
||||
cpu_percent?: number;
|
||||
cpu_shares?: number | string;
|
||||
cpu_quota?: number | string;
|
||||
cpu_period?: number | string;
|
||||
cpu_rt_period?: number | string;
|
||||
cpu_rt_runtime?: number | string;
|
||||
cpus?: number | string;
|
||||
cpuset?: string;
|
||||
credential_spec?: {
|
||||
config?: string;
|
||||
file?: string;
|
||||
registry?: string;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
depends_on?:
|
||||
| ListOfStrings
|
||||
| {
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^[a-zA-Z0-9._-]+$".
|
||||
*/
|
||||
[k: string]: {
|
||||
condition: "service_started" | "service_healthy" | "service_completed_successfully";
|
||||
};
|
||||
};
|
||||
device_cgroup_rules?: ListOfStrings;
|
||||
devices?: string[];
|
||||
dns?: StringOrList;
|
||||
dns_opt?: string[];
|
||||
dns_search?: StringOrList;
|
||||
domainname?: string;
|
||||
entrypoint?: string | string[];
|
||||
env_file?: StringOrList;
|
||||
environment?: ListOrDict;
|
||||
expose?: (string | number)[];
|
||||
extends?:
|
||||
| string
|
||||
| {
|
||||
service: string;
|
||||
file?: string;
|
||||
};
|
||||
external_links?: string[];
|
||||
extra_hosts?: ListOrDict;
|
||||
group_add?: (string | number)[];
|
||||
healthcheck?: DefinitionsHealthcheck;
|
||||
hostname?: string;
|
||||
image?: string;
|
||||
init?: boolean;
|
||||
ipc?: string;
|
||||
isolation?: string;
|
||||
labels?: ListOrDict;
|
||||
links?: string[];
|
||||
logging?: {
|
||||
driver?: string;
|
||||
options?: {
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^.+$".
|
||||
*/
|
||||
[k: string]: string | number | null;
|
||||
};
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
mac_address?: string;
|
||||
mem_limit?: number | string;
|
||||
mem_reservation?: string | number;
|
||||
mem_swappiness?: number;
|
||||
memswap_limit?: number | string;
|
||||
network_mode?: string;
|
||||
networks?:
|
||||
| ListOfStrings
|
||||
| {
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^[a-zA-Z0-9._-]+$".
|
||||
*/
|
||||
[k: string]: {
|
||||
aliases?: ListOfStrings;
|
||||
ipv4_address?: string;
|
||||
ipv6_address?: string;
|
||||
link_local_ips?: ListOfStrings;
|
||||
priority?: number;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
} | null;
|
||||
};
|
||||
oom_kill_disable?: boolean;
|
||||
oom_score_adj?: number;
|
||||
pid?: string | null;
|
||||
pids_limit?: number | string;
|
||||
platform?: string;
|
||||
ports?: (
|
||||
| number
|
||||
| string
|
||||
| {
|
||||
mode?: string;
|
||||
host_ip?: string;
|
||||
target?: number;
|
||||
published?: string | number;
|
||||
protocol?: string;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}
|
||||
)[];
|
||||
privileged?: boolean;
|
||||
profiles?: ListOfStrings;
|
||||
pull_policy?: "always" | "never" | "if_not_present" | "build" | "missing";
|
||||
read_only?: boolean;
|
||||
restart?: string;
|
||||
runtime?: string;
|
||||
scale?: number;
|
||||
security_opt?: string[];
|
||||
shm_size?: number | string;
|
||||
secrets?: ServiceConfigOrSecret;
|
||||
sysctls?: ListOrDict;
|
||||
stdin_open?: boolean;
|
||||
stop_grace_period?: string;
|
||||
stop_signal?: string;
|
||||
storage_opt?: {
|
||||
[k: string]: unknown;
|
||||
};
|
||||
tmpfs?: StringOrList;
|
||||
tty?: boolean;
|
||||
ulimits?: {
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^[a-z]+$".
|
||||
*/
|
||||
[k: string]:
|
||||
| number
|
||||
| {
|
||||
hard: number;
|
||||
soft: number;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
};
|
||||
user?: string;
|
||||
uts?: string;
|
||||
userns_mode?: string;
|
||||
volumes?: (
|
||||
| string
|
||||
| {
|
||||
type: string;
|
||||
source?: string;
|
||||
target?: string;
|
||||
read_only?: boolean;
|
||||
consistency?: string;
|
||||
bind?: {
|
||||
propagation?: string;
|
||||
create_host_path?: boolean;
|
||||
selinux?: "z" | "Z";
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
volume?: {
|
||||
nocopy?: boolean;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
tmpfs?: {
|
||||
size?: number | string;
|
||||
mode?: number;
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
};
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}
|
||||
)[];
|
||||
volumes_from?: string[];
|
||||
working_dir?: string;
|
||||
/**
|
||||
* This interface was referenced by `DefinitionsService`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface BlkioLimit {
|
||||
path?: string;
|
||||
rate?: number | string;
|
||||
}
|
||||
export interface BlkioWeight {
|
||||
path?: string;
|
||||
weight?: number;
|
||||
}
|
||||
export interface DefinitionsHealthcheck {
|
||||
disable?: boolean;
|
||||
interval?: string;
|
||||
retries?: number;
|
||||
test?: string | string[];
|
||||
timeout?: string;
|
||||
start_period?: string;
|
||||
/**
|
||||
* This interface was referenced by `DefinitionsHealthcheck`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface PropertiesNetworks {
|
||||
[k: string]: DefinitionsNetwork;
|
||||
}
|
||||
export interface PropertiesVolumes {
|
||||
[k: string]: DefinitionsVolume;
|
||||
}
|
||||
export interface PropertiesSecrets {
|
||||
[k: string]: DefinitionsSecret;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `PropertiesSecrets`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^[a-zA-Z0-9._-]+$".
|
||||
*/
|
||||
export interface DefinitionsSecret {
|
||||
name?: string;
|
||||
environment?: string;
|
||||
file?: string;
|
||||
external?:
|
||||
| boolean
|
||||
| {
|
||||
name?: string;
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labels?: ListOrDict;
|
||||
driver?: string;
|
||||
driver_opts?: {
|
||||
/**
|
||||
* This interface was referenced by `undefined`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^.+$".
|
||||
*/
|
||||
[k: string]: string | number;
|
||||
};
|
||||
template_driver?: string;
|
||||
/**
|
||||
* This interface was referenced by `DefinitionsSecret`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}
|
||||
export interface PropertiesConfigs {
|
||||
[k: string]: DefinitionsConfig;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `PropertiesConfigs`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^[a-zA-Z0-9._-]+$".
|
||||
*/
|
||||
export interface DefinitionsConfig {
|
||||
name?: string;
|
||||
file?: string;
|
||||
external?:
|
||||
| boolean
|
||||
| {
|
||||
name?: string;
|
||||
[k: string]: unknown;
|
||||
};
|
||||
labels?: ListOrDict;
|
||||
template_driver?: string;
|
||||
/**
|
||||
* This interface was referenced by `DefinitionsConfig`'s JSON-Schema definition
|
||||
* via the `patternProperty` "^x-".
|
||||
*/
|
||||
[k: string]: unknown;
|
||||
}
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env /bin/bash
|
||||
|
||||
CACHING_OPTIONS=""
|
||||
# If in CI and we have a defined cache bucket, use caching
|
||||
if [[ -n "${CI}" ]] && [[ -n "${AWS_BUCKET}" ]]; then
|
||||
CACHING_OPTIONS="\
|
||||
--cache-to type=s3,mode=max,bucket=$AWS_BUCKET,region=$AWS_REGION,prefix=buildCache,name=$IMAGE_NAME \
|
||||
--cache-from type=s3,mode=max,bucket=$AWS_BUCKET,region=$AWS_REGION,prefix=buildCache,name=$IMAGE_NAME"
|
||||
fi
|
||||
|
||||
docker buildx build \
|
||||
--load \
|
||||
-t $IMAGE_NAME $CACHING_OPTIONS "$@"
|
||||
Executable
+161
@@ -0,0 +1,161 @@
|
||||
const AWS_BUCKET = process.env.AWS_BUCKET;
|
||||
const scriptDir = __dirname;
|
||||
|
||||
import * as crypto from 'crypto';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as child_process from 'child_process';
|
||||
import ignore, { Ignore } from 'ignore'
|
||||
|
||||
const holePunchInteropDir = path.join(scriptDir, '..')
|
||||
const arch = child_process.execSync('docker info -f "{{.Architecture}}"').toString().trim();
|
||||
|
||||
enum Mode {
|
||||
LoadCache = 1,
|
||||
PushCache,
|
||||
}
|
||||
const modeStr = process.argv[2];
|
||||
let mode: Mode
|
||||
switch (modeStr) {
|
||||
case "push":
|
||||
mode = Mode.PushCache
|
||||
break
|
||||
case "load":
|
||||
mode = Mode.LoadCache
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unknown mode: ${modeStr}`)
|
||||
}
|
||||
|
||||
(async () => {
|
||||
for (const implFamily of fs.readdirSync(path.join(holePunchInteropDir, 'impl'))) {
|
||||
const ig = ignore()
|
||||
|
||||
addGitignoreIfPresent(ig, path.join(holePunchInteropDir, ".gitignore"))
|
||||
addGitignoreIfPresent(ig, path.join(holePunchInteropDir, "..", ".gitignore"))
|
||||
|
||||
const implFamilyDir = path.join(holePunchInteropDir, 'impl', implFamily)
|
||||
|
||||
addGitignoreIfPresent(ig, path.join(implFamilyDir, ".gitignore"))
|
||||
|
||||
for (const impl of fs.readdirSync(implFamilyDir)) {
|
||||
const implFolder = fs.realpathSync(path.join(implFamilyDir, impl));
|
||||
|
||||
if (!fs.statSync(implFolder).isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
await loadCacheOrBuild(implFolder, ig);
|
||||
}
|
||||
|
||||
await loadCacheOrBuild("router", ig);
|
||||
await loadCacheOrBuild("rust-relay", ig);
|
||||
}
|
||||
})()
|
||||
|
||||
async function loadCacheOrBuild(dir: string, ig: Ignore) {
|
||||
addGitignoreIfPresent(ig, path.join(dir, ".gitignore"))
|
||||
|
||||
// Get all the files in the dir:
|
||||
let files = walkDir(dir)
|
||||
// Turn them into relative paths:
|
||||
files = files.map(f => f.replace(dir + "/", ""))
|
||||
// Ignore files that are in the .gitignore:
|
||||
files = files.filter(ig.createFilter())
|
||||
// Sort them to be deterministic
|
||||
files = files.sort()
|
||||
|
||||
console.log(dir)
|
||||
console.log("Files:", files)
|
||||
|
||||
// Turn them back into absolute paths:
|
||||
files = files.map(f => path.join(dir, f))
|
||||
const cacheKey = await hashFiles(files)
|
||||
console.log("Cache key:", cacheKey)
|
||||
|
||||
if (mode == Mode.PushCache) {
|
||||
console.log("Pushing cache")
|
||||
try {
|
||||
if (!AWS_BUCKET) {
|
||||
throw new Error("AWS_BUCKET not set")
|
||||
}
|
||||
try {
|
||||
child_process.execSync(`aws s3 ls s3://${AWS_BUCKET}/imageCache/${cacheKey}-${arch}.tar.gz`)
|
||||
console.log("Cache already exists")
|
||||
} catch (e) {
|
||||
console.log("Cache doesn't exist", e)
|
||||
// Read image id from image.json
|
||||
const imageID = JSON.parse(fs.readFileSync(path.join(dir, 'image.json')).toString()).imageID;
|
||||
console.log(`Pushing cache for ${dir}: ${imageID}`)
|
||||
child_process.execSync(`docker image save ${imageID} | gzip | aws s3 cp - s3://${AWS_BUCKET}/imageCache/${cacheKey}-${arch}.tar.gz`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Failed to push image cache:", e)
|
||||
}
|
||||
} else if (mode == Mode.LoadCache) {
|
||||
if (fs.existsSync(path.join(dir, 'image.json'))) {
|
||||
console.log("Already built")
|
||||
return;
|
||||
}
|
||||
console.log("Loading cache")
|
||||
let cacheHit = false
|
||||
try {
|
||||
if (!AWS_BUCKET) {
|
||||
throw new Error("AWS_BUCKET not set")
|
||||
}
|
||||
const cachePath = fs.mkdtempSync(path.join(os.tmpdir(), 'cache'))
|
||||
const archivePath = path.join(cachePath, 'archive.tar.gz')
|
||||
const dockerLoadedMsg = child_process.execSync(`aws s3 cp s3://${AWS_BUCKET}/imageCache/${cacheKey}-${arch}.tar.gz ${archivePath} && docker image load -i ${archivePath}`).toString();
|
||||
const loadedImageId = dockerLoadedMsg.match(/Loaded image( ID)?: (.*)/)[2];
|
||||
if (loadedImageId) {
|
||||
console.log(`Cache hit for ${loadedImageId}`);
|
||||
fs.writeFileSync(path.join(dir, 'image.json'), JSON.stringify({imageID: loadedImageId}) + "\n");
|
||||
cacheHit = true
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("Cache not found:", e)
|
||||
}
|
||||
|
||||
if (cacheHit) {
|
||||
console.log("Building any remaining things from image.json")
|
||||
// We're building using -o image.json. This tells make to
|
||||
// not bother building image.json or anything it depends on.
|
||||
child_process.execSync(`make -o image.json`, {cwd: dir, stdio: 'inherit'})
|
||||
} else {
|
||||
console.log("No cache, building from scratch")
|
||||
child_process.execSync(`make`, {cwd: dir, stdio: "inherit"})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function walkDir(dir: string) {
|
||||
let results = [];
|
||||
fs.readdirSync(dir).forEach(f => {
|
||||
let dirPath = path.join(dir, f);
|
||||
let isDirectory = fs.statSync(dirPath).isDirectory();
|
||||
results = isDirectory ? results.concat(walkDir(dirPath)) : results.concat(path.join(dir, f));
|
||||
});
|
||||
return results;
|
||||
};
|
||||
|
||||
async function hashFiles(files: string[]): Promise<string> {
|
||||
const fileHashes = await Promise.all(
|
||||
files.map(async (file) => {
|
||||
const data = await fs.promises.readFile(file);
|
||||
return crypto.createHash('sha256').update(data).digest('hex');
|
||||
})
|
||||
);
|
||||
return crypto.createHash('sha256').update(fileHashes.join('')).digest('hex');
|
||||
}
|
||||
|
||||
function addGitignoreIfPresent(ig: Ignore, pathStr: string): boolean {
|
||||
try {
|
||||
if (fs.statSync(pathStr).isFile()) {
|
||||
ig.add(fs.readFileSync(pathStr).toString())
|
||||
}
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
rust-libp2p-*.zip
|
||||
rust-libp2p-*
|
||||
rust-libp2p-*/*
|
||||
image.json
|
||||
@@ -0,0 +1,20 @@
|
||||
image_name := rust-v0.53
|
||||
commitSha := 7f4ba690e87a867403f6266d8ee7d7db5e7a15bc
|
||||
|
||||
all: image.json
|
||||
|
||||
image.json: rust-libp2p-${commitSha}
|
||||
cd rust-libp2p-${commitSha} && IMAGE_NAME=${image_name} ../../../../dockerBuildWrapper.sh -f hole-punching-tests/Dockerfile .
|
||||
docker image inspect ${image_name} -f "{{.Id}}" | \
|
||||
xargs -I {} echo "{\"imageID\": \"{}\"}" > $@
|
||||
|
||||
rust-libp2p-${commitSha}: rust-libp2p-${commitSha}.zip
|
||||
unzip -o rust-libp2p-${commitSha}.zip
|
||||
|
||||
rust-libp2p-${commitSha}.zip:
|
||||
wget -O $@ "https://github.com/libp2p/rust-libp2p/archive/${commitSha}.zip"
|
||||
|
||||
clean:
|
||||
rm image.json
|
||||
rm rust-libp2p-*.zip
|
||||
rm -rf rust-libp2p-*
|
||||
Generated
+3196
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "libp2p hole-punch test",
|
||||
"version": "0.0.1",
|
||||
"description": "Tests hole-punching across libp2p implementations",
|
||||
"main": "testplans.ts",
|
||||
"scripts": {
|
||||
"test": "ts-node src/*.test.ts && ts-node testplans.ts",
|
||||
"renderResults": "ts-node renderResults.ts",
|
||||
"cache": "ts-node helpers/cache.ts"
|
||||
},
|
||||
"author": "marcopolo",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^4.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/yargs": "^17.0.19",
|
||||
"csv-parse": "^5.3.3",
|
||||
"csv-stringify": "^6.2.3",
|
||||
"ignore": "^5.2.4",
|
||||
"json-schema-to-typescript": "^11.0.2",
|
||||
"sqlite": "^4.1.2",
|
||||
"sqlite3": "^5.1.2",
|
||||
"yaml": "^2.2.1",
|
||||
"yargs": "^17.6.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { generateTable, load, markdownTable } from './src/lib'
|
||||
|
||||
// Read results.csv
|
||||
export async function render() {
|
||||
const runs = load("results.csv")
|
||||
|
||||
const regex = /(?<implA>.+) x (?<implB>.+) \((?<options>.*)\)/
|
||||
const parsedRuns = runs.map(run => {
|
||||
const match = run.name.match(regex)
|
||||
if (!match || match.groups === undefined) {
|
||||
throw new Error(`Run ID ${run.name} does not match the expected format`);
|
||||
}
|
||||
return {
|
||||
...run,
|
||||
implA: match.groups.implA,
|
||||
implB: match.groups.implB,
|
||||
options: match.groups.options.split(",").map(option => option.replace("_", " ").trim()),
|
||||
}
|
||||
})
|
||||
|
||||
// Group by options
|
||||
const runsByOptions = parsedRuns.reduce((acc: { [key: string]: any }, run) => {
|
||||
acc[JSON.stringify(run.options)] = [...acc[JSON.stringify(run.options)] || [], run]
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
let outMd = ""
|
||||
|
||||
for (const runGroup of Object.values(runsByOptions)) {
|
||||
outMd += `## Using: ${runGroup[0].options.join(", ")}\n`
|
||||
const table = generateTable(runGroup)
|
||||
outMd += markdownTable(table)
|
||||
outMd += "\n\n"
|
||||
}
|
||||
|
||||
console.log(outMd)
|
||||
|
||||
}
|
||||
|
||||
render()
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
FROM debian:12-slim
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
RUN --mount=type=cache,target=/var/cache/apt apt-get update && apt-get -y install iproute2 nftables jq tcpdump
|
||||
|
||||
COPY *.sh /scripts/
|
||||
RUN chmod +x /scripts/*.sh
|
||||
|
||||
HEALTHCHECK CMD [ "sh", "-c", "test $(cat /tmp/setup_done) = 1" ]
|
||||
|
||||
ENTRYPOINT ["./scripts/run.sh"]
|
||||
@@ -0,0 +1,10 @@
|
||||
image_name := hole-punch-test-router
|
||||
|
||||
all: image.json
|
||||
|
||||
image.json: Dockerfile run.sh
|
||||
IMAGE_NAME=${image_name} ../dockerBuildWrapper.sh -f Dockerfile .
|
||||
docker image inspect ${image_name} -f "{{.Id}}" | \
|
||||
xargs -I {} echo "{\"imageID\": \"{}\"}" > $@
|
||||
clean:
|
||||
rm image.json
|
||||
@@ -0,0 +1,16 @@
|
||||
# Router
|
||||
|
||||
This directory contains a Debian-based router implemented on top of nftables.
|
||||
|
||||
It expects to be run with two network interfaces:
|
||||
|
||||
- `eth0`: The "external" interface.
|
||||
- `eth1`: The "internal" interface.
|
||||
|
||||
The order of these is important.
|
||||
The router cannot possibly know which one is which and thus assumes that `eth0` is the external one and `eth1` the internal one.
|
||||
The firewall is set up to take incoming traffic on `eth1` and forward + masquerade it to `eth0`.
|
||||
|
||||
It also expects an env variable `DELAY_MS` to be set and will apply this delay as part of the routing process[^1].
|
||||
|
||||
[^1]: This is done via `tc qdisc` which only works for egress traffic. To ensure the delay applies in both directions, we divide it by 2 and apply it on both interfaces.
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
|
||||
if [ -z "$DELAY_MS" ]; then
|
||||
echo "Error: DELAY_MS is not set!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ADDR_EXTERNAL=$(ip -json addr show eth0 | jq '.[0].addr_info[0].local' -r)
|
||||
SUBNET_INTERNAL=$(ip -json addr show eth1 | jq '.[0].addr_info[0].local + "/" + (.[0].addr_info[0].prefixlen | tostring)' -r)
|
||||
|
||||
# Set up NAT
|
||||
nft add table ip nat
|
||||
nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }
|
||||
nft add rule ip nat postrouting ip saddr $SUBNET_INTERNAL oifname "eth0" snat $ADDR_EXTERNAL
|
||||
|
||||
# tc can only apply delays on egress traffic. By setting a delay for both eth0 and eth1, we achieve the active delay passed in as a parameter.
|
||||
half_of_delay=$(expr "$DELAY_MS" / 2 )
|
||||
param="${half_of_delay}ms"
|
||||
|
||||
tc qdisc add dev eth0 root netem delay $param
|
||||
tc qdisc add dev eth1 root netem delay $param
|
||||
|
||||
echo "1" > /tmp/setup_done # This will be checked by our docker HEALTHCHECK
|
||||
|
||||
tail -f /dev/null # Keep it running forever.
|
||||
@@ -0,0 +1 @@
|
||||
target/
|
||||
@@ -0,0 +1 @@
|
||||
target/
|
||||
Generated
+2959
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "relay"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.72"
|
||||
env_logger = "0.10.0"
|
||||
libp2p = { version = "0.52.1", features = ["tokio", "relay", "ed25519", "quic", "tcp", "yamux", "noise", "macros", "identify", "ping"] }
|
||||
log = "0.4.19"
|
||||
redis = { version = "0.23.0", default-features = false, features = ["tokio-comp"] }
|
||||
tokio = { version = "1.29.1", features = ["rt-multi-thread", "macros"] }
|
||||
@@ -0,0 +1,20 @@
|
||||
# syntax=docker/dockerfile:1.5-labs
|
||||
FROM rust:1.72.0 as builder
|
||||
|
||||
# Run with access to the target cache to speed up builds
|
||||
WORKDIR /workspace
|
||||
ADD . .
|
||||
|
||||
# Build the relay as a statically-linked binary. Unfortunately, we must specify the `--target` explicitly. See https://msfjarvis.dev/posts/building-static-rust-binaries-for-linux/.
|
||||
RUN --mount=type=cache,target=./target \
|
||||
--mount=type=cache,target=/usr/local/cargo/registry \
|
||||
RUSTFLAGS='-C target-feature=+crt-static' cargo build --release --package relay --target $(rustc -vV | grep host | awk '{print $2}')
|
||||
|
||||
RUN --mount=type=cache,target=./target \
|
||||
mv ./target/$(rustc -vV | grep host | awk '{print $2}')/release/relay /usr/local/bin/relay
|
||||
|
||||
FROM alpine:3
|
||||
COPY --from=builder /usr/local/bin/relay /usr/bin/relay
|
||||
RUN --mount=type=cache,target=/var/cache/apk apk add iproute2-tc
|
||||
ENV RUST_BACKTRACE=1
|
||||
CMD ["/usr/bin/relay"]
|
||||
@@ -0,0 +1,10 @@
|
||||
image_name := hole-punch-test-rust-relay
|
||||
|
||||
all: image.json
|
||||
|
||||
image.json: Cargo.lock src/** Dockerfile
|
||||
IMAGE_NAME=${image_name} ../dockerBuildWrapper.sh -f Dockerfile .
|
||||
docker image inspect ${image_name} -f "{{.Id}}" | \
|
||||
xargs -I {} echo "{\"imageID\": \"{}\"}" > $@
|
||||
clean:
|
||||
rm image.json
|
||||
@@ -0,0 +1,151 @@
|
||||
use anyhow::{bail, Context, Result};
|
||||
use libp2p::{
|
||||
core::{
|
||||
multiaddr::{Multiaddr, Protocol},
|
||||
muxing::StreamMuxerBox,
|
||||
transport::Transport,
|
||||
upgrade,
|
||||
},
|
||||
futures::future::Either,
|
||||
futures::StreamExt,
|
||||
identify, identity, noise, ping, quic, relay,
|
||||
swarm::{NetworkBehaviour, SwarmBuilder, SwarmEvent},
|
||||
tcp, yamux, PeerId, Swarm,
|
||||
};
|
||||
use redis::AsyncCommands;
|
||||
use std::net::{IpAddr, Ipv4Addr};
|
||||
|
||||
/// The redis key we push the relay's TCP listen address to.
|
||||
const RELAY_TCP_ADDRESS: &str = "RELAY_TCP_ADDRESS";
|
||||
/// The redis key we push the relay's QUIC listen address to.
|
||||
const RELAY_QUIC_ADDRESS: &str = "RELAY_QUIC_ADDRESS";
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
env_logger::builder()
|
||||
.parse_filters(
|
||||
"debug,netlink_proto=warn,rustls=warn,multistream_select=warn,libp2p_swarm::connection=info,quinn=debug,libp2p_quic=trace",
|
||||
)
|
||||
.parse_default_env()
|
||||
.init();
|
||||
|
||||
let mut swarm = make_swarm()?;
|
||||
|
||||
let tcp_listener_id = swarm.listen_on(tcp_addr(Ipv4Addr::UNSPECIFIED.into()))?;
|
||||
let quic_listener_id = swarm.listen_on(quic_addr(Ipv4Addr::UNSPECIFIED.into()))?;
|
||||
|
||||
loop {
|
||||
match swarm.next().await.expect("Infinite Stream.") {
|
||||
SwarmEvent::NewListenAddr {
|
||||
address,
|
||||
listener_id,
|
||||
} => {
|
||||
let Some(Protocol::Ip4(addr)) = address.iter().next() else {
|
||||
bail!("Expected first protocol of listen address to be Ip4")
|
||||
};
|
||||
|
||||
if addr.is_loopback() {
|
||||
log::debug!("Ignoring loop-back address: {address}");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
swarm.add_external_address(address.clone()); // We know that in our testing network setup, that we are listening on a "publicly-reachable" address.
|
||||
|
||||
log::info!("Listening on {address}");
|
||||
|
||||
let address = address
|
||||
.with(Protocol::P2p(*swarm.local_peer_id()))
|
||||
.to_string();
|
||||
|
||||
// Push each address twice because we need to connect two clients.
|
||||
|
||||
let mut redis = RedisClient::new("redis", 6379).await?;
|
||||
|
||||
if listener_id == tcp_listener_id {
|
||||
redis.push(RELAY_TCP_ADDRESS, &address).await?;
|
||||
redis.push(RELAY_TCP_ADDRESS, &address).await?;
|
||||
}
|
||||
if listener_id == quic_listener_id {
|
||||
redis.push(RELAY_QUIC_ADDRESS, &address).await?;
|
||||
redis.push(RELAY_QUIC_ADDRESS, &address).await?;
|
||||
}
|
||||
}
|
||||
other => {
|
||||
log::trace!("{other:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tcp_addr(addr: IpAddr) -> Multiaddr {
|
||||
Multiaddr::empty().with(addr.into()).with(Protocol::Tcp(0))
|
||||
}
|
||||
|
||||
fn quic_addr(addr: IpAddr) -> Multiaddr {
|
||||
Multiaddr::empty()
|
||||
.with(addr.into())
|
||||
.with(Protocol::Udp(0))
|
||||
.with(Protocol::QuicV1)
|
||||
}
|
||||
|
||||
fn make_swarm() -> Result<Swarm<Behaviour>> {
|
||||
let local_key = identity::Keypair::generate_ed25519();
|
||||
let local_peer_id = PeerId::from(local_key.public());
|
||||
log::info!("Local peer id: {local_peer_id}");
|
||||
|
||||
let transport = tcp::tokio::Transport::new(tcp::Config::default().nodelay(true))
|
||||
.upgrade(upgrade::Version::V1Lazy)
|
||||
.authenticate(noise::Config::new(&local_key)?)
|
||||
.multiplex(yamux::Config::default())
|
||||
.or_transport(quic::tokio::Transport::new(quic::Config::new(&local_key)))
|
||||
.map(|either_output, _| match either_output {
|
||||
Either::Left((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)),
|
||||
Either::Right((peer_id, muxer)) => (peer_id, StreamMuxerBox::new(muxer)),
|
||||
})
|
||||
.boxed();
|
||||
let behaviour = Behaviour {
|
||||
relay: relay::Behaviour::new(local_peer_id, relay::Config::default()),
|
||||
identify: identify::Behaviour::new(identify::Config::new(
|
||||
"/hole-punch-tests/1".to_owned(),
|
||||
local_key.public(),
|
||||
)),
|
||||
ping: ping::Behaviour::default(),
|
||||
};
|
||||
|
||||
Ok(
|
||||
SwarmBuilder::with_tokio_executor(transport, behaviour, local_peer_id)
|
||||
.substream_upgrade_protocol_override(upgrade::Version::V1Lazy)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
|
||||
struct RedisClient {
|
||||
inner: redis::aio::Connection,
|
||||
}
|
||||
|
||||
impl RedisClient {
|
||||
async fn new(host: &str, port: u16) -> Result<Self> {
|
||||
let client = redis::Client::open(format!("redis://{host}:{port}/"))
|
||||
.context("Bad redis server URL")?;
|
||||
let connection = client
|
||||
.get_async_connection()
|
||||
.await
|
||||
.context("Failed to connect to redis server")?;
|
||||
|
||||
Ok(Self { inner: connection })
|
||||
}
|
||||
|
||||
async fn push(&mut self, key: &str, value: impl ToString) -> Result<()> {
|
||||
self.inner.rpush(key, value.to_string()).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(NetworkBehaviour)]
|
||||
struct Behaviour {
|
||||
relay: relay::Behaviour,
|
||||
identify: identify::Behaviour,
|
||||
ping: ping::Behaviour,
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
import {promises as fs} from 'fs';
|
||||
import path from 'path';
|
||||
import {exec as execStd} from 'child_process';
|
||||
import util from 'util';
|
||||
import {ComposeSpecification} from "../compose-spec/compose-spec";
|
||||
import {stringify} from 'yaml';
|
||||
import {sanitizeComposeName} from "./lib";
|
||||
|
||||
const exec = util.promisify(execStd);
|
||||
|
||||
export async function run(compose: ComposeSpecification, rootAssetDir: string, dryRun: boolean): Promise<Report | null> {
|
||||
const sanitizedComposeName = sanitizeComposeName(compose.name)
|
||||
const assetDir = path.join(rootAssetDir, sanitizedComposeName);
|
||||
|
||||
await fs.mkdir(assetDir, { recursive: true })
|
||||
|
||||
|
||||
// Create compose.yaml file
|
||||
// Some docker compose environments don't like the name field to have special characters
|
||||
const composeYmlPath = path.join(assetDir, "docker-compose.yaml");
|
||||
await fs.writeFile(composeYmlPath, stringify({ ...compose, name: sanitizedComposeName }))
|
||||
|
||||
if (dryRun) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const stdoutLogFile = path.join(assetDir, `stdout.log`);
|
||||
const stderrLogFile = path.join(assetDir, `stderr.log`);
|
||||
|
||||
try {
|
||||
const { stdout, stderr } = await exec(`docker compose -f ${composeYmlPath} up --exit-code-from dialer --abort-on-container-exit`, { timeout: 60 * 1000 })
|
||||
|
||||
await fs.writeFile(stdoutLogFile, stdout);
|
||||
await fs.writeFile(stderrLogFile, stderr);
|
||||
|
||||
return JSON.parse(lastStdoutLine(stdout, "dialer", sanitizedComposeName)) as Report
|
||||
} catch (e: unknown) {
|
||||
if (isExecException(e)) {
|
||||
await fs.writeFile(stdoutLogFile, e.stdout)
|
||||
await fs.writeFile(stderrLogFile, e.stderr)
|
||||
}
|
||||
|
||||
throw e
|
||||
} finally {
|
||||
try {
|
||||
await exec(`docker compose -f ${composeYmlPath} down`);
|
||||
} catch (e) {
|
||||
console.log("Failed to compose down", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface ExecException extends Error {
|
||||
cmd?: string | undefined;
|
||||
killed?: boolean | undefined;
|
||||
code?: number | undefined;
|
||||
signal?: NodeJS.Signals | undefined;
|
||||
stdout: string;
|
||||
stderr: string;
|
||||
}
|
||||
|
||||
function isExecException(candidate: unknown): candidate is ExecException {
|
||||
return candidate && typeof candidate === 'object' && 'cmd' in candidate;
|
||||
}
|
||||
|
||||
interface Report {
|
||||
rtt_to_holepunched_peer_millis: number
|
||||
}
|
||||
|
||||
export function lastStdoutLine(stdout: string, component: string, composeName: string): string {
|
||||
const allComponentStdout = stdout.split("\n").filter(line => line.startsWith(`${composeName}-${component}-1`));
|
||||
|
||||
const exitMessage = allComponentStdout.pop();
|
||||
const lastLine = allComponentStdout.pop();
|
||||
|
||||
const [front, componentStdout] = lastLine.split("|");
|
||||
|
||||
return componentStdout.trim()
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
import sqlite3 from "sqlite3";
|
||||
import {open} from "sqlite";
|
||||
import {Version} from "../versions";
|
||||
import {ComposeSpecification} from "../compose-spec/compose-spec";
|
||||
import {sanitizeComposeName} from "./lib";
|
||||
import path from "path";
|
||||
|
||||
export async function buildTestSpecs(versions: Array<Version>, nameFilter: string | null, nameIgnore: string | null, routerImageId: string, relayImageId: string, routerDelay: number, relayDelay: number, assetDir: string): Promise<Array<ComposeSpecification>> {
|
||||
sqlite3.verbose();
|
||||
|
||||
const db = await open({
|
||||
// In memory DB. We don't persist this.
|
||||
filename: ":memory:",
|
||||
driver: sqlite3.Database,
|
||||
});
|
||||
|
||||
await db.exec('CREATE TABLE IF NOT EXISTS transports (id string not null, imageID string not null, transport string not null);');
|
||||
|
||||
await Promise.all(
|
||||
versions.flatMap(version => ([
|
||||
db.exec(`INSERT INTO transports (id, imageID, transport) VALUES ${version.transports.map(transport => `("${version.id}", "${version.containerImageID}", "${transport}")`).join(", ")};`)
|
||||
]))
|
||||
)
|
||||
|
||||
// Generate the testing combinations by SELECT'ing from transports tables the distinct combinations where the transports of the different libp2p implementations match.
|
||||
const queryResults =
|
||||
await db.all(`SELECT DISTINCT a.id as dialer, a.imageID as dialerImage, b.id as listener, b.imageID as listenerImage, a.transport
|
||||
FROM transports a,
|
||||
transports b
|
||||
WHERE a.transport == b.transport;`
|
||||
);
|
||||
await db.close();
|
||||
|
||||
return queryResults
|
||||
.map(testCase => {
|
||||
let name = `${testCase.dialer} x ${testCase.listener} (${testCase.transport})`;
|
||||
|
||||
if (nameFilter && !name.includes(nameFilter)) {
|
||||
return null
|
||||
}
|
||||
if (nameIgnore && name.includes(nameIgnore)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return buildSpec(name, testCase.dialerImage, testCase.listenerImage, routerImageId, relayImageId, testCase.transport, routerDelay, relayDelay, assetDir, {})
|
||||
})
|
||||
.filter(spec => spec !== null)
|
||||
}
|
||||
|
||||
function buildSpec(name: string, dialerImage: string, listenerImage: string, routerImageId: string, relayImageId: string, transport: string, routerDelay: number, relayDelay: number, assetDir: string, extraEnv: { [key: string]: string }): ComposeSpecification {
|
||||
let internetNetworkName = `${sanitizeComposeName(name)}_internet`
|
||||
|
||||
let startupScriptFn = (actor: "dialer" | "listener") => (`
|
||||
set -ex;
|
||||
|
||||
ROUTER_IP=$$(dig +short ${actor}_router)
|
||||
INTERNET_SUBNET=$$(curl --fail --silent --unix-socket /var/run/docker.sock http://localhost/networks/${internetNetworkName} | jq -r '.IPAM.Config[0].Subnet')
|
||||
|
||||
ip route add $$INTERNET_SUBNET via $$ROUTER_IP dev eth0
|
||||
|
||||
tcpdump -i eth0 -w /tmp/${actor}.pcap &
|
||||
|
||||
sleep 2 # Let tcpdump start up
|
||||
|
||||
hole-punch-client
|
||||
`);
|
||||
|
||||
let relayStartupScript = `
|
||||
set -ex;
|
||||
|
||||
tc qdisc add dev eth0 root netem delay ${relayDelay}ms; # Add a delay to all relayed connections
|
||||
|
||||
/usr/bin/relay
|
||||
`;
|
||||
|
||||
const dockerSocketVolume = "/var/run/docker.sock:/var/run/docker.sock";
|
||||
const tcpDumpVolume = `${path.join(assetDir, sanitizeComposeName(name))}:/tmp:rw`;
|
||||
|
||||
return {
|
||||
name,
|
||||
services: {
|
||||
relay: {
|
||||
depends_on: ["redis"],
|
||||
image: relayImageId,
|
||||
init: true,
|
||||
command: ["/bin/sh", "-c", relayStartupScript],
|
||||
networks: {
|
||||
internet: {},
|
||||
},
|
||||
cap_add: ["NET_ADMIN"]
|
||||
},
|
||||
dialer_router: {
|
||||
depends_on: ["redis"],
|
||||
image: routerImageId,
|
||||
init: true,
|
||||
environment: {
|
||||
DELAY_MS: routerDelay
|
||||
},
|
||||
networks: {
|
||||
lan_dialer: {},
|
||||
internet: {},
|
||||
},
|
||||
cap_add: ["NET_ADMIN"],
|
||||
},
|
||||
dialer: {
|
||||
depends_on: ["relay", "dialer_router", "redis"],
|
||||
image: dialerImage,
|
||||
init: true,
|
||||
command: ["/bin/sh", "-c", startupScriptFn("dialer")],
|
||||
environment: {
|
||||
TRANSPORT: transport,
|
||||
MODE: "dial",
|
||||
},
|
||||
networks: {
|
||||
lan_dialer: {},
|
||||
},
|
||||
cap_add: ["NET_ADMIN"],
|
||||
volumes: [dockerSocketVolume, tcpDumpVolume]
|
||||
},
|
||||
listener_router: {
|
||||
depends_on: ["redis"],
|
||||
image: routerImageId,
|
||||
init: true,
|
||||
environment: {
|
||||
DELAY_MS: routerDelay
|
||||
},
|
||||
networks: {
|
||||
lan_listener: {},
|
||||
internet: {},
|
||||
},
|
||||
cap_add: ["NET_ADMIN"]
|
||||
},
|
||||
listener: {
|
||||
depends_on: ["relay", "listener_router", "redis"],
|
||||
image: listenerImage,
|
||||
init: true,
|
||||
command: ["/bin/sh", "-c", startupScriptFn("listener")],
|
||||
environment: {
|
||||
TRANSPORT: transport,
|
||||
MODE: "listen",
|
||||
SSLKEYLOGFILE: "/tmp/tls.key"
|
||||
},
|
||||
networks: {
|
||||
lan_listener: {},
|
||||
},
|
||||
cap_add: ["NET_ADMIN"],
|
||||
volumes: [dockerSocketVolume, tcpDumpVolume]
|
||||
},
|
||||
redis: {
|
||||
image: "redis:7-alpine",
|
||||
healthcheck: {
|
||||
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
|
||||
},
|
||||
networks: {
|
||||
internet: {
|
||||
aliases: ["redis"]
|
||||
},
|
||||
lan_dialer: {
|
||||
aliases: ["redis"]
|
||||
},
|
||||
lan_listener: {
|
||||
aliases: ["redis"]
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
networks: {
|
||||
lan_dialer: {},
|
||||
lan_listener: {},
|
||||
internet: {},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import * as csv from "csv-parse/sync";
|
||||
import fs from "fs";
|
||||
|
||||
export type ResultLine = {
|
||||
name: string;
|
||||
outcome: string;
|
||||
error: string;
|
||||
};
|
||||
|
||||
export type ParsedResultLine = {
|
||||
name: string;
|
||||
outcome: string;
|
||||
error: string;
|
||||
implA: string;
|
||||
implB: string;
|
||||
};
|
||||
|
||||
export type ResultFile = ResultLine[];
|
||||
|
||||
export type CellRender = (a: string, b: string, line: ResultLine) => string;
|
||||
|
||||
/**
|
||||
* called for every cell in the table.
|
||||
*
|
||||
* This is designed to let future implementers add more complex ouput interpretation, with nested tables, etc.
|
||||
*/
|
||||
export const defaultCellRender: CellRender = (a, b, line) => {
|
||||
let result = ":red_circle:";
|
||||
|
||||
if (line.outcome === "success") {
|
||||
result = ":green_circle:";
|
||||
}
|
||||
|
||||
if (process.env.RUN_URL) {
|
||||
result = `[${result}](${process.env.RUN_URL})`;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const load = (path: string): ResultFile => {
|
||||
return csv.parse(fs.readFileSync(path, "utf8"), {
|
||||
columns: true,
|
||||
skip_empty_lines: true,
|
||||
delimiter: ",",
|
||||
}) as ResultFile;
|
||||
};
|
||||
|
||||
export const save = (path: string, content: string) => {
|
||||
fs.writeFileSync(path, content);
|
||||
};
|
||||
|
||||
type PairOfImplementation = [string, string];
|
||||
|
||||
export const listUniqPairs = (pairs: PairOfImplementation[]): string[] => {
|
||||
const uniq = new Set<string>();
|
||||
|
||||
for (const [a, b] of pairs) {
|
||||
uniq.add(a);
|
||||
uniq.add(b);
|
||||
}
|
||||
|
||||
return Array.from(uniq).sort();
|
||||
};
|
||||
|
||||
export const generateEmptyMatrix = (
|
||||
keys: string[],
|
||||
defaultValue: string
|
||||
): string[][] => {
|
||||
const header = [" ", ...keys];
|
||||
|
||||
const matrix = [header];
|
||||
const rowOfDefaultValues = Array<string>(keys.length).fill(defaultValue);
|
||||
|
||||
for (const key of keys) {
|
||||
const row = [key, ...rowOfDefaultValues];
|
||||
matrix.push(row);
|
||||
}
|
||||
|
||||
return matrix;
|
||||
};
|
||||
|
||||
export const generateTable = (
|
||||
results: Array<ParsedResultLine>,
|
||||
defaultValue: string = ":white_circle:",
|
||||
testedCell: CellRender = defaultCellRender
|
||||
): string[][] => {
|
||||
const pairs = results.map(({ implA, implB }) => [implA, implB] as PairOfImplementation);
|
||||
const uniqPairs = listUniqPairs(pairs);
|
||||
|
||||
const matrix = generateEmptyMatrix(uniqPairs, defaultValue);
|
||||
matrix[0][0] = "⬇️ dialer 📞 \\ ➡️ listener 🎧"
|
||||
|
||||
for (const result of results) {
|
||||
const { implA, implB } = result
|
||||
const i = uniqPairs.indexOf(implA);
|
||||
const j = uniqPairs.indexOf(implB);
|
||||
|
||||
const cell = testedCell(implA, implB, result);
|
||||
|
||||
matrix[i + 1][j + 1] = cell;
|
||||
}
|
||||
|
||||
return matrix;
|
||||
};
|
||||
|
||||
export const markdownTable = (table: string[][]): string => {
|
||||
const wrapped = (x: string) => `| ${x} |`;
|
||||
|
||||
const header = table[0].join(" | ");
|
||||
const separator = table[0].map((x) => "-".repeat(x.length)).join(" | ");
|
||||
|
||||
const rows = table.slice(1).map((row) => row.join(" | "));
|
||||
|
||||
const body = [wrapped(header), wrapped(separator), ...rows.map(wrapped)].join(
|
||||
"\n"
|
||||
);
|
||||
|
||||
return body;
|
||||
};
|
||||
|
||||
export function sanitizeComposeName(name: string) {
|
||||
return name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import {lastStdoutLine} from "./compose-runner";
|
||||
|
||||
let exampleStdout = `
|
||||
Attaching to rust-v0_52_x_rust-v0_52__quic_-dialer-1, rust-v0_52_x_rust-v0_52__quic_-dialer_router-1, rust-v0_52_x_rust-v0_52__quic_-listener-1, rust-v0_52_x_rust-v0_52__quic_-listener_router-1, rust-v0_52_x_rust-v0_52__quic_-redis-1, rust-v0_52_x_rust-v0_52__quic_-relay-1
|
||||
rust-v0_52_x_rust-v0_52__quic_-redis-1 | 1:C 19 Sep 2023 05:19:20.620 # WARNING Memory overcommit must be enabled! Without it, a background save or replication may fail under low memory condition. Being disabled, it can also cause failures without low memory condition, see https://github.com/jemalloc/jemalloc/issues/1328. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
|
||||
rust-v0_52_x_rust-v0_52__quic_-redis-1 | 1:C 19 Sep 2023 05:19:20.620 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
|
||||
rust-v0_52_x_rust-v0_52__quic_-redis-1 | 1:C 19 Sep 2023 05:19:20.620 * Redis version=7.2.1, bits=64, commit=00000000, modified=0, pid=1, just started
|
||||
rust-v0_52_x_rust-v0_52__quic_-redis-1 | 1:C 19 Sep 2023 05:19:20.620 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
|
||||
rust-v0_52_x_rust-v0_52__quic_-redis-1 | 1:M 19 Sep 2023 05:19:20.620 * monotonic clock: POSIX clock_gettime
|
||||
rust-v0_52_x_rust-v0_52__quic_-redis-1 | 1:M 19 Sep 2023 05:19:20.621 * Running mode=standalone, port=6379.
|
||||
rust-v0_52_x_rust-v0_52__quic_-redis-1 | 1:M 19 Sep 2023 05:19:20.621 * Server initialized
|
||||
rust-v0_52_x_rust-v0_52__quic_-redis-1 | 1:M 19 Sep 2023 05:19:20.621 * Ready to accept connections tcp
|
||||
rust-v0_52_x_rust-v0_52__quic_-dialer-1 | {"rtt_to_holepunched_peer_millis":201}
|
||||
rust-v0_52_x_rust-v0_52__quic_-dialer-1 exited with code 0
|
||||
`;
|
||||
|
||||
const line = lastStdoutLine(exampleStdout, "dialer", "rust-v0_52_x_rust-v0_52__quic_");
|
||||
|
||||
if (line != `{"rtt_to_holepunched_peer_millis":201}`) {
|
||||
throw new Error("Unexpected stdout")
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import { buildTestSpecs } from "./src/generator"
|
||||
import { Version, versions } from "./versions"
|
||||
import { promises as fs } from "fs";
|
||||
import {ExecException, run} from "./src/compose-runner"
|
||||
import { stringify } from "csv-stringify/sync"
|
||||
import { stringify as YAMLStringify } from "yaml"
|
||||
import yargs from "yargs/yargs"
|
||||
import path from "path";
|
||||
|
||||
(async () => {
|
||||
const WorkerCount = parseInt(process.env.WORKER_COUNT || "1")
|
||||
const argv = await yargs(process.argv.slice(2))
|
||||
.options({
|
||||
'name-filter': {
|
||||
description: 'Only run tests including this name',
|
||||
default: "",
|
||||
},
|
||||
'name-ignore': {
|
||||
description: 'Do not run any tests including this name',
|
||||
default: "",
|
||||
},
|
||||
'dry-run': {
|
||||
description: "Don't actually run the test, just generate the compose files",
|
||||
default: false,
|
||||
type: 'boolean'
|
||||
},
|
||||
'extra-versions-dir': {
|
||||
description: 'Look for extra versions in this directory. Version files must be in json format',
|
||||
default: "",
|
||||
type: 'string'
|
||||
},
|
||||
'extra-version': {
|
||||
description: 'Paths to JSON files for additional versions to include in the test matrix',
|
||||
default: [],
|
||||
type: 'array'
|
||||
},
|
||||
})
|
||||
.help()
|
||||
.version(false)
|
||||
.alias('help', 'h').argv;
|
||||
const extraVersionsDir = argv.extraVersionsDir
|
||||
const extraVersions: Array<Version> = []
|
||||
if (extraVersionsDir !== "") {
|
||||
try {
|
||||
const files = await fs.readdir(extraVersionsDir);
|
||||
for (const file of files) {
|
||||
const contents = await fs.readFile(path.join(extraVersionsDir, file))
|
||||
extraVersions.push(...JSON.parse(contents.toString()))
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Error reading extra versions")
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
for (let versionPath of argv.extraVersion.filter(p => p !== "")) {
|
||||
const contents = await fs.readFile(versionPath);
|
||||
extraVersions.push(JSON.parse(contents.toString()))
|
||||
}
|
||||
|
||||
let nameFilter: string | null = argv["name-filter"]
|
||||
if (nameFilter === "") {
|
||||
nameFilter = null
|
||||
}
|
||||
let nameIgnore: string | null = argv["name-ignore"]
|
||||
if (nameIgnore === "") {
|
||||
nameIgnore = null
|
||||
}
|
||||
|
||||
let routerImageId = JSON.parse(await fs.readFile(path.join(".", "router", "image.json"), "utf-8")).imageID;
|
||||
let relayImageId = JSON.parse(await fs.readFile(path.join(".", "rust-relay", "image.json"), "utf-8")).imageID;
|
||||
|
||||
const routerDelay = 100;
|
||||
const relayDelay = 25;
|
||||
|
||||
const rttRelayedConnection = routerDelay * 2 + relayDelay * 2;
|
||||
const rttDirectConnection = routerDelay * 2;
|
||||
|
||||
const assetDir = path.join(__dirname, "runs");
|
||||
|
||||
let testSpecs = await buildTestSpecs(versions.concat(extraVersions), nameFilter, nameIgnore, routerImageId, relayImageId, routerDelay, relayDelay, assetDir)
|
||||
|
||||
console.log(`Running ${testSpecs.length} tests`)
|
||||
const failures: Array<{ name: String, e: ExecException }> = []
|
||||
const statuses: Array<string[]> = [["name", "outcome"]]
|
||||
const workers = new Array(WorkerCount).fill({}).map(async () => {
|
||||
while (true) {
|
||||
const testSpec = testSpecs.pop()
|
||||
if (testSpec == null) {
|
||||
return
|
||||
}
|
||||
const name = testSpec.name;
|
||||
if (!name) {
|
||||
console.warn("Skipping testSpec without name")
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log("Running test spec: " + name)
|
||||
|
||||
try {
|
||||
const report = await run(testSpec, assetDir, argv['dry-run'] as boolean);
|
||||
|
||||
if (report != null) {
|
||||
const rttDifference = Math.abs(report.rtt_to_holepunched_peer_millis - rttDirectConnection);
|
||||
|
||||
if (rttDifference > 5) {
|
||||
// Emit a warning but don't do anything for now.
|
||||
console.warn(`Expected RTT of direct connection to be ~${rttDirectConnection}ms but was ${report.rtt_to_holepunched_peer_millis}ms`)
|
||||
}
|
||||
}
|
||||
|
||||
statuses.push([name, "success"])
|
||||
} catch (e) {
|
||||
failures.push({ name, e })
|
||||
statuses.push([name, "failure"])
|
||||
}
|
||||
}
|
||||
})
|
||||
await Promise.all(workers)
|
||||
|
||||
console.log(`${failures.length} failures:`)
|
||||
|
||||
for (const [number, {name, e}] of failures.entries()) {
|
||||
console.log(`---------- ${name} ---------- (${number + 1} / ${failures.length})\n`);
|
||||
console.log(e.stderr)
|
||||
}
|
||||
|
||||
await fs.writeFile("results.csv", stringify(statuses))
|
||||
|
||||
console.log("Run complete")
|
||||
})()
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"target": "ES2015",
|
||||
"moduleResolution": "node"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import fs from "fs"
|
||||
|
||||
export type Version = {
|
||||
id: string,
|
||||
// This can be the image ID, or a function that takes the version ID and returns the image ID.
|
||||
// By default it uses the canonicalImageIDLookup.
|
||||
containerImageID?: string,
|
||||
transports: Array<"tcp" | "quic">,
|
||||
}
|
||||
|
||||
export const versions: Array<Version> = [
|
||||
{
|
||||
id: "rust-v0.53",
|
||||
transports: ["tcp", "quic"]
|
||||
} as Version,
|
||||
].map((v: Version) => (typeof v.containerImageID === "undefined" ? ({ ...v, containerImageID: readImageId(canonicalImagePath(v.id)) }) : v))
|
||||
|
||||
function readImageId(path: string): string {
|
||||
return JSON.parse(fs.readFileSync(path, "utf8")).imageID;
|
||||
}
|
||||
|
||||
// Finds the `image.json` for the given version id.
|
||||
//
|
||||
// Expects the form of "<impl>-vX.Y.Z" or "<impl>vX.Y".
|
||||
// The image id must be in the file "./impl/<impl>/vX.Y/image.json" or "./impl/<impl>/v0.0.Z/image.json".
|
||||
function canonicalImagePath(id: string): string {
|
||||
// Split by implementation and version
|
||||
const [impl, version] = id.split("-v")
|
||||
// Drop the patch version
|
||||
const [major, minor, patch] = version.split(".")
|
||||
let versionFolder = `v${major}.${minor}`
|
||||
if (major === "0" && minor === "0") {
|
||||
// We're still in the 0.0.x phase, so we use the patch version
|
||||
versionFolder = `v0.0.${patch}`
|
||||
}
|
||||
// Read the image ID from the JSON file on the filesystem
|
||||
return `./impl/${impl}/${versionFolder}/image.json`
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
# `Plan:` Nodes Connectivity (Transports, Hole Punching, Relay)
|
||||
|
||||

|
||||
|
||||
Ensuring that a node can always connect to the rest of the network, if not completely isolated.
|
||||
|
||||
## What is being optimized (min/max, reach)
|
||||
|
||||
- (Reach) The number of nodes that are able to dial to any other node (100%)
|
||||
|
||||
## Plan Parameters
|
||||
|
||||
- **Network Parameters**
|
||||
- `Region` - Region or Regions where the test should be run at (default to single region)
|
||||
- Ran with with an arbitraty amount of nodes (from 10 to 1000000) - N
|
||||
- Nodes being beyind a NAT/Firewall - F (F is a % of N)
|
||||
- Nodes running the Image with IPFS on a Browser - B (B is a % of N)
|
||||
- Nodes running the Image with go-ipfs using only TCP - T (T is a % of N)
|
||||
- Nodes running the Image with go-ipfs using only QUIC - Q (Q is a % of N)
|
||||
- Nodes running the Image with go-ipfs using only WebSockets - W (W is a % of N)
|
||||
- Nodes running the Image with go-ipfs using only WebRTC - C (C is a % of N)
|
||||
- **Image Parameters**
|
||||
- Image A - Base `go-ipfs`
|
||||
- `Transport` The only transport to be used
|
||||
- Image B - Base `js-ipfs` running in a Browser
|
||||
- `Browser` The Browser in which js-ipfs will be running from
|
||||
|
||||
## Tests
|
||||
|
||||
### `Test:` TCP hole punching
|
||||
|
||||
- **Test Parameters**
|
||||
- n/a
|
||||
- **Narrative**
|
||||
- **Warm up**
|
||||
- Create the Bootstrapper nodes that are connected among themselves and support every transport
|
||||
- **Act I**
|
||||
- b
|
||||
- **Act II**
|
||||
- c
|
||||
- **Act III**
|
||||
- d
|
||||
|
||||
## `Test:` uTP hole punching
|
||||
|
||||
- **Test Parameters**
|
||||
- n/a
|
||||
- **Narrative**
|
||||
- **Warm up**
|
||||
- Create the Bootstrapper nodes that are connected among themselves and support every transport
|
||||
- **Act I**
|
||||
- b
|
||||
- **Act II**
|
||||
- c
|
||||
- **Act III**
|
||||
- d
|
||||
|
||||
### `Test:` QUIC hole punching
|
||||
|
||||
- **Test Parameters**
|
||||
- n/a
|
||||
- **Narrative**
|
||||
- **Warm up**
|
||||
- Create the Bootstrapper nodes that are connected among themselves and support every transport
|
||||
- **Act I**
|
||||
- b
|
||||
- **Act II**
|
||||
- c
|
||||
- **Act III**
|
||||
- d
|
||||
|
||||
## `Test:` WebRTC hole punching
|
||||
|
||||
- **Test Parameters**
|
||||
- n/a
|
||||
- **Narrative**
|
||||
- **Warm up**
|
||||
- Create the Bootstrapper nodes that are connected among themselves and support every transport
|
||||
- **Act I**
|
||||
- b
|
||||
- **Act II**
|
||||
- c
|
||||
- **Act III**
|
||||
- d
|
||||
|
||||
## `Test:` Circuit Relay (between all transports combinations)
|
||||
|
||||
- **Test Parameters**
|
||||
- n/a
|
||||
- **Narrative**
|
||||
- **Warm up**
|
||||
- Create the Bootstrapper nodes that are connected among themselves and support every transport
|
||||
- **Act I**
|
||||
- b
|
||||
- **Act II**
|
||||
- c
|
||||
- **Act III**
|
||||
- d
|
||||
|
||||
## `Test:` go-ipfs to js-ipfs to browser Interop (Transports & Relay)
|
||||
|
||||
- **Test Parameters**
|
||||
- n/a
|
||||
- **Narrative**
|
||||
- **Warm up**
|
||||
- Create the Bootstrapper nodes that are connected among themselves and support every transport
|
||||
- **Act I**
|
||||
- b
|
||||
- **Act II**
|
||||
- c
|
||||
- **Act III**
|
||||
- d
|
||||
@@ -0,0 +1,5 @@
|
||||
ssh-keygen:
|
||||
ssh-keygen -t ed25519 -f ./terraform/modules/short_lived/files/perf -N ''
|
||||
|
||||
ssh-add:
|
||||
ssh-add ./terraform/modules/short_lived/files/perf
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
# libp2p performance benchmarking
|
||||
|
||||
This project includes the following components:
|
||||
|
||||
- `terraform/`: a Terraform scripts to provision infrastructure
|
||||
- `impl/`: implementations of the [libp2p perf protocol](https://github.com/libp2p/specs/blob/master/perf/perf.md) running on top of e.g. go-libp2p, rust-libp2p or Go's std-library https stack
|
||||
- `runner/`: a set of scripts building and running the above implementations on the above infrastructure, reporting the results in `benchmark-results.json`
|
||||
|
||||
Benchmark results can be visualized with https://observablehq.com/@libp2p-workspace/performance-dashboard.
|
||||
|
||||
## Running via GitHub Action
|
||||
|
||||
1. Create a pull request with your changes on https://github.com/libp2p/test-plans/.
|
||||
2. Trigger GitHub Action for branch on https://github.com/libp2p/test-plans/actions/workflows/perf.yml (see _Run workflow_ button).
|
||||
3. Wait for action run to finish and to push a commit to your branch.
|
||||
4. Visualize results on https://observablehq.com/@libp2p-workspace/performance-dashboard.
|
||||
|
||||
## Running manually
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Terraform 1.5.4 or later
|
||||
- Node.js 18 or later
|
||||
- [an AWS IAM user](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_users.html)
|
||||
|
||||
|
||||
### Provision infrastructure
|
||||
|
||||
1. Save your public SSH key as the file `./terraform/modules/short_lived/files/perf.pub`; or generate a new key pair with `make ssh-keygen` and add it to your SSH agent with `make ssh-add`.
|
||||
2. `cd terraform/configs/local`
|
||||
3. `terraform init`
|
||||
4. `terraform apply`
|
||||
5. `CLIENT_IP=$(terraform output -raw client_ip)`
|
||||
6. `SERVER_IP=$(terraform output -raw server_ip)`
|
||||
|
||||
**Notes**
|
||||
- While running terraform you may encounter the following error:
|
||||
```bash
|
||||
Error: collecting instance settings: reading EC2 Launch Template versions: couldn't find resource
|
||||
│
|
||||
│ with module.short_lived_server[0].aws_instance.perf,
|
||||
│ on ../../modules/short_lived/main.tf line 15, in resource "aws_instance" "perf":
|
||||
│ 15: resource "aws_instance" "perf" {
|
||||
```
|
||||
- This implies that you haven't deployed the long-lived infrastructure on your AWS account. To do so along with each short-lived deployment, you can set *TF_VAR* [`long_lived_enabled`](./terraform/configs/local/terraform.tf#L42) env variable to default to `true`. Terraform should then spin up the long-lived resources that are required for the short-lived resources to be created.
|
||||
|
||||
- It's best to destroy the infrastructure after you're done with your testing, you can do that by running `terraform destroy`.
|
||||
|
||||
### Build and run libp2p implementations
|
||||
|
||||
Given you have provisioned your infrastructure, you can now build and run the libp2p implementations on the AWS instances.
|
||||
|
||||
1. `cd runner`
|
||||
2. `npm ci`
|
||||
3. `npm run start -- --client-public-ip $CLIENT_IP --server-public-ip $SERVER_IP`
|
||||
* Note: The default number of iterations that perf will run is 10; desired iterations can be set with the `--iterations <value>` option.
|
||||
|
||||
### Deprovision infrastructure
|
||||
|
||||
1. `cd terraform/configs/local`
|
||||
2. `terraform destroy`
|
||||
|
||||
## Adding a new implementation or a new version
|
||||
|
||||
1. Add the implementation to new subdirectory in [`impl/*`](./impl/).
|
||||
- For a new implementation, create a folder `impl/<your-implementation-name>/` e.g. `go-libp2p`
|
||||
- For a new version of an existing implementation, create a folder `impl/<your-implementation-name>/<your-implementation-version>`.
|
||||
- In that folder include a `Makefile` that builds an executable and stores it next to the `Makefile` under the name `perf`.
|
||||
- Requirements for the executable:
|
||||
- Running as a libp2p-perf server:
|
||||
- The perf server must not exit as it will be closed by the test runner.
|
||||
- The executable must accept the command flag `--run-server` which indicates it's running as server.
|
||||
- Running as a libp2p-perf client
|
||||
- Given that perf is a client driven set of benchmarks, the performance will be measured by the client.
|
||||
- Input via command line
|
||||
- `--server-address`
|
||||
- `--transport` (see [`runner/versions.ts`](./runner/src/versions.ts#L7-L43) for possible variants)
|
||||
- `--upload-bytes` number of bytes to upload per stream.
|
||||
- `--download-bytes` number of bytes to download per stream.
|
||||
- Output
|
||||
- Logging MUST go to `stderr`.
|
||||
- Measurement output is printed to `stdout` as JSON.
|
||||
- The output schema is:
|
||||
``` typescript
|
||||
interface Data {
|
||||
type: "intermediary" | "final";
|
||||
timeSeconds: number;
|
||||
uploadBytes: number;
|
||||
downloadBytes: number;
|
||||
}
|
||||
```
|
||||
- Every second the client must print the current progress to stdout. See example below. Note the `type: "intermediary"`.
|
||||
``` json
|
||||
{
|
||||
"type": "intermediary",
|
||||
"timeSeconds": 1.004957645,
|
||||
"uploadBytes": 73039872,
|
||||
"downloadBytes": 0
|
||||
},
|
||||
```
|
||||
- Before terminating the client must print a final summary. See example below. Note the `type: "final"`. Also note that the measurement includes the time to (1) establish the connection, (2) upload the bytes and (3) download the bytes.
|
||||
``` json
|
||||
{
|
||||
"type": "final",
|
||||
"timeSeconds": 60.127230659,
|
||||
"uploadBytes": 4382392320,
|
||||
"downloadBytes": 0
|
||||
}
|
||||
```
|
||||
2. For a new implementation, in [`impl/Makefile` include your implementation in the `all` target.](./impl/Makefile#L7)
|
||||
3. For a new version, reference version in [`runner/src/versions.ts`](./runner/src/versions.ts#L7-L43).
|
||||
@@ -0,0 +1,24 @@
|
||||
GO_SUBDIRS := $(wildcard go-libp2p/*/.)
|
||||
RUST_SUBDIRS := $(wildcard rust-libp2p/*/.)
|
||||
HTTPS_SUBDIRS := $(wildcard https/*/.)
|
||||
QUIC_GO_SUBDIRS := $(wildcard quic-go/*/.)
|
||||
JS_SUBDIRS := $(wildcard js-libp2p/*/.)
|
||||
|
||||
all: $(RUST_SUBDIRS) $(GO_SUBDIRS) $(HTTPS_SUBDIRS) $(QUIC_GO_SUBDIRS) $(JS_SUBDIRS)
|
||||
$(RUST_SUBDIRS):
|
||||
$(MAKE) -C $@
|
||||
$(GO_SUBDIRS):
|
||||
$(MAKE) -C $@
|
||||
$(HTTPS_SUBDIRS):
|
||||
$(MAKE) -C $@
|
||||
$(QUIC_GO_SUBDIRS):
|
||||
$(MAKE) -C $@
|
||||
$(JS_SUBDIRS):
|
||||
$(MAKE) -C $@
|
||||
|
||||
clean: $(RUST_SUBDIRS:%=%clean) $(GO_SUBDIRS:%=%clean) $(HTTPS_SUBDIRS:%=%clean) $(QUIC_GO_SUBDIRS:%=%clean) $(JS_SUBDIRS:%=%clean)
|
||||
|
||||
%clean:
|
||||
$(MAKE) -C $* clean
|
||||
|
||||
.PHONY: $(RUST_SUBDIRS) $(GO_SUBDIRS) $(HTTPS_SUBDIRS) $(QUIC_GO_SUBDIRS) $(JS_SUBDIRS) all clean
|
||||
@@ -0,0 +1,4 @@
|
||||
go-libp2p-*.zip
|
||||
go-libp2p-*
|
||||
go-libp2p-*/*
|
||||
image.json
|
||||
@@ -0,0 +1,3 @@
|
||||
perf
|
||||
.cache
|
||||
v0.27
|
||||
@@ -0,0 +1,14 @@
|
||||
# Build Go Binary
|
||||
FROM golang:1.20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY *.go ./
|
||||
RUN go build -o perf .
|
||||
|
||||
FROM alpine
|
||||
|
||||
COPY --from=builder /app/perf /app/perf
|
||||
|
||||
ENTRYPOINT [ "/app/perf" ]
|
||||
@@ -0,0 +1,13 @@
|
||||
GO_FILES := $(wildcard *.go)
|
||||
|
||||
all: perf
|
||||
|
||||
perf: $(GO_FILES)
|
||||
docker run --rm --user "$(shell id -u):$(shell id -g)" -v "$(shell pwd)":/usr/src/myapp -w /usr/src/myapp -e GOCACHE=/usr/src/myapp/.cache golang:1.20 go build -o perf .
|
||||
|
||||
clean:
|
||||
rm perf
|
||||
rm .cache
|
||||
rm v0.27
|
||||
|
||||
.PHONY: all clean
|
||||
@@ -0,0 +1,98 @@
|
||||
module github.com/libp2p/test-plans/perf/impl/go-libp2p/v0.27
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/ipfs/go-log/v2 v2.5.1
|
||||
github.com/libp2p/go-buffer-pool v0.1.0
|
||||
github.com/libp2p/go-libp2p v0.27.0
|
||||
github.com/multiformats/go-multiaddr v0.9.0
|
||||
github.com/stretchr/testify v1.8.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/benbjohnson/clock v1.3.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/containerd/cgroups v1.1.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/elastic/gosigar v0.14.2 // indirect
|
||||
github.com/flynn/noise v1.0.0 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b // indirect
|
||||
github.com/huin/goupnp v1.1.0 // indirect
|
||||
github.com/ipfs/go-cid v0.4.1 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
|
||||
github.com/klauspost/compress v1.16.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||
github.com/koron/go-ssdp v0.0.4 // indirect
|
||||
github.com/libp2p/go-cidranger v1.1.0 // indirect
|
||||
github.com/libp2p/go-flow-metrics v0.1.0 // indirect
|
||||
github.com/libp2p/go-libp2p-asn-util v0.3.0 // indirect
|
||||
github.com/libp2p/go-msgio v0.3.0 // indirect
|
||||
github.com/libp2p/go-nat v0.1.0 // indirect
|
||||
github.com/libp2p/go-netroute v0.2.1 // indirect
|
||||
github.com/libp2p/go-reuseport v0.2.0 // indirect
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0 // indirect
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
||||
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/miekg/dns v1.1.53 // indirect
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||
github.com/multiformats/go-base36 v0.2.0 // indirect
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
|
||||
github.com/multiformats/go-multibase v0.2.0 // indirect
|
||||
github.com/multiformats/go-multicodec v0.8.1 // indirect
|
||||
github.com/multiformats/go-multihash v0.2.1 // indirect
|
||||
github.com/multiformats/go-multistream v0.4.1 // indirect
|
||||
github.com/multiformats/go-varint v0.0.7 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.9.2 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.0.2 // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.42.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
|
||||
github.com/quic-go/quic-go v0.33.0 // indirect
|
||||
github.com/quic-go/webtransport-go v0.5.2 // indirect
|
||||
github.com/raulk/go-watchdog v1.3.0 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/dig v1.16.1 // indirect
|
||||
go.uber.org/fx v1.19.2 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
golang.org/x/crypto v0.7.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
|
||||
golang.org/x/mod v0.10.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.7.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/tools v0.7.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/blake3 v1.1.7 // indirect
|
||||
nhooyr.io/websocket v1.8.7 // indirect
|
||||
)
|
||||
@@ -0,0 +1,506 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo=
|
||||
dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
|
||||
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
|
||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||
github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
|
||||
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
|
||||
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
|
||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU=
|
||||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
|
||||
github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4=
|
||||
github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ=
|
||||
github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag=
|
||||
github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk=
|
||||
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
|
||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
|
||||
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b h1:Qcx5LM0fSiks9uCyFZwDBUasd3lxd1RM0GYpL+Li5o4=
|
||||
github.com/google/pprof v0.0.0-20230405160723-4a4c7d95572b/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
|
||||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
|
||||
github.com/huin/goupnp v1.1.0 h1:gEe0Dp/lZmPZiDFzJJaOfUpOvv2MKUkoBX8lDrn9vKU=
|
||||
github.com/huin/goupnp v1.1.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
||||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
||||
github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=
|
||||
github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk=
|
||||
github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
|
||||
github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
|
||||
github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY=
|
||||
github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
|
||||
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk=
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.16.4 h1:91KN02FnsOYhuunwU4ssRe8lc2JosWmizWa91B5v1PU=
|
||||
github.com/klauspost/compress v1.16.4/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk=
|
||||
github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0=
|
||||
github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8=
|
||||
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
|
||||
github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c=
|
||||
github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic=
|
||||
github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM=
|
||||
github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro=
|
||||
github.com/libp2p/go-libp2p v0.27.0 h1:QbhrTuB0ln9j9op6yAOR0o+cx/qa9NyNZ5ov0Tql8ZU=
|
||||
github.com/libp2p/go-libp2p v0.27.0/go.mod h1:FAvvfQa/YOShUYdiSS03IR9OXzkcJXwcNA2FUCh9ImE=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.3.0 h1:gMDcMyYiZKkocGXDQ5nsUQyquC9+H+iLEQHwOCZ7s8s=
|
||||
github.com/libp2p/go-libp2p-asn-util v0.3.0/go.mod h1:B1mcOrKUE35Xq/ASTmQ4tN3LNzVVaMNmq2NACuqyB9w=
|
||||
github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA=
|
||||
github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0=
|
||||
github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM=
|
||||
github.com/libp2p/go-nat v0.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg=
|
||||
github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM=
|
||||
github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=
|
||||
github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU=
|
||||
github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ=
|
||||
github.com/libp2p/go-reuseport v0.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560=
|
||||
github.com/libp2p/go-reuseport v0.2.0/go.mod h1:bvVho6eLMm6Bz5hmU0LYN3ixd3nPPvtIlaURZZgOY4k=
|
||||
github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0 h1:+Y80dV2Yx/kv7Y7JKu0LECyVdMXm1VUoko+VQ9rBfZQ=
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4=
|
||||
github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
|
||||
github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8=
|
||||
github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms=
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc=
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU=
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc=
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s=
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
|
||||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
|
||||
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE=
|
||||
github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI=
|
||||
github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0=
|
||||
github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4=
|
||||
github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo=
|
||||
github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4=
|
||||
github.com/multiformats/go-multiaddr v0.9.0 h1:3h4V1LHIk5w4hJHekMKWALPXErDfz/sggzwC/NcqbDQ=
|
||||
github.com/multiformats/go-multiaddr v0.9.0/go.mod h1:mI67Lb1EeTOYb8GQfL/7wpIZwc46ElrvzhYnoJOmTT0=
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A=
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk=
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E=
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
|
||||
github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
|
||||
github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
|
||||
github.com/multiformats/go-multicodec v0.8.1 h1:ycepHwavHafh3grIbR1jIXnKCsFm0fqsfEOsJ8NtKE8=
|
||||
github.com/multiformats/go-multicodec v0.8.1/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k=
|
||||
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
|
||||
github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108=
|
||||
github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc=
|
||||
github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo=
|
||||
github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q=
|
||||
github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
|
||||
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
|
||||
github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
|
||||
github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
|
||||
github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E=
|
||||
github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0=
|
||||
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
|
||||
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
|
||||
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U=
|
||||
github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E=
|
||||
github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
||||
github.com/quic-go/quic-go v0.33.0 h1:ItNoTDN/Fm/zBlq769lLJc8ECe9gYaW40veHCCco7y0=
|
||||
github.com/quic-go/quic-go v0.33.0/go.mod h1:YMuhaAV9/jIu0XclDXwZPAsP/2Kgr5yMYhe9oxhhOFA=
|
||||
github.com/quic-go/webtransport-go v0.5.2 h1:GA6Bl6oZY+g/flt00Pnu0XtivSD8vukOu3lYhJjnGEk=
|
||||
github.com/quic-go/webtransport-go v0.5.2/go.mod h1:OhmmgJIzTTqXK5xvtuX0oBpLV2GkLWNDA+UeTGJXErU=
|
||||
github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk=
|
||||
github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
||||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
||||
github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||
github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
|
||||
github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
|
||||
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
|
||||
github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
|
||||
github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
|
||||
github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
|
||||
github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
|
||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
||||
github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
|
||||
github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
|
||||
github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
|
||||
github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
|
||||
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
|
||||
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
|
||||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
||||
github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/dig v1.16.1 h1:+alNIBsl0qfY0j6epRubp/9obgtrObRAc5aD+6jbWY8=
|
||||
go.uber.org/dig v1.16.1/go.mod h1:557JTAUZT5bUK0SvCwikmLPPtdQhfvLYtO5tJgQSbnk=
|
||||
go.uber.org/fx v1.19.2 h1:SyFgYQFr1Wl0AYstE8vyYIzP4bFz2URrScjwC4cwUvY=
|
||||
go.uber.org/fx v1.19.2/go.mod h1:43G1VcqSzbIv77y00p1DRAsyZS8WdzuYdhZXmEUkMyQ=
|
||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
|
||||
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
|
||||
lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
|
||||
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
|
||||
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
@@ -0,0 +1,120 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
func main() {
|
||||
runServer := flag.Bool("run-server", false, "Should run as server")
|
||||
serverAddr := flag.String("server-address", "", "Server address")
|
||||
transport := flag.String("transport", "tcp", "Transport to use")
|
||||
uploadBytes := flag.Uint64("upload-bytes", 0, "Upload bytes")
|
||||
downloadBytes := flag.Uint64("download-bytes", 0, "Download bytes")
|
||||
flag.Parse()
|
||||
|
||||
host, port, err := net.SplitHostPort(*serverAddr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
tcpMultiAddrStr := fmt.Sprintf("/ip4/%s/tcp/%s", host, port)
|
||||
quicMultiAddrStr := fmt.Sprintf("/ip4/%s/udp/%s/quic-v1", host, port)
|
||||
|
||||
var opts []libp2p.Option
|
||||
if *runServer {
|
||||
opts = append(opts, libp2p.ListenAddrStrings(tcpMultiAddrStr, quicMultiAddrStr))
|
||||
|
||||
// Generate stable fake identity.
|
||||
//
|
||||
// Using a stable identity (i.e. peer ID) allows the client to
|
||||
// connect to the server without a prior exchange of the
|
||||
// server's peer ID.
|
||||
priv, _, err := crypto.GenerateEd25519Key(&simpleReader{seed: 0})
|
||||
if err != nil {
|
||||
log.Fatalf("failed to generate key: %s", err)
|
||||
}
|
||||
opts = append(opts, libp2p.Identity(priv))
|
||||
}
|
||||
|
||||
h, err := libp2p.New(opts...)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to instantiate libp2p: %s", err)
|
||||
}
|
||||
|
||||
perf := NewPerfService(h)
|
||||
if *runServer {
|
||||
for _, a := range h.Addrs() {
|
||||
fmt.Println(a.Encapsulate(multiaddr.StringCast("/p2p/" + h.ID().String())))
|
||||
}
|
||||
|
||||
select {} // run forever, exit on interrupt
|
||||
}
|
||||
|
||||
var multiAddrStr string
|
||||
switch *transport {
|
||||
case "tcp":
|
||||
multiAddrStr = tcpMultiAddrStr
|
||||
case "quic-v1":
|
||||
multiAddrStr = quicMultiAddrStr
|
||||
default:
|
||||
fmt.Println("Invalid transport. Accepted values: 'tcp' or 'quic-v1'")
|
||||
return
|
||||
}
|
||||
// Peer ID corresponds to the above fake identity.
|
||||
multiAddrStr = multiAddrStr + "/p2p/12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN"
|
||||
serverInfo, err := peer.AddrInfoFromString(multiAddrStr)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to build address info: %s", err)
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
err = h.Connect(context.Background(), *serverInfo)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to dial peer: %s", err)
|
||||
}
|
||||
|
||||
err = perf.RunPerf(context.Background(), serverInfo.ID, uint64(*uploadBytes), uint64(*downloadBytes))
|
||||
if err != nil {
|
||||
log.Fatalf("failed to execute perf: %s", err)
|
||||
}
|
||||
|
||||
jsonB, err := json.Marshal(Result{
|
||||
TimeSeconds: time.Since(start).Seconds(),
|
||||
UploadBytes: *uploadBytes,
|
||||
DownloadBytes: *downloadBytes,
|
||||
Type: "final",
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("failed to marshal perf result: %s", err)
|
||||
}
|
||||
|
||||
fmt.Println(string(jsonB))
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
Type string `json:"type"`
|
||||
TimeSeconds float64 `json:"timeSeconds"`
|
||||
UploadBytes uint64 `json:"uploadBytes"`
|
||||
DownloadBytes uint64 `json:"downloadBytes"`
|
||||
}
|
||||
|
||||
type simpleReader struct {
|
||||
seed uint8
|
||||
}
|
||||
|
||||
func (r *simpleReader) Read(p []byte) (n int, err error) {
|
||||
for i := range p {
|
||||
p[i] = r.seed
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
pool "github.com/libp2p/go-buffer-pool"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
|
||||
var log = logging.Logger("perf")
|
||||
|
||||
const (
|
||||
ID = "/perf/1.0.0"
|
||||
blockSize = 64 << 10
|
||||
)
|
||||
|
||||
type PerfService struct {
|
||||
Host host.Host
|
||||
}
|
||||
|
||||
func NewPerfService(h host.Host) *PerfService {
|
||||
ps := &PerfService{h}
|
||||
h.SetStreamHandler(ID, ps.PerfHandler)
|
||||
return ps
|
||||
}
|
||||
|
||||
func (ps *PerfService) PerfHandler(s network.Stream) {
|
||||
u64Buf := make([]byte, 8)
|
||||
if _, err := io.ReadFull(s, u64Buf); err != nil {
|
||||
log.Errorw("err", err)
|
||||
s.Reset()
|
||||
return
|
||||
}
|
||||
|
||||
bytesToSend := binary.BigEndian.Uint64(u64Buf)
|
||||
|
||||
if _, err := drainStream(s); err != nil {
|
||||
log.Errorw("err", err)
|
||||
s.Reset()
|
||||
return
|
||||
}
|
||||
|
||||
if err := sendBytes(s, bytesToSend); err != nil {
|
||||
log.Errorw("err", err)
|
||||
s.Reset()
|
||||
return
|
||||
}
|
||||
s.CloseWrite()
|
||||
}
|
||||
|
||||
func (ps *PerfService) RunPerf(ctx context.Context, p peer.ID, bytesToSend uint64, bytesToRecv uint64) error {
|
||||
s, err := ps.Host.NewStream(ctx, p, ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sizeBuf := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(sizeBuf, bytesToRecv)
|
||||
|
||||
_, err = s.Write(sizeBuf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := sendBytes(s, bytesToSend); err != nil {
|
||||
return err
|
||||
}
|
||||
s.CloseWrite()
|
||||
|
||||
recvd, err := drainStream(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if recvd != bytesToRecv {
|
||||
return fmt.Errorf("expected to recv %d bytes, got %d", bytesToRecv, recvd)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sendBytes(s io.Writer, bytesToSend uint64) error {
|
||||
buf := pool.Get(blockSize)
|
||||
defer pool.Put(buf)
|
||||
|
||||
lastReportTime := time.Now()
|
||||
lastReportWrite := uint64(0)
|
||||
|
||||
for bytesToSend > 0 {
|
||||
now := time.Now()
|
||||
if now.Sub(lastReportTime) >= time.Second {
|
||||
jsonB, err := json.Marshal(Result{
|
||||
TimeSeconds: now.Sub(lastReportTime).Seconds(),
|
||||
UploadBytes: lastReportWrite,
|
||||
Type: "intermediary",
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("failed to marshal perf result: %s", err)
|
||||
}
|
||||
fmt.Println(string(jsonB))
|
||||
|
||||
lastReportTime = now
|
||||
lastReportWrite = 0
|
||||
}
|
||||
|
||||
toSend := buf
|
||||
if bytesToSend < blockSize {
|
||||
toSend = buf[:bytesToSend]
|
||||
}
|
||||
|
||||
n, err := s.Write(toSend)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bytesToSend -= uint64(n)
|
||||
lastReportWrite += uint64(n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func drainStream(s io.Reader) (uint64, error) {
|
||||
var recvd int64
|
||||
recvd, err := io.Copy(io.Discard, &reportingReader{orig: s, LastReportTime: time.Now()})
|
||||
if err != nil && err != io.EOF {
|
||||
return uint64(recvd), err
|
||||
}
|
||||
return uint64(recvd), nil
|
||||
}
|
||||
|
||||
type reportingReader struct {
|
||||
orig io.Reader
|
||||
LastReportTime time.Time
|
||||
lastReportRead uint64
|
||||
}
|
||||
|
||||
var _ io.Reader = &reportingReader{}
|
||||
|
||||
func (r *reportingReader) Read(b []byte) (int, error) {
|
||||
n, err := r.orig.Read(b)
|
||||
r.lastReportRead += uint64(n)
|
||||
|
||||
now := time.Now()
|
||||
if now.Sub(r.LastReportTime) >= time.Second {
|
||||
result := Result{
|
||||
TimeSeconds: now.Sub(r.LastReportTime).Seconds(),
|
||||
Type: "intermediary",
|
||||
DownloadBytes: r.lastReportRead,
|
||||
}
|
||||
|
||||
jsonB, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to marshal perf result: %s", err)
|
||||
}
|
||||
fmt.Println(string(jsonB))
|
||||
|
||||
r.LastReportTime = now
|
||||
r.lastReportRead = 0
|
||||
}
|
||||
|
||||
return n, err
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
perf
|
||||
.cache
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user