266 Commits
Author SHA1 Message Date
Alejandro Cabeza Romero e7d9b15158 Merge remote-tracking branch 'upstream/master'
* upstream/master:
  chore: update the link to the interop dashboard [skip ci]
  chore: parameterise s3 build cache setup (#465)
  chore: Create funding.json
2024-09-12 18:51:12 +02:00
github-actions[bot] c164b24049 chore: update the link to the interop dashboard [skip ci] 2024-09-11 08:25:10 +00:00
Piotr GalarandAlex Potsides e5e32c7c0a chore: parameterise s3 build cache setup (#465)
* chore: parameterise s3 build cache setup

* Apply suggestions from code review

Co-authored-by: Alex Potsides <alex@achingbrain.net>

* fix: cache load/push

* chore: pass creds when reading cache

* fix: interact with aws only using the CLI

* Update transport-interop.yml

---------

Co-authored-by: Alex Potsides <alex@achingbrain.net>
2024-09-11 10:01:42 +02:00
Prithvi Shahi e509958ad9 chore: Create funding.json
Add funding.json for application to OP rPGF round 5
2024-09-05 13:49:25 -04:00
github-actions[bot] 40fde07559 chore: update the link to the interop dashboard [skip ci] 2024-08-23 20:52:39 +00:00
Álex 2748dde76a Merge pull request #2 from vacp2p/update/upstream
feat: update from upstream
2024-08-22 15:00:11 +02:00
github-actions[bot] 0289c3ce91 chore: update the link to the interop dashboard [skip ci] 2024-08-21 15:42:15 +02:00
github-actions[bot] 50b451ff28 chore: update the link to the interop dashboard [skip ci] 2024-08-19 23:12:58 +00:00
github-actions[bot]andgalargh 3123632877 chore: add go-libp2p@v0.36.0 to transport-interop (#440)
Co-authored-by: galargh <galargh@users.noreply.github.com>
2024-08-19 15:36:10 -07:00
github-actions[bot] c97dc62f62 chore: update the link to the interop dashboard [skip ci] 2024-06-12 00:38:54 +00:00
5210452aef chore: add go-libp2p@v0.34.0 to transport-interop (#363)
* chore: add go-libp2p@v0.34.0 to transport-interop

* Add webtransport back in

* chore: add go-libp2p@v0.35.0 to transport-interop

* Remove go-libp2p versions < 0.33

---------

Co-authored-by: galargh <galargh@users.noreply.github.com>
Co-authored-by: Marco Munizaga <marco@marcopolo.io>
Co-authored-by: Marco Munizaga <git@marcopolo.io>
2024-06-11 17:23:18 -07:00
github-actions[bot] 5055eba611 chore: update the link to the interop dashboard [skip ci] 2024-06-06 10:10:51 +00:00
Alex Potsides fb99e690a6 fix: add js tests to this repo (#365)
Trying to debug these tests in CI is incredibly difficult and since they depend on older versions of previously published modules, if something breaks due to a bug in released code it's very hard to fix it.

Instead follow the pattern in the perf tests and include the full test implementations here.
2024-06-06 10:53:35 +01:00
github-actions[bot] 711318402a chore: update the link to the interop dashboard [skip ci] 2024-05-23 01:15:30 +00:00
f25059fc3e chore: add js-libp2p@v1.3.0 to transport-interop (#359)
* chore: add js-libp2p@v1.3.0 to transport-interop

* chore: add js-libp2p@v1.4.0 to transport-interop

* chore: add js-libp2p@v1.5.0 to transport-interop

* chore: add js-libp2p@v1.6.0 to transport-interop

* Update js-libp2p versions

* Buster has openssl 1.1 still

* Filter only js v1.6 for debugging

* Try emitting only

* Print docker version

* Attempt to patch tests

* Undo changes in .github

* Buster not needed apparently

---------

Co-authored-by: galargh <galargh@users.noreply.github.com>
Co-authored-by: Marco Munizaga <git@marcopolo.io>
Co-authored-by: Marco Munizaga <marco@marcopolo.io>
2024-05-22 17:53:31 -07:00
github-actions[bot] a63d3dc0a6 chore: update the link to the interop dashboard [skip ci] 2024-05-22 05:57:52 +00:00
github-actions[bot] 7ce1a023ae chore: update the link to the interop dashboard [skip ci] 2024-05-16 03:35:04 +00:00
Marco Munizaga 7a24227e5e Prepare for breaking change in webtransport-go (#362) 2024-05-15 20:14:56 -07:00
github-actions[bot] 0f5736dae0 chore: update the link to the interop dashboard [skip ci] 2024-05-07 10:31:59 +00:00
Alex Potsides fd59ed70fa fix: handle multiple strings that look like they might be JSON (#361)
The test output can have occurrences of `{` that aren't the string we are looking for, eg:

```
dialer-1    | test browser
dialer-1    | [JavaScript Error: "Clear-Site-Data header found. Unknown value “"cache"”." {file: "http://127.0.0.1:34451/" line: 0}]
dialer-1    | [JavaScript Error: "Clear-Site-Data header forced the clean up of “cookies” data." {file: "http://127.0.0.1:34451/" line: 0}]
dialer-1    | [JavaScript Error: "Clear-Site-Data header forced the clean up of “storage” data." {file: "http://127.0.0.1:34451/" line: 0}]
```

These fail to parse so improve the results parsing by:

1. Try parsing every instance of `{...}` in the output, not just the first
2. Test the output for the `handshakePlusOneRTTMillis` and `pingRTTMilllis` keys
2024-05-07 11:10:40 +01:00
github-actions[bot] 0518ca618c chore: update the link to the interop dashboard [skip ci] 2024-03-26 17:34:13 +00:00
galargh a30678eb62 ci: fix testing newly added impl versions 2024-03-26 17:16:34 +00:00
Piotr Galar ed111cdc25 feat: add new implementation versions (go, js, rust) (#349)
* feat: add new implementation versions (go)

* ci: generalise adding new implementation versions

* ci: automate new version addition for rust-libp2p and js-libp2p
2024-03-26 17:13:03 +00:00
github-actions[bot] 9fd3f85733 chore: update the link to the interop dashboard [skip ci] 2024-02-23 15:26:42 +00:00
Sukun 5bfec5ffde chore: add go-libp2p v0.32 and v0.33 (#346) 2024-02-23 20:35:36 +05:30
github-actions[bot] f8d2c6f9c5 chore: update the link to the interop dashboard [skip ci] 2024-02-01 14:58:39 +00:00
GitHub cb3e7eb4e5 chore: Update .github/workflows/stale.yml [skip ci] 2024-01-31 16:48:37 +00:00
github-actions[bot] 27adf40262 chore: update the link to the interop dashboard [skip ci] 2024-01-25 19:59:20 +00:00
diegomrsantos 0e5bf85a1a chore(interop): update to nim 1.6.16 (#344) 2024-01-25 11:40:31 -08:00
github-actions[bot] dd2d5744ca chore: update the link to the interop dashboard [skip ci] 2024-01-25 01:13:05 +00:00
Thomas Eizinger eb6bf67d30 deps(transport-interop): add v0.53 release of rust-libp2p (#326) 2024-01-25 11:55:33 +11:00
github-actions[bot] b4384fb60b chore: update the link to the interop dashboard [skip ci] 2024-01-24 21:02:02 +00:00
Thomas Eizinger d1d9e18430 fix: update rust-v0.52 hash to fix build error (#342) 2024-01-25 07:47:42 +11:00
Max Inden 9e2ae17326 chore(perf): update to rust-libp2p v0.53.2 (#341)
Update `perf/impl/rust-libp2p/v0.53` to rust-libp2p `v0.53.2`. With this patch
release comes the rust-yamux stream receive window auto-tuning.

https://github.com/libp2p/rust-libp2p/pull/4970

https://github.com/libp2p/rust-libp2p/releases/tag/libp2p-v0.53.2
2023-12-30 20:39:05 +01:00
Max Inden 299aaeb8e4 Revert "chore(perf): update to rust-libp2p v0.53.2 (#339)" (#340)
This reverts commit 393b09a43f.
2023-12-19 18:37:15 +01:00
Max Inden 393b09a43f chore(perf): update to rust-libp2p v0.53.2 (#339)
Update `perf/impl/rust-libp2p/v0.53` to rust-libp2p `v0.53.2`. With this patch
release comes the rust-yamux stream receive window auto-tuning.

https://github.com/libp2p/rust-libp2p/pull/4970

https://github.com/libp2p/rust-libp2p/releases/tag/libp2p-v0.53.2
2023-12-19 22:37:54 +11:00
Alex Potsidesandachingbrain 7fab93f625 fix: update js-libp2p perf to include v1 release (#336)
Update deps to non-next versions.

---------

Co-authored-by: achingbrain <achingbrain@users.noreply.github.com>
2023-12-04 13:30:59 +00:00
github-actions[bot] fa34779b3d chore: update the link to the interop dashboard [skip ci] 2023-12-01 09:30:54 +00:00
Alex Potsidesandachingbrain 9a4c969523 fix: re-enable js-libp2p under node.js (#325)
Adds perf tests for js-libp2p 0.46.x and 1.0 (via the `next` tag).

---------

Co-authored-by: achingbrain <achingbrain@users.noreply.github.com>
2023-11-21 08:22:56 +00:00
Thomas Eizinger 7ca92e80ab feat(hole-punch/rust): use v0.53 release (#327) 2023-11-16 15:56:41 +01:00
github-actions[bot] a87f0ad998 chore: update the link to the interop dashboard [skip ci] 2023-11-15 07:56:48 +00:00
Chad Nehemiah b9aa2a53ca feat: re-introduce webRTC tests (#310) 2023-11-15 18:42:53 +11:00
github-actions[bot] faf6368b2a chore: update the link to the interop dashboard [skip ci] 2023-11-14 19:51:59 +00:00
Chad Nehemiah 6d4c701f27 chore(transport-interop): add js-libp2p v0.46.21 (#305)
Also upgrade the dependencies
2023-11-14 19:34:52 +00:00
github-actions[bot] 0f80795440 chore: update the link to the interop dashboard [skip ci] 2023-11-08 14:48:08 +00:00
kevodwyer 189496f182 feat(interop): add java-v0.6 (#323) 2023-11-08 15:33:43 +01:00
Thomas Eizinger eb21984300 feat(hole-punch): update rust v0.52 to master (#317) 2023-10-27 17:09:28 +11:00
diegomrsantosandThomas Eizinger 5332a26264 fix(hole-punch): Add support for arm64 architecture (#311)
Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
2023-10-26 16:28:40 +11:00
Max Inden 0a8dbab87c feat(perf): continuosly measure on single conn (iperf-style) (#276)
Our current throughput tests open a connection, open a stream,
up- or download 100MB and close the connection. 100 MB is not enough on the
given path (60ms, ~5gbit/s) to exit congestion controller's slow-start. See
https://github.com/libp2p/test-plans/issues/261 for details.

Instead of downloading 100MB multiple times, each on a new connection, establish
a single connection and continuously measure the throughput for a fixed
duration (20s).
2023-10-25 13:24:08 +02:00
Thomas Eizinger 9247c9fd99 Fix flaky QUIC hole-punching tests (#314) 2023-10-25 13:23:34 +11:00
github-actions[bot] 261c1978ec chore: update the link to the interop dashboard [skip ci] 2023-10-24 09:24:37 +00:00
Thomas Eizinger b59ed7498c feat(rust-libp2p): update to latest v0.52 patch release (#313) 2023-10-24 10:43:09 +02:00
Thomas Eizinger 1e37b93e93 feat(hole-punch): add hole-punch interoperability test suite (#304) 2023-10-17 10:07:25 +11:00
github-actions[bot] 4ed47fec42 chore: update the link to the interop dashboard [skip ci] 2023-10-05 03:26:17 +00:00
Thomas Eizinger 6ab15df0ec Rename multidim-interop to transport-interop (#308) 2023-10-05 14:12:39 +11:00
github-actions[bot] fbe8eb620f chore: update the link to the interop dashboard [skip ci] 2023-09-14 21:06:35 +00:00
Thomas Eizinger d9a5c388ad fix: make rust-chromium a separate implementation (#302) 2023-09-15 06:57:15 +10:00
Chad Nehemiah a96d930eb4 fix(perf): re-introduce js-libp2p + add encryption (#299) 2023-09-14 18:49:46 +02:00
github-actions[bot] b8235c9eae chore: update the link to the interop dashboard [skip ci] 2023-09-07 16:32:17 +00:00
Chad Nehemiah 43b67ccdba fix(multidim): make js-libp2p builds reproducible (#288) 2023-09-07 09:03:09 -07:00
github-actions[bot] 2218a12457 chore: update the link to the interop dashboard [skip ci] 2023-09-07 06:17:38 +00:00
Prithvi Shahi fa6dc4c724 chore(multidim-interop): add go v0.31 (#289) 2023-09-06 22:41:34 -07:00
Piotr Galar 0b4e5e490d feat(.github/perf): reference metrics dashboard (#297) 2023-09-04 17:57:22 +02:00
github-actions[bot]galarghgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
09d15c0e8b chore: add go-libp2p@v0.31.0 to perf/impl/go-libp2p (#295)
* chore: add go-libp2p@v0.31.0 to perf/impl/go-libp2p

* perf: update benchmark results

---------

Co-authored-by: galargh <galargh@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-09-04 11:28:35 +02:00
Piotr Galar 353e2db77c fix: how new go-libp2p versions are added to perf (#294) 2023-09-04 09:40:32 +02:00
Piotr Galar 2980863ebc feat: automate adding new go-libp2p versions to perf (#256)
* feat: automate adding new go-libp2p versions to perf

* fix: put add-new-impl-versions.yml on schedule
2023-09-02 10:16:35 +02:00
Max Inden 73dba1a5bc feat(perf/rust-libp2p): upgrade to v0.52.3 and remove master (#290)
- Upgrade rust-libp2p `v0.52` implementation to rust-libp2p `v0.52.3`.
- Remove rust-libp2p `master` implementation. Given that `v0.52.3` contains the
  stable QUIC implementation, there is no more need for `master`.
2023-09-01 19:59:53 +02:00
Chad NehemiahandMax Inden fbb92b75b2 fix(perf): adjust cli flags for perf runner for testing purposes (#275)
Co-authored-by: Max Inden <mail@max-inden.de>
2023-09-01 19:59:30 +02:00
Max Inden a68c19699e Revert "feat(perf): add js-libp2p NodeJS (#244)" (#292)
This reverts commit c39bfb9b32.

Reverting due to https://github.com/libp2p/test-plans/issues/291. Can revert
revert once resolved.
2023-09-01 19:58:31 +02:00
Max Inden fd1889fedb feat(perf): use m5.xlarge (#284)
Instead of `m5n.8xlarge`, use `m5.xlarge`.

Rational:
- Closer to real-world libp2p deployments (e.g. < 25 Gibps)
- Cheaper (~2 USD vs ~0.2 USD)

m5n.8xlarge:
- 32 vCPUs
- 128.0 GiB of memory
- 25 Gibps of bandwidth - 2019

m5.xlarge
- 4 vCPUs
- 16.0 GiB of memory
- up to 10 Gibps of bandwidth
2023-09-01 19:55:45 +02:00
github-actions[bot] f1ac9bfd12 chore: update the link to the interop dashboard [skip ci] 2023-08-31 16:10:50 +00:00
github-actions[bot] 483c19ca2c chore: update the link to the interop dashboard [skip ci] 2023-08-30 19:36:28 +00:00
github-actions[bot] 24f1cca2ce chore: update the link to the interop dashboard [skip ci] 2023-08-26 05:12:12 +00:00
Marten SeemannandMax Inden 7d6f24afe6 interop: fix description on how to run locally (#278)
* interop: fix description on how to run locally

1. js-libp2p uses a Makefile
2. The listener should be started first, then the dialer

* Update multidim-interop/README.md

Co-authored-by: Max Inden <mail@max-inden.de>

---------

Co-authored-by: Max Inden <mail@max-inden.de>
2023-08-25 21:42:50 -07:00
Prithvi Shahi 20b73dd172 chore: add perf to readme (#271) 2023-08-25 07:47:09 -07:00
Chad NehemiahandMax Inden c39bfb9b32 feat(perf): add js-libp2p NodeJS (#244)
Co-authored-by: Max Inden <mail@max-inden.de>
2023-08-25 11:09:01 +02:00
Max Inden d1ff642e9b fix(perf): remove obsolete quinn build infra (#274)
Implementation has been removed with https://github.com/libp2p/test-plans/pull/246.
2023-08-24 15:08:23 +02:00
github-actions[bot] 8bf6d03752 chore: update the link to the interop dashboard [skip ci] 2023-08-24 08:24:59 +00:00
Max Inden 54fe78c332 fix(interop/rust/wasm): bump version to use chrome 115 (#273)
Bump rust-libp2p v0.52 interop version to include
https://github.com/libp2p/rust-libp2p/pull/4383 which fixes issue in
https://github.com/libp2p/go-libp2p/pull/2506.
2023-08-24 09:49:23 +02:00
Chad Nehemiah eebc07b1b4 docs(perf): Added new CLI flags for iterations + updated docs (#258) 2023-08-23 23:19:11 -07:00
github-actions[bot] 947ad8abbd chore: update the link to the interop dashboard [skip ci] 2023-08-23 18:18:51 +00:00
Prithvi Shahi 055eb0745d chore: add go-libp2p v0.30 and remove v0.27 and v0.28 (#269)
* chore: add go-libp2p v0.30 and remove v0.27 and v0.28

* remove quic and mplex in v0.30
2023-08-23 10:37:12 -07:00
Prithvi Shahi 7d5710dbdb ci: only run interop tests on changes to multidim-interop dir (#272) 2023-08-23 07:31:11 -07:00
Prithvi Shahi 2a4e313301 ci: only run interop tests on changes to multidim-interop dir (#270) 2023-08-22 08:52:59 +02:00
github-actions[bot] 03f5d99262 chore: update the link to the interop dashboard [skip ci] 2023-08-21 09:06:06 +00:00
Max Inden 826444d867 fix(perf): install nvm for ec2-user instead of root (#267)
On root the nvm install script can not find a shell config.

```
=> Profile not found. Tried ~/.bashrc, ~/.bash_profile, ~/.zprofile, ~/.zshrc, and ~/.profile.
```
2023-08-21 10:22:39 +02:00
github-actions[bot] 6fae3e5843 chore: update the link to the interop dashboard [skip ci] 2023-08-18 16:32:12 +00:00
github-actions[bot] 742d6c80bf chore: update the link to the interop dashboard [skip ci] 2023-08-18 16:03:38 +00:00
Marco Munizaga 0e29408daa Disable browser webrtc tests (#265) 2023-08-18 08:25:43 -07:00
github-actions[bot] 4507e91ef1 chore: update the link to the interop dashboard [skip ci] 2023-08-18 12:52:39 +00:00
Max Inden f57408de37 chore(perf): install NodeJS LTS on VMs (#266)
Needed for js-libp2p perf implementation.

https://github.com/libp2p/test-plans/pull/244/
2023-08-18 14:23:06 +02:00
github-actions[bot] 9caabc8d0d chore: update the link to the interop dashboard [skip ci] 2023-08-17 13:54:54 +00:00
github-actions[bot] 0ea4725525 chore: update the link to the interop dashboard [skip ci] 2023-08-17 13:40:35 +00:00
Max Inden e5b7e0e16e fix(perf): use $Default launch template (#257)
Our perf terraform setup differentiates in long lived and short lived resources.
On CI, our long lived resources are spun up once and our short lived resources
are spun up on each CI run. From time to time we have to adjust the long lived
resources. End result is a new launch template that needs to be referenced in
the short lived resources by version.

Next to our CI, the perf terraform setup can as well be used on personal AWS
accounts. Their long lived launch template version likely doesn't match the
configured launch template version of the short lived aws_instance.

Instead of specifying a specific version, instruct terraform to use the default,
thus supporting both our CI and personal AWS account use-case.
2023-08-17 15:02:23 +02:00
github-actions[bot] c763d1fdce chore: update the link to the interop dashboard [skip ci] 2023-08-17 12:12:06 +00:00
github-actions[bot] 142557b9eb chore: update the link to the interop dashboard [skip ci] 2023-08-14 14:37:06 +00:00
Max Inden 8e2c837599 fix(perf): increase maximum udp send buffer size (#254)
Previously only the maximum udp **receive** buffer size was increased to
`2500000` bytes. With this commit both the send and the receive buffer size is increase.
2023-08-14 16:08:41 +02:00
github-actions[bot] 6c964a96eb chore: update the link to the interop dashboard [skip ci] 2023-08-11 23:09:16 +00:00
github-actions[bot] 07be41335b chore: update the link to the interop dashboard [skip ci] 2023-08-11 19:44:54 +00:00
Prithvi Shahi da62ebc979 chore: rm rust-libp2p v0.49 and v0.50, update v0.52 (#253) 2023-08-11 12:17:07 -07:00
github-actions[bot] 28567c70da chore: update the link to the interop dashboard [skip ci] 2023-08-11 18:02:30 +00:00
Prithvi Shahi 55e43bd610 chore: update go-libp2p releases and rm v0.25 & v0.26 (#252) 2023-08-11 10:33:33 -07:00
github-actions[bot] e0b459639a chore: update the link to the interop dashboard [skip ci] 2023-08-10 03:31:22 +00:00
Prithvi Shahi b0b8ad8a62 chore: add js-libp2p v0.46.x, rm v0.44, rm v0.45 browser tests (#251) 2023-08-09 20:04:43 -07:00
github-actions[bot] da5d3f4924 chore: update the link to the interop dashboard [skip ci] 2023-08-09 23:58:35 +00:00
github-actions[bot] a674f734cc chore: update the link to the interop dashboard [skip ci] 2023-08-04 17:17:09 +00:00
Max Inden ad43602e63 fix(perf): increase root volume size (#249)
Multiple perf runs have failed due to "no space left on device". See e.g. https://github.com/libp2p/test-plans/actions/runs/5727165977/job/15527780097.

The perf terraform launch template previously did not specify a root volume
size. Thus terraform used the default:

```
df -h

Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        4.0M     0  4.0M   0% /dev
tmpfs            63G     0   63G   0% /dev/shm
tmpfs            25G  540K   25G   1% /run
/dev/nvme0n1p1  8.0G  1.9G  6.1G  24% /
tmpfs            63G     0   63G   0% /tmp
tmpfs            13G     0   13G   0% /run/user/1000
```

With this commit the root volume is increased to 100GB:

```
df -h

Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        4.0M     0  4.0M   0% /dev
tmpfs            63G     0   63G   0% /dev/shm
tmpfs            25G  564K   25G   1% /run
/dev/nvme0n1p1  100G  2.6G   98G   3% /
tmpfs            63G  8.0K   63G   1% /tmp
tmpfs            13G     0   13G   0% /run/user/0
tmpfs            13G     0   13G   0% /run/user/1000
```
2023-08-04 18:50:32 +02:00
github-actions[bot] b31b44fbde chore: update the link to the interop dashboard [skip ci] 2023-08-04 08:49:48 +00:00
Max Inden cfd1049e8a fix(perf): run iperf on TCP and set TCP windows to bdp (#241)
This commit makes iperf use TCP instead of UDP. Using UDP allows the sender to
send as much data as they can, not as much data as the receiver can handle.
Using TCP measures the actual bandwidth of the connection.

This commit sets the TCP send and receive window to the bandwidth-delay-product.
In order to exhaust the whole bandwidth between the two nodes, TCP needs to be
able to buffer all bytes on the wire in the case of packet loss.
2023-08-04 10:23:47 +02:00
github-actions[bot] e8c0733ce5 chore: update the link to the interop dashboard [skip ci] 2023-08-01 15:06:26 +00:00
Max Inden ffc7ae0d5f fix(perf): replace rust-libp2p-quinn/ with rust-libp2p/master (#246)
With https://github.com/libp2p/rust-libp2p/pull/3454 merged we can now test the
new rust-libp2p QUIC implementation based on upstream quinn directly from
rust-libp2p `master`.

This commit does the following in libp2p/test-plans:

1. Remove the `perf/impl/rust-libp2p-quinn` implementation.
2. Introduce the `perf/impl/rust-libp2p/master` version of the rust-libp2p implementation.

We can promote the latter to a proper version on the next rust-libp2p release.
2023-08-01 16:40:02 +02:00
github-actions[bot] 003ac2c02d chore: update the link to the interop dashboard [skip ci] 2023-08-01 01:14:15 +00:00
github-actions[bot] d8913edb57 chore: update the link to the interop dashboard [skip ci] 2023-07-26 17:08:44 +00:00
Max Inden 3d9be81c9a docs(perf): document how to add a new version of existing impl (#243) 2023-07-26 18:41:49 +02:00
github-actions[bot] 66a596ce53 chore: update the link to the interop dashboard [skip ci] 2023-07-26 12:27:58 +00:00
Max Inden 35eb403b2d feat(perf): add go-libp2p v0.29 (#242) 2023-07-26 14:01:46 +02:00
github-actions[bot] f0437a8ec2 chore: update the link to the interop dashboard [skip ci] 2023-07-20 06:21:22 +00:00
Alex Potsides 5c74bfec3d feat: expose name-ignore setting (#239)
Exposes `--name-ignore` as `test-ignore` in the ping test github action to be consistent with how `--name-filter` is exposed as `test-filter`

Follows on from #225
2023-07-20 06:54:46 +01:00
github-actions[bot] 5a337a4b64 chore: update the link to the interop dashboard [skip ci] 2023-07-19 17:09:51 +00:00
github-actions[bot] 0b2fa59a56 chore: update the link to the interop dashboard [skip ci] 2023-07-19 17:06:16 +00:00
Steve Loeppky 7e074ba39a Update README.md - fix link to libp2p observable (#238) 2023-07-19 09:38:18 -07:00
Marco Munizaga 8834ac1555 Add go-libp2p v0.29.0 (#234) 2023-07-19 09:37:06 -07:00
github-actions[bot] 3132bf12b3 chore: update the link to the interop dashboard [skip ci] 2023-07-14 21:28:51 +00:00
Marco Munizaga 1ebb8b505c multidim-interop: Prune older versions (#233)
* Remove older versions

* Remove older chromium versions
2023-07-14 14:01:52 -07:00
github-actions[bot] 1191bb5f13 chore: update the link to the interop dashboard [skip ci] 2023-07-14 19:32:58 +00:00
Marco Munizaga 4bd0f9992f Revert "Install playwright in the base image so it is cached (#226)" (#231)
* Revert "Install playwright in the base image so it is cached (#226)"

This reverts commit d21d042ddd.

* Add comment
2023-07-14 11:48:08 -07:00
github-actions[bot] e69e155fe9 chore: update the link to the interop dashboard [skip ci] 2023-07-14 17:46:59 +00:00
Marco Munizaga cbca2c06de multidim-interop: Update rust-libp2p .gitignore with chromium-image.json (#232)
* .gitignore chromium-image.json

* Assert that git tree is clean
2023-07-14 10:00:35 -07:00
github-actions[bot] 00170f36e3 chore: update the link to the interop dashboard [skip ci] 2023-07-13 20:01:43 +00:00
Marco Munizaga fff587f66f More resilient stdout parsing of dialer stdout (#224)
* More resilient stdout parsing of dialer stdout

* Add another test case

* Handle JS cases where timings aren't the only thing on stdout
2023-07-13 12:14:43 -07:00
github-actions[bot] f954fd8522 chore: update the link to the interop dashboard [skip ci] 2023-07-11 00:35:27 +00:00
Marco MunizagaandThomas Eizinger 81e78aed34 multidim-interop: Add name ignore option (#225)
* Add name ignore option

* Update multidim-interop/testplans.ts

Co-authored-by: Thomas Eizinger <thomas@eizinger.io>

---------

Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
2023-07-10 16:49:46 -07:00
github-actions[bot] ba8169f189 chore: update the link to the interop dashboard [skip ci] 2023-07-10 03:52:51 +00:00
Max Inden d7391f13e1 fix(perf): increase iterations (#213)
- Increase upload/download benchmark iterations. Still conservative value of `10` due to slow rust-libp2p tcp. See https://github.com/libp2p/rust-yamux/issues/162. Note however that this is 10x an upload of 100MB.
- Increase latency benchmark iterations.
2023-07-10 05:06:51 +02:00
github-actions[bot] 289e90b80a chore: update the link to the interop dashboard [skip ci] 2023-07-08 05:01:33 +00:00
Marco Munizaga d21d042ddd Install playwright in the base image so it is cached (#226) 2023-07-07 21:15:16 -07:00
github-actions[bot] 81b339dd70 chore: update the link to the interop dashboard [skip ci] 2023-07-07 23:25:17 +00:00
35ab35b1a4 feat: run multidim-interop.yml on self-hosted runners (#154)
* feat: run multidim-interop.yml on self-hosted runners

* feat: make worker count configurable

* feat: enable docker.io proxy on self-hosted runners

* chore: provide s3 creds through env

* Try 4 workers

* ci: run-multidim-interop on 16 workers

* chore: change self hosted labels

* Update .github/workflows/multidim-interop.yml

Co-authored-by: Piotr Galar <piotr.galar@gmail.com>

* Use self-hosted runners for now

This reverts commit 7e868ea6b486798c03ad5b88f14c1a78e51e7c26.

---------

Co-authored-by: Marco Munizaga <git@marcopolo.io>
Co-authored-by: Marco Munizaga <marco@marcopolo.io>
2023-07-07 15:41:38 -07:00
github-actions[bot] 22c7e58513 chore: update the link to the interop dashboard [skip ci] 2023-07-07 13:07:57 +00:00
Max Inden ce83afc1b0 feat(interop): add rust-libp2p chromium WASM WebTransport (#217)
Introduced in rust-libp2p with https://github.com/libp2p/rust-libp2p/pull/4015.
2023-07-07 14:37:57 +02:00
465065cff8 fix(interop): use standaloneTransports as string instead of param (#219)
* fix(interop): use standaloneTransports as string instead of param

When generating the test specification (docker-compose file) we enumerate all
transport permutations. While some of our transports need to be upgraded (e.g.
TCP and WS) some don't (e.g. QUIC or WebRTC). To differentiate the two we
execute two SQL queries (`queryResults` and `standaloneTransportsQueryResults`),
each with either a `AND _ NOT IN` or `AND _ IN`.

The previous implementation would use `node-sqlite3` query parameters (see
https://github.com/TryGhost/node-sqlite3/wiki/API#runsql--param---callback) to
provide the list of transport protocols that don't need upgrading as an array.

The problem is that `node-sqlite3` does not support arrays as query parameters,
see https://github.com/TryGhost/node-sqlite3/issues/762.

This commit uses string interpolation instead to inject the list of standalone
transports into the SQL queries.

* Nit

---------

Co-authored-by: Marco Munizaga <git@marcopolo.io>
Co-authored-by: Marco Munizaga <marco@marcopolo.io>
2023-07-05 16:57:30 -07:00
Marco Munizaga ec32d36cab Add debug logging if JSON parse fails (#223) 2023-07-05 18:59:03 +00:00
github-actions[bot] 9277cff3bd chore: update the link to the interop dashboard [skip ci] 2023-07-05 06:34:30 +00:00
github-actions[bot] bd57868279 chore: update the link to the interop dashboard [skip ci] 2023-07-05 05:07:51 +00:00
Max Inden acea8b5e0c fix(perf): increase MAX_AGE_MINUTES to 120 (#215)
- When experimenting with increasing iterations, instances are taken down
prematurely. See e.g. https://github.com/libp2p/test-plans/actions/runs/5418669631/jobs/9850992882

- When benchmarking from a local developer machine, experimenting for longer is useful.

- The AWS Lambda is only a safety net machanism. In the rare case where we
miss to clean up, running the machines for <1h or 2h doesn't matter cost wise.
2023-07-05 07:06:39 +02:00
Piotr Galar 1b187a379c chore: move perf cleanup test code to a test directory (#216) 2023-07-05 05:46:58 +02:00
github-actions[bot] 4fd3b087d1 chore: update the link to the interop dashboard [skip ci] 2023-06-30 20:32:36 +00:00
github-actions[bot] ed962f61bb chore: update the link to the interop dashboard [skip ci] 2023-06-30 20:23:31 +00:00
Marco Munizaga a4e5381432 Remove often wrong patch version from id (#211) 2023-06-30 12:11:10 -07:00
github-actions[bot] 6fecac3b91 chore: update the link to the interop dashboard [skip ci] 2023-06-30 03:59:56 +00:00
Max Inden 0df7762587 chore(perf): document GitHub action usage (#212) 2023-06-30 04:25:05 +02:00
github-actions[bot] 7c43c940ce chore: update the link to the interop dashboard [skip ci] 2023-06-29 23:33:52 +00:00
Marco Munizaga 95f1277fed Squash queries down to just 2 (#210) 2023-06-29 15:16:32 -07:00
github-actions[bot] 7268d72a65 chore: update the link to the interop dashboard [skip ci] 2023-06-29 21:04:08 +00:00
Marco Munizaga fd719f534e Less error-prone way of defining image IDs and other quality of life improvements (#208)
* Make canonicalImageIDLookup default

* Fix browser containerImageID
2023-06-29 12:52:13 -07:00
GitHub 42179a6721 chore: Update .github/workflows/stale.yml [skip ci] 2023-06-28 08:54:37 +00:00
github-actions[bot] 79c94da915 chore: update the link to the interop dashboard [skip ci] 2023-06-27 02:45:59 +00:00
Max Inden 67960902e8 feat(perf/go-libp2p): add v0.28.1 (#209) 2023-06-27 03:24:19 +02:00
github-actions[bot] d18494ea9a chore: update the link to the interop dashboard [skip ci] 2023-06-26 10:07:28 +00:00
github-actions[bot] 4ba32fe7db chore: update the link to the interop dashboard [skip ci] 2023-06-26 09:49:53 +00:00
Max Inden cdf7820037 refactor(perf): expose single latency measurement (#207) 2023-06-26 10:35:44 +02:00
Max IndenandMarco Munizaga 81b6e7c370 feat(interop): add rust-libp2p v0.52 (#206)
See https://github.com/libp2p/rust-libp2p/releases/tag/libp2p-v0.52.0

Co-authored-by: Marco Munizaga <git@marcopolo.io>
2023-06-26 10:33:06 +02:00
github-actions[bot] 3b8e62b74b chore: update the link to the interop dashboard [skip ci] 2023-06-23 03:06:48 +00:00
Max Inden b1cfea4f52 fix(perf/go-libp2p): close write after sending in client (#205)
Follow up to https://github.com/libp2p/test-plans/pull/184.
2023-06-23 03:43:06 +02:00
github-actions[bot] 19d5ac0619 chore: update the link to the interop dashboard [skip ci] 2023-06-22 13:55:01 +00:00
github-actions[bot] f27d0445e6 chore: update the link to the interop dashboard [skip ci] 2023-06-22 13:14:05 +00:00
Max Inden 2ddea6a139 fix(perf/https): request downloadBytes instead of uploadBytes (#203) 2023-06-22 14:49:42 +02:00
53ff8b5db1 feat(perf): add (automation, provision, build, run) tooling (#184)
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/@mxinden-workspace/libp2p-performance-dashboard.

Co-authored-by: Marco Munizaga <git@marcopolo.io>
Co-authored-by: Marten Seemann <martenseemann@gmail.com>
Co-authored-by: Piotr Galar <piotr.galar@gmail.com>
2023-06-22 13:54:09 +02:00
github-actions[bot] 3c7d726d4a chore: update the link to the interop dashboard [skip ci] 2023-06-20 19:01:51 +00:00
Marco Munizaga af82e8fc5f Rename build-without-cache to build-without-secrets (#199)
This workflow uses the public cache. It just can't update it. The goal of this workflow is to see how public forks behave. The name is a vestige from when we didn't have a public cache. But the original goal was always to see how public forks and external repos would behave.
2023-06-20 10:55:43 -07:00
github-actions[bot] 6e0b215ce4 chore: update the link to the interop dashboard [skip ci] 2023-06-20 13:26:45 +00:00
kevodwyer 248cf9962c fix(java-libp2p): update test client with resource fix (#200) 2023-06-20 14:20:17 +02:00
github-actions[bot] 9af8b511b1 chore: update the link to the interop dashboard [skip ci] 2023-06-16 22:35:20 +00:00
kevodwyer 112e2efe20 add Java to interop tests (#197)
* add Nabu (Java) to interop tests

* naming fix

* missed a reference

* update build commit

* update build commit

* update git hash

* add to gitignore
2023-06-16 14:14:47 -07:00
GitHub df7c9d711c chore: Update .github/workflows/stale.yml [skip ci] 2023-06-14 09:03:57 +00:00
github-actions[bot] b446a9f9ad chore: update the link to the interop dashboard [skip ci] 2023-06-13 22:50:41 +00:00
Marten Seemann b0d365365b chore: remove Go version badge from readme (#194) 2023-06-13 14:47:07 -07:00
github-actions[bot] 88bf66afd3 chore: update the link to the interop dashboard [skip ci] 2023-06-13 21:44:27 +00:00
github-actions[bot] 4e5c9e99a6 chore: update the link to the interop dashboard [skip ci] 2023-06-13 19:35:54 +00:00
Prithvi Shahi f828ee216b chore: add go-libp2p 0.28.0 and update to v0.27.6 (#192) 2023-06-13 11:33:32 -07:00
github-actions[bot] 0143634927 chore: update the link to the interop dashboard [skip ci] 2023-06-08 22:51:12 +00:00
Marco Munizaga 06a82c0d95 Reintroduce js-libp2p v0.45.0 and fix build from cache (#189)
* Add js-libp2p v0.45.0

* Name the image before creating browser images

* Update commit sha to test webrtc

* Enable webrtc & webrtc-direct tests
2023-06-08 14:56:17 -07:00
github-actions[bot] ba3f8cfc20 chore: update the link to the interop dashboard [skip ci] 2023-06-03 02:16:29 +00:00
Marco Munizaga fb9bb6a690 Don't include muxer and secure channel for webrtc (#190)
* Don't include muxer and secure channel for webrtc

* Also filter out webrtc
2023-06-02 18:34:28 -07:00
github-actions[bot] 6d55e6995c chore: update the link to the interop dashboard [skip ci] 2023-06-02 17:13:47 +00:00
Marco Munizaga 22f37a0e93 Revert "Add js-libp2p v0.45.0 (#187)" (#188)
This reverts commit e9f4962362.
2023-06-02 09:21:20 -07:00
github-actions[bot] bd3d138c7c chore: update the link to the interop dashboard [skip ci] 2023-06-02 15:51:15 +00:00
Marco Munizaga e9f4962362 Add js-libp2p v0.45.0 (#187) 2023-06-02 08:43:54 -07:00
github-actions[bot] 4a35532808 chore: update the link to the interop dashboard [skip ci] 2023-05-19 20:33:53 +00:00
Chad Nehemiah 633ff35ba4 docs: update readme for instructions on running locally (#182)
* docs: update readme for instructions on running locally

* docs: update readme for instructions on running locally

* docs: pr feedback
2023-05-19 12:39:08 -07:00
github-actions[bot] 92bf5c4ca5 chore: update the link to the interop dashboard [skip ci] 2023-05-16 18:31:08 +00:00
github-actions[bot] 4f53d80b8d chore: update the link to the interop dashboard [skip ci] 2023-05-16 16:19:59 +00:00
Thomas Eizinger f1acc202eb Update Rust tests to use smaller docker container (#181) 2023-05-16 08:01:28 -07:00
github-actions[bot] b2504be8cb chore: update the link to the interop dashboard [skip ci] 2023-05-05 07:34:02 +00:00
Max Inden a2235a0d55 feat(interop): add js-libp2p v0.44 (#171)
Copy of `multidim-interop/impl/js/v0.42` plus version adjustments + reenable
WebRTC (see https://github.com/libp2p/test-plans/pull/160).
2023-05-05 08:44:42 +02:00
github-actions[bot] ec279581b8 chore: update the link to the interop dashboard [skip ci] 2023-05-04 22:46:55 +00:00
Prithvi Shahi a1edfe231e chore: Add go-libp2p v0.27.1 and v0.26.4, update zig-libp2p (#177)
* chore: Add go-libp2p v0.27.1 and v0.26.4

* update zig
2023-05-04 15:10:16 -07:00
github-actions[bot] f54b5d45bd chore: update the link to the interop dashboard [skip ci] 2023-05-03 18:48:48 +00:00
Marco Munizaga 103b2a3847 Update zig-libp2p to latest head to fix a flaky segfault (#175) 2023-05-03 11:20:49 -07:00
github-actions[bot] 70f2c0210f chore: update the link to the interop dashboard [skip ci] 2023-05-01 21:13:44 +00:00
Marco Munizaga df742523d4 Bring back zig-libp2p (#174)
* Revert "Revert "Bring back zig-libp2p (#172)" (#173)"

This reverts commit e4e9f985f7.

* Update zig-libp2p
2023-05-01 13:46:27 -07:00
github-actions[bot] 48400e3208 chore: update the link to the interop dashboard [skip ci] 2023-05-01 17:48:49 +00:00
Marco Munizaga e4e9f985f7 Revert "Bring back zig-libp2p (#172)" (#173)
This reverts commit f0c82d3d81.
2023-05-01 10:22:25 -07:00
github-actions[bot] 24891a7aa2 chore: update the link to the interop dashboard [skip ci] 2023-05-01 17:15:45 +00:00
github-actions[bot] bdd0a9a147 chore: update the link to the interop dashboard [skip ci] 2023-05-01 16:40:21 +00:00
Marco Munizaga f0c82d3d81 Bring back zig-libp2p (#172)
* Revert "Revert "Add zig-libp2p to interop tester (#167)" (#170)"

This reverts commit 3856de32fc.

* Print CPU info during make of zig-libp2p

* Show stdout output

* Use image id from json file

* Update zig-libp2p to log why a connection was shutdown

* Update zig to play nice with rust mss
2023-05-01 09:04:44 -07:00
github-actions[bot] d17c40e4e8 chore: update the link to the interop dashboard [skip ci] 2023-04-20 07:04:17 +00:00
Marco Munizaga 3856de32fc Revert "Add zig-libp2p to interop tester (#167)" (#170) 2023-04-20 08:33:21 +02:00
github-actions[bot] 3c1b605883 chore: update the link to the interop dashboard [skip ci] 2023-04-19 12:26:04 +00:00
Max Inden e07ffabbe8 fix(interop): rename webrtc to webrtc-direct (#166)
See https://github.com/multiformats/multiaddr/pull/150#issuecomment-1468791586
for context on discussion.

- Renames the `webrtc` transport identifier to `webrtc-direct`.
- Re-enables `webrtc-direct` support for rust-libp2p v0.51. Previously disabled
  in https://github.com/libp2p/test-plans/pull/160. See
  https://github.com/libp2p/rust-libp2p/pull/3781 for corresponding change on
  the rust-libp2p side.
- Leaves JS v0.41 and v0.42 untouched. To be done in a follow-up alongside JS
  dependency updates.
2023-04-19 13:48:07 +02:00
github-actions[bot] b80483a3f3 chore: update the link to the interop dashboard [skip ci] 2023-04-15 16:11:32 +00:00
Marco Munizaga d61600ccd2 Add zig-libp2p to interop tester (#167)
* Add zig-libp2p to interop tester

* Fix typo
2023-04-15 17:44:38 +02:00
github-actions[bot] 60003a42ab chore: update the link to the interop dashboard [skip ci] 2023-04-11 19:53:43 +00:00
Marco Munizaga 23fdcef9be Cache images slightly differently (#165) 2023-04-11 11:29:32 -07:00
github-actions[bot] 1bc8283cd6 chore: update the link to the interop dashboard [skip ci] 2023-04-08 20:03:45 +00:00
Marco Munizaga c30c1c429f Sanitize name before saving to compose file (#164) 2023-04-08 12:31:25 -07:00
github-actions[bot] 9c67a406a5 chore: update the link to the interop dashboard [skip ci] 2023-04-08 18:28:24 +00:00
Marco Munizaga d342ac541e Fix: Correctly abort process on timeout (#162)
* Pass in abort controller signal

* Rearrange
2023-04-08 10:53:38 -07:00
github-actions[bot] f9863b901c chore: update the link to the interop dashboard [skip ci] 2023-04-04 11:59:58 +00:00
Max Inden 134a8735d5 fix(versions): disable webrtc tests (#160)
This commit disables the WebRTC tests for rust-libp2p v0.50.0 and v0.51.0 and
chromium-js v0.41.0 and v0.42.0. Neither of these support the new
`/webrtc-direct` (see
https://github.com/multiformats/multiaddr/pull/150/#issuecomment-1468791586 for
context on rename).

The missing support is blocking https://github.com/libp2p/rust-libp2p/pull/3688
namely to upgrade to using `/webrtc-direct`. (Note that this is only blocking
CI. Users can already use `/webrtc-direct` with the latest released
rust-libp2p.)

We will backport `/webrtc-direct` support to the rust-libp2p `v0.51.0` interop
binary and then re-enable it here.

Instead of disabling the versions with missing support for `/webrtc-direct` we
could as well patch our interoperability test logic. For the sake of simplicity,
I am proposing simply disabling the versions for now.
2023-04-04 13:10:30 +02:00
github-actions[bot] e08199551c chore: update the link to the interop dashboard [skip ci] 2023-03-20 05:29:26 +00:00
github-actions[bot] d7aa304d61 chore: update the link to the interop dashboard [skip ci] 2023-03-10 01:32:16 +00:00
Marco Munizaga 54d19f56a4 Add go-libp2p v0.26 (#151) 2023-03-09 16:58:16 -08:00
github-actions[bot] 019118710a chore: update the link to the interop dashboard [skip ci] 2023-03-07 16:22:53 +00:00
Max Inden 9bb9d2f933 feat(rust): Add v0.51 (#148)
With the latest rust-libp2p
[v0.51.0](https://github.com/libp2p/rust-libp2p/releases/tag/v0.51.0) release,
one can now test the `v0.51` family in the interop tests.
2023-03-07 07:46:19 -08:00
github-actions[bot] e1418c0679 chore: update the link to the interop dashboard [skip ci] 2023-03-07 02:15:47 +00:00
Marco Munizaga 1318080e01 Browser WSS testing (#144)
* Update playwright test

* Update multiaddr

* WIP: websocket testing in browser

* Add v0.42 test

* node-image.json

* Revert js v0.41 changes

* Update versions.ts
2023-03-06 17:47:40 -08:00
github-actions[bot] a91f5da8cf chore: update the link to the interop dashboard [skip ci] 2023-02-25 00:02:17 +00:00
Marco Munizaga ad7d37d6f9 Switch to redis:7-alpine (#146) 2023-02-24 15:39:08 -08:00
github-actions[bot] 5ba5425ef7 chore: update the link to the interop dashboard [skip ci] 2023-02-24 23:36:59 +00:00
Marco Munizaga 10794acd49 Add .gitignore for nim (#145) 2023-02-24 15:09:26 -08:00
github-actions[bot] f7fb4b4d92 chore: update the link to the interop dashboard [skip ci] 2023-02-24 21:07:46 +00:00
Marco Munizaga 29daa4876a Fix image references (#143) 2023-02-24 12:46:39 -08:00
github-actions[bot] 6cf68b1658 chore: update the link to the interop dashboard [skip ci] 2023-02-17 23:17:29 +00:00
github-actions[bot] 0d1310305e chore: update the link to the interop dashboard [skip ci] 2023-02-17 23:04:04 +00:00
Marco MunizagaandThomas Eizinger 9ac5af38bf Add backported Rust versions (#134)
* Add backported Rust versions

* Update v0.48 to merge backport commit

* Reference backport commit

* Reference backport commit for v049

---------

Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
2023-02-17 14:47:03 -08:00
Marco MunizagaandThomas Eizinger ed99eadf82 Add key to table (#140)
* Add key to table

* Update multidim-interop/src/lib.ts

Co-authored-by: Thomas Eizinger <thomas@eizinger.io>

---------

Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
2023-02-17 14:46:06 -08:00
github-actions[bot] a5ce5e6d0a chore: update the link to the interop dashboard [skip ci] 2023-02-17 18:01:06 +00:00
Tanguy 80d78c81f7 Nim interop support (#138) 2023-02-17 09:37:26 -08:00
github-actions[bot] 2b40c181de chore: update the link to the interop dashboard [skip ci] 2023-02-13 18:11:31 +00:00
github-actions[bot] a071f4fd83 chore: update the link to the interop dashboard [skip ci] 2023-02-13 18:07:30 +00:00
Marco Munizaga b7285c0a3a Add go-libp2p v0.25.1 (#133) 2023-02-13 09:51:45 -08:00
Max Inden b0d8a55dd9 fix(aws): Only set bucket var when creds are available (#136)
The `dockerBuildWrapper` script enables caching based on the `AWS_BUCKET`
environment variable. When calling the `libp2p ping interop test` with a bucket
name but no AWS credentials, this leads to the script enabling caching even
though the workflow does not have access to AWS.

With this commit the environment variable `AWS_BUCKET` is only set when
credentials are available and thus the `dockerBuildWrapper` script does not enable
caching then workflow does nothave access to AWS.
2023-02-13 09:50:47 -08:00
github-actions[bot] 9643a1f4bc chore: update the link to the interop dashboard [skip ci] 2023-02-11 01:14:38 +00:00
Marco Munizaga 3b6d87b532 Update Go & JS tests to conform to the multidim interop test spec. (#121)
* Update Go test implementations to match new spec

* Update JS test implementation

* Update Rust test Implementation

* Update root Makefile

* Update runner to new spec

* Use composite action and S3 caching

* Not using GHA cache anymore

* Try removing access key from env

* Test workflow without cache keys (#131)

* Test if it works without s3 cache keys

* Fix if statement

* Fix if statement

* Always use buildkit

* Undo debug change

* Add no cache workflow

* Skip test in no-cache workflow

* Update .github/workflows/no-cache-multidim-interop.yml

* Same workflow; use CACHING_OPTIONS

* Add Browser WebRTC test (#130)

* Add webrtc to JS test

* Add onlyDial to all queries

* Update versions.ts

* Remove unneeded timeout overrides
2023-02-10 17:00:53 -08:00
github-actions[bot] ebdf52d20c chore: update the link to the interop dashboard [skip ci] 2023-02-08 18:08:23 +00:00
Prithvi Shahi 1d16ab3ed7 chore: tidy up the repo (#129)
* chore: tidy up the repo

* remove ping/
2023-02-08 09:45:42 -08:00
github-actions[bot] b0550f3936 chore: update the link to the interop dashboard [skip ci] 2023-02-07 20:34:18 +00:00
Prithvi Shahi eeb4425242 chore: update readme and update references to Testground (#128) 2023-02-07 12:10:24 -08:00
github-actions[bot] 41777186d0 chore: update the link to the interop dashboard [skip ci] 2023-02-01 23:49:45 +00:00
Thomas EizingerandMarco Munizaga c9130e425d Introduce composite action for running ping interop tests (#123)
Co-authored-by: Marco Munizaga <git@marcopolo.io>
2023-02-02 10:17:22 +11:00
github-actions[bot] 7fd08bfd80 chore: update the link to the interop dashboard [skip ci] 2023-01-31 00:31:26 +00:00
Marco Munizaga 53adabae00 Add multidim-interop test spec (#117)
* Add test spec

* PR comments

* PR comments
2023-01-30 16:26:27 -08:00
github-actions[bot] 5c19f0876f chore: update the link to the interop dashboard [skip ci] 2023-01-24 18:10:28 +00:00
Marco Munizaga 438b689cfa Use aegir for testing js-libp2p (#104)
* Browser testing with aegir

* Support onlyDial

* Bump timeout for browser tests

* Support webtransport browser test

* PR comments

* Tweak

* Handle cases where the listener exits before dialer

* Remove debug code

* Bump node version

* Prewarm with playwright install

* Support extra timeouts when running against node or browser

* Add timeout option to rust and js
2023-01-24 09:52:44 -08:00
github-actions[bot] 5d55d99de8 chore: update the link to the interop dashboard [skip ci] 2023-01-19 20:30:49 +00:00
Piotr Galar 988ecaa42f feat: update README badge automatically (#108) 2023-01-19 12:18:11 -08:00
João Oliveira b0f3a2d2ae Add webrtc transport multidim interop (#100)
* update interop rust test lib to use tokio

to allow us add the WebRTC transport test (which is only available with
the tokio runtime)
Clean up the test and update Cargo.toml to 0.2.0 to avoid conflicting with the older tests, and allow us to import lib.rs
on the rust-libp2p repo and have the master tests there.

* simplify build_builder function

* replace deprecated ping keepalive

with KeepAlive Behaviour

* add WebRTC support for rust tests

* add webrtc support on interop generator.

* fix typo on generators.ts

webrtc instead of webtransport.

* update rust test plans to use enums instead.

* update rust tests enum to match the ones by generator.ts

* fix webrtc testcases to have proper security and muxer.

* review: address suggestions:

- undo generator changes, let's do that later on
- don't parse muxer and sec protocol where we don't need it

* ident generator.ts.
2023-01-18 11:56:09 +00:00
Marco Munizaga 150c5ca618 feat: multidim-interop: Setup badge (#105) 2023-01-17 16:44:22 -08:00
Marco Munizaga 23ff0db5b5 Support other repos using the multidim interop tests (#99)
* Support running interop workflow from other repos

* A bit of shuffling and cleanup
2023-01-13 10:23:58 -08:00
c35de22070 Add fast multidimensional interop tests (#97)
* Add fast multidimensional interop tests

* Remove generated files

* Remove debug code around itnerfaces

* Revert changes to setup testground

* multidim-interop: update rust v050 test

for multidim-interop with redis

* Add depends on and enable rust version for testing

* Cleanup Rust test

* Have listener print multiaddr in go v024 test

* Remove EXPOSE in dockerfile

* Update multidim-interop/go/v0.24/main.go

Co-authored-by: João Oliveira <hello@jxs.pt>

* Update multidim-interop/go/v0.22/main.go

Co-authored-by: João Oliveira <hello@jxs.pt>

* Update multidim-interop/go/v0.23/main.go

Co-authored-by: João Oliveira <hello@jxs.pt>

* Go nits

* Cleanup Rust makefile

* add working ping test (js) or multidim-interop (#98)

* add working ping test (js) or multidim-interop

* Add JS-libp2p to interop tests

* ping libp2p-js (wo): resolve PR comments

* Add yamux js-libp2p test

Co-authored-by: Marco Munizaga <git@marcopolo.io>

* Fix Go err

* Ignore errors when shutting down

* Fix err

* Rename workflow

* Remove rust v0.49

* Bump up timeouts

Co-authored-by: João Oliveira <hello@jxs.pt>
Co-authored-by: Glen De Cauwsemaecker <contact@glendc.com>
2023-01-10 14:26:27 -08:00
Marco Munizaga 43d50c2500 Fix race in ping test case for Go (#93)
* Fix race condition in go ping

* Fix import

* Pass host in

* Pass host in

* Fix import

* Remove events in v0.11
2022-12-30 20:30:15 -08:00
Thomas Eizinger 34b6eaeffd Bump Rust version of docker image to 1.65 (#90) 2022-12-14 20:14:51 +01:00
TanguyandMax Inden 003eb91e2e Nim ping test (#70)
* Nim ping test

* Working interop

* Add nim toml

* Add CI

* fix workflow name

* Delete go-rust specifics

* Update .github/workflows/ping-interop-latest.yml

Co-authored-by: Max Inden <mail@max-inden.de>

Co-authored-by: Max Inden <mail@max-inden.de>
2022-12-05 17:23:50 -08:00
Max Inden a2d38ccbbe fix(ping/rust): Use refs/heads/master and not branch and master (#81)
* fix(ping/rust): Use refs/heads/master and not branch and master

Follows suggestion in
https://github.com/libp2p/test-plans/pull/79#discussion_r1030425774.
2022-12-01 18:25:34 +01:00
Thomas Eizinger 0ea1553b2c ping/rust: Add 0.50.0 as a release and fix deprecation warnings (#87) 2022-12-01 17:14:22 +01:00
334 changed files with 146450 additions and 27338 deletions
@@ -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
+13
View File
@@ -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)"
+152
View File
@@ -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
+34
View File
@@ -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
+104
View File
@@ -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
-34
View File
@@ -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 }}
-35
View File
@@ -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 }}
-34
View File
@@ -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 }}
-45
View File
@@ -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 }}
-105
View File
@@ -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
+6 -19
View File
@@ -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
+33
View File
@@ -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"'
+79
View File
@@ -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 = `[![${badgeName}](${badgeURL}?branch=${refName})](${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
+8
View File
@@ -39,3 +39,11 @@ __pycache__/
.history
# End of https://www.gitignore.io/api/go,visualstudiocode
### NodeJS
node_modules
dist
# ignore system files
.DS_Store
-158
View File
@@ -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) havent 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 were able to use these tests for benchmarking probably.
- Whats the plan for the day when everything starts to break?
- Whats 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 dont 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
+21 -35
View File
@@ -1,9 +1,27 @@
# Testground test plans for libp2p
# Interoperability/end to end test-plans & performance benchmarking for libp2p
[![Interop Dashboard](https://github.com/vacp2p/libp2p-test-plans/workflows/libp2p%20transport%20interop%20test/badge.svg?branch=master)](https://github.com/vacp2p/libp2p-test-plans/actions/runs/10508587062/attempts/1#summary-29112802717)
[![Made by Protocol Labs](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://protocol.ai)
![Go version](https://img.shields.io/badge/go-%3E%3D1.14.0-blue.svg?style=flat-square)
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
-74
View File
@@ -1,74 +0,0 @@
# `Plan:` The go-libp2p DHT behaves
![](https://img.shields.io/badge/status-wip-orange.svg?style=flat-square)
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`
-170
View File
@@ -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"
-205
View File
@@ -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"
-169
View File
@@ -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"
-43
View File
@@ -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"]
-172
View File
@@ -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"
-205
View File
@@ -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"
-189
View File
@@ -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"
-54
View File
@@ -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"
-52
View File
@@ -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"
-31
View File
@@ -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"
-91
View File
@@ -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
View File
@@ -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
View File
@@ -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=
-47
View File
@@ -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
View File
@@ -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)
}
-172
View File
@@ -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 }
-29
View File
@@ -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"
}
-225
View File
@@ -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
-204
View File
@@ -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"
}
-34
View File
@@ -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
}
-20
View File
@@ -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
}
-946
View File
@@ -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,
)
}
-49
View File
@@ -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) {}
-134
View File
@@ -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))
}
-110
View File
@@ -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
}
-242
View File
@@ -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
}
-188
View File
@@ -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
}
-73
View File
@@ -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")
}
-319
View File
@@ -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
}
-9
View File
@@ -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{})
-79
View File
@@ -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
}
-109
View File
@@ -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
}
-14
View File
@@ -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
}
-202
View File
@@ -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) {}
+5
View File
@@ -0,0 +1,5 @@
{
"opRetro": {
"projectId": "0x966804cb492e1a4bde5d781a676a44a23d69aa5dd2562fa7a4f95bb606021c8b"
}
}
+7
View File
@@ -0,0 +1,7 @@
# For now, not committing image.json files
image.json
results.csv
runs/
node_modules/
+19
View File
@@ -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)
+84
View File
@@ -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;
}
+13
View File
@@ -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 "$@"
+161
View File
@@ -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
}
}
+4
View File
@@ -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-*
File diff suppressed because it is too large Load Diff
+28
View File
@@ -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"
}
}
+41
View File
@@ -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()
+11
View File
@@ -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"]
+10
View File
@@ -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
+16
View File
@@ -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.
+27
View File
@@ -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/
+1
View File
@@ -0,0 +1 @@
target/
File diff suppressed because it is too large Load Diff
+15
View File
@@ -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"] }
+20
View File
@@ -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"]
+10
View File
@@ -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
+151
View File
@@ -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,
}
+79
View File
@@ -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()
}
+173
View File
@@ -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: {},
}
}
}
+124
View File
@@ -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")
}
+131
View File
@@ -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")
})()
+8
View File
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"resolveJsonModule": true,
"esModuleInterop": true,
"target": "ES2015",
"moduleResolution": "node"
}
}
+38
View File
@@ -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`
}
-112
View File
@@ -1,112 +0,0 @@
# `Plan:` Nodes Connectivity (Transports, Hole Punching, Relay)
![](https://img.shields.io/badge/status-wip-orange.svg?style=flat-square)
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
+5
View File
@@ -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
View File
@@ -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).
+24
View File
@@ -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
+4
View File
@@ -0,0 +1,4 @@
go-libp2p-*.zip
go-libp2p-*
go-libp2p-*/*
image.json
+3
View File
@@ -0,0 +1,3 @@
perf
.cache
v0.27
+14
View File
@@ -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" ]
+13
View File
@@ -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
+98
View File
@@ -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
)
+506
View File
@@ -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=
+120
View File
@@ -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
}
+169
View File
@@ -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
}
+2
View File
@@ -0,0 +1,2 @@
perf
.cache

Some files were not shown because too many files have changed in this diff Show More