Integrate BACKBEAT SDK and resolve KACHING license validation
Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2
vendor/github.com/libp2p/go-libp2p/.codecov.yml
generated
vendored
Normal file
2
vendor/github.com/libp2p/go-libp2p/.codecov.yml
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
github_checks:
|
||||
annotations: false
|
||||
6
vendor/github.com/libp2p/go-libp2p/.gitignore
generated
vendored
Normal file
6
vendor/github.com/libp2p/go-libp2p/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
*.swp
|
||||
.idea
|
||||
*.qlog
|
||||
*.sqlog
|
||||
*.qlog.zst
|
||||
*.sqlog.zst
|
||||
293
vendor/github.com/libp2p/go-libp2p/CHANGELOG.md
generated
vendored
Normal file
293
vendor/github.com/libp2p/go-libp2p/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
# Table Of Contents <!-- omit in toc -->
|
||||
- [v0.28.0](#v0280)
|
||||
- [v0.27.0](#v0270)
|
||||
- [v0.26.4](#v0264)
|
||||
- [v0.26.3](#v0263)
|
||||
- [v0.26.2](#v0262)
|
||||
- [v0.26.1](#v0261)
|
||||
- [v0.26.0](#v0260)
|
||||
- [v0.25.1](#v0251)
|
||||
- [v0.25.0](#v0250)
|
||||
|
||||
# [v0.28.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.28.0)
|
||||
|
||||
## 🔦 Highlights <!-- omit in toc -->
|
||||
|
||||
### Smart Dialing <!-- omit in toc -->
|
||||
|
||||
This release introduces smart dialing logic. Currently, libp2p dials all addresses of a remote peer in parallel, and
|
||||
aborts all outstanding dials as soon as the first one succeeds.
|
||||
Dialing many addresses in parallel creates a lot of churn on the client side, and unnecessary load on the network and
|
||||
on the server side, and is heavily discouraged by the networking community (see [RFC 8305](https://www.rfc-editor.org/rfc/rfc8305) for example).
|
||||
|
||||
When connecting to a peer we first determine the order to dial its addresses. This ranking logic considers a number of corner cases
|
||||
described in detail in the documentation of the swarm package (`swarm.DefaultDialRanker`).
|
||||
At a high level, this is what happens:
|
||||
* If a peer offers a WebTransport and a QUIC address (on the same IP:port), the QUIC address is preferred.
|
||||
* If a peer has a QUIC and a TCP address, the QUIC address is dialed first. Only if the connection attempt doesn't succeed within 250ms, a TCP connection is started.
|
||||
|
||||
Our measurements on the IPFS network show that for >90% of established libp2p connections, the first connection attempt succeeds,
|
||||
leading a dramatic decrease in the number of aborted connection attempts.
|
||||
|
||||
We also added new metrics to the swarm Grafana dashboard, showing:
|
||||
* The number of connection attempts it took to establish a connection
|
||||
* The delay introduced by the ranking logic
|
||||
|
||||
This feature should be safe to enable for nodes running in data centers and for most nodes in home networks.
|
||||
However, there are some (mostly home and corporate networks) that block all UDP traffic. If enabled, the current implementation
|
||||
of the smart dialing logic will lead to a regression, since it preferes QUIC addresses over TCP addresses. Nodes would still be
|
||||
able to connect, but connection establishment of the TCP connection would be delayed by 250ms.
|
||||
|
||||
In a future release (see #1605 for details), we will introduce a feature called blackhole detection. By observing the outcome of
|
||||
QUIC connection attempts, we can determine if UDP traffic is blocked (namely, if all QUIC connection attempts fail), and stop
|
||||
dialing QUIC in this case altogether. Once this detection logic is in place, smart dialing will be enabled by default.
|
||||
|
||||
### More Metrics! <!-- omit in toc -->
|
||||
Since the last release, we've added metrics for:
|
||||
* [Holepunching](https://github.com/libp2p/go-libp2p/pull/2246)
|
||||
* Smart Dialing (see above)
|
||||
|
||||
### WebTransport <!-- omit in toc -->
|
||||
* [#2251](https://github.com/libp2p/go-libp2p/pull/2251): Infer public WebTransport address from `quic-v1` addresses if both transports are using the same port for both quic-v1 and WebTransport addresses.
|
||||
* [#2271](https://github.com/libp2p/go-libp2p/pull/2271): Only add certificate hashes to WebTransport mulitaddress if listening on WebTransport
|
||||
|
||||
## Housekeeping updates <!-- omit in toc -->
|
||||
* Identify
|
||||
* [#2303](https://github.com/libp2p/go-libp2p/pull/2303): Don't send default protocol version
|
||||
* Prevent polluting PeerStore with local addrs
|
||||
* [#2325](https://github.com/libp2p/go-libp2p/pull/2325): Don't save signed peer records
|
||||
* [#2300](https://github.com/libp2p/go-libp2p/pull/2300): Filter received addresses based on the node's remote address
|
||||
* WebSocket
|
||||
* [#2280](https://github.com/libp2p/go-libp2p/pull/2280): Reverted back to the Gorilla library for WebSocket
|
||||
* NAT
|
||||
* [#2248](https://github.com/libp2p/go-libp2p/pull/2248): Move NAT mapping logic out of the host
|
||||
|
||||
## 🐞 Bugfixes <!-- omit in toc -->
|
||||
* Identify
|
||||
* [Reject signed peer records on peer ID mismatch](https://github.com/libp2p/go-libp2p/commit/8d771355b41297623e05b04a865d029a2522a074)
|
||||
* [#2299](https://github.com/libp2p/go-libp2p/pull/2299): Avoid spuriously pushing updates
|
||||
* Swarm
|
||||
* [#2322](https://github.com/libp2p/go-libp2p/pull/2322): Dedup addresses to dial
|
||||
* [#2284](https://github.com/libp2p/go-libp2p/pull/2284): Change maps with multiaddress keys to use strings
|
||||
* QUIC
|
||||
* [#2262](https://github.com/libp2p/go-libp2p/pull/2262): Prioritize listen connections for reuse
|
||||
* [#2276](https://github.com/libp2p/go-libp2p/pull/2276): Don't panic when quic-go's accept call errors
|
||||
* [#2263](https://github.com/libp2p/go-libp2p/pull/2263): Fix race condition when generating random holepunch packet
|
||||
|
||||
**Full Changelog**: https://github.com/libp2p/go-libp2p/compare/v0.27.0...v0.28.0
|
||||
|
||||
# [v0.27.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.27.0)
|
||||
|
||||
### Breaking Changes <!-- omit in toc -->
|
||||
|
||||
* The `LocalPrivateKey` method was removed from the `network.Conn` interface. [#2144](https://github.com/libp2p/go-libp2p/pull/2144)
|
||||
|
||||
## 🔦 Highlights <!-- omit in toc -->
|
||||
|
||||
### Additional metrics <!-- omit in toc -->
|
||||
Since the last release, we've added metrics for:
|
||||
* [Relay Service](https://github.com/libp2p/go-libp2p/pull/2154): RequestStatus, RequestCounts, RejectionReasons for Reservation and Connection Requests,
|
||||
ConnectionDuration, BytesTransferred, Relay Service Status.
|
||||
* [Autorelay](https://github.com/libp2p/go-libp2p/pull/2185): relay finder status, reservation request outcomes, current reservations, candidate circuit v2 support, current candidates, relay addresses updated, num relay address, and scheduled work times
|
||||
|
||||
## 🐞 Bugfixes <!-- omit in toc -->
|
||||
|
||||
* autonat: don't change status on dial request refused [2225](https://github.com/libp2p/go-libp2p/pull/2225)
|
||||
* relaysvc: fix flaky TestReachabilityChangeEvent [2215](https://github.com/libp2p/go-libp2p/pull/2215)
|
||||
* basichost: prevent duplicate dials [2196](https://github.com/libp2p/go-libp2p/pull/2196)
|
||||
* websocket: don't set a WSS multiaddr for accepted unencrypted conns [2199](https://github.com/libp2p/go-libp2p/pull/2199)
|
||||
* identify: Fix IdentifyWait when Connected events happen out of order [2173](https://github.com/libp2p/go-libp2p/pull/2173)
|
||||
* circuitv2: cleanup relay service properly [2164](https://github.com/libp2p/go-libp2p/pull/2164)
|
||||
|
||||
**Full Changelog**: https://github.com/libp2p/go-libp2p/compare/v0.26.4...v0.27.0
|
||||
|
||||
# [v0.26.4](https://github.com/libp2p/go-libp2p/releases/tag/v0.26.4)
|
||||
|
||||
This patch release fixes a busy-looping happening inside AutoRelay on private nodes, see [2208](https://github.com/libp2p/go-libp2p/pull/2208).
|
||||
|
||||
**Full Changelog**: https://github.com/libp2p/go-libp2p/compare/v0.26.0...v0.26.4
|
||||
|
||||
# [v0.26.3](https://github.com/libp2p/go-libp2p/releases/tag/v0.26.3)
|
||||
|
||||
* rcmgr: fix JSON marshalling of ResourceManagerStat peer map [2156](https://github.com/libp2p/go-libp2p/pull/2156)
|
||||
* websocket: Don't limit message sizes in the websocket reader [2193](https://github.com/libp2p/go-libp2p/pull/2193)
|
||||
|
||||
**Full Changelog**: https://github.com/libp2p/go-libp2p/compare/v0.26.0...v0.26.3
|
||||
|
||||
# [v0.26.2](https://github.com/libp2p/go-libp2p/releases/tag/v0.26.2)
|
||||
|
||||
This patch release fixes two bugs:
|
||||
* A panic in WebTransport: https://github.com/quic-go/webtransport-go/releases/tag/v0.5.2
|
||||
* Incorrect accounting of accepted connections in the swarm metrics: [#2147](https://github.com/libp2p/go-libp2p/pull/2147)
|
||||
|
||||
**Full Changelog**: https://github.com/libp2p/go-libp2p/compare/v0.26.0...v0.26.2
|
||||
|
||||
# v0.26.1
|
||||
|
||||
This version was retracted due to errors when publishing the release.
|
||||
|
||||
# [v0.26.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.26.0)
|
||||
|
||||
## 🔦 Highlights <!-- omit in toc -->
|
||||
|
||||
### Circuit Relay Changes <!-- omit in toc -->
|
||||
|
||||
#### [Removed Circuit Relay v1](https://github.com/libp2p/go-libp2p/pull/2107) <!-- omit in toc -->
|
||||
|
||||
We've decided to remove support for Circuit Relay v1 in this release. v1 Relays have been retired a few months ago. Notably, running the Relay v1 protocol was expensive and resulted in only a small number of nodes in the network. Users had to either manually configure these nodes as static relays, or discover them from the DHT.
|
||||
Furthermore, rust-libp2p [has dropped support](https://github.com/libp2p/rust-libp2p/pull/2549) and js-libp2p [is dropping support](https://github.com/libp2p/js-libp2p/pull/1533) for Relay v1.
|
||||
|
||||
Support for Relay v2 was first added in [late 2021 in v0.16.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.16.0). With Circuit Relay v2 it became cheap to run (limited) relays. Public nodes also started the relay service by default. There's now a massive number of Relay v2 nodes on the IPFS network, and they don't advertise their service to the DHT any more. Because there's now so many of these nodes, connecting to just a small number of nodes (e.g. by joining the DHT), a node is statistically guaranteed to connect to some relays.
|
||||
|
||||
#### [Unlimited Relay v2](https://github.com/libp2p/go-libp2p/pull/2125) <!-- omit in toc -->
|
||||
|
||||
In conjunction with removing relay v1, we also added an option to Circuit Relay v2 to disable limits.
|
||||
This done by enabling `WithInfiniteLimits`. When enabled this allows for users to have a drop in replacement for Relay v1 with Relay v2.
|
||||
|
||||
### Additional metrics <!-- omit in toc -->
|
||||
|
||||
Since the last release, we've added additional metrics to different components.
|
||||
Metrics were added to:
|
||||
* [AutoNat](https://github.com/libp2p/go-libp2p/pull/2086): Current Reachability Status and Confidence, Client and Server DialResponses, Server DialRejections. The dashboard is [available here](https://github.com/libp2p/go-libp2p/blob/master/dashboards/autonat/autonat.json).
|
||||
* Swarm:
|
||||
- [Early Muxer Selection](https://github.com/libp2p/go-libp2p/pull/2119): Added early_muxer label indicating whether a connection was established using early muxer selection.
|
||||
- [IP Version](https://github.com/libp2p/go-libp2p/pull/2114): Added ip_version label to connection metrics
|
||||
* Identify:
|
||||
- Metrics for Identify, IdentifyPush, PushesTriggered (https://github.com/libp2p/go-libp2p/pull/2069)
|
||||
- Address Count, Protocol Count, Connection IDPush Support (https://github.com/libp2p/go-libp2p/pull/2126)
|
||||
|
||||
|
||||
We also migrated the metric dashboards to a top-level [dashboards](https://github.com/libp2p/go-libp2p/tree/master/dashboards) directory.
|
||||
|
||||
## 🐞 Bugfixes <!-- omit in toc -->
|
||||
|
||||
### AutoNat <!-- omit in toc -->
|
||||
* [Fixed a bug](https://github.com/libp2p/go-libp2p/issues/2091) where AutoNat would emit events when the observed address has changed even though the node reachability hadn't changed.
|
||||
|
||||
### Relay Manager <!-- omit in toc -->
|
||||
* [Fixed a bug](https://github.com/libp2p/go-libp2p/pull/2093) where the Relay Manager started a new relay even though the previous reachability was `Public` or if a relay already existed.
|
||||
|
||||
### [Stop sending detailed error messages on closing QUIC connections](https://github.com/libp2p/go-libp2p/pull/2112) <!-- omit in toc -->
|
||||
|
||||
Users reported seeing confusing error messages and could not determine the root cause or if the error was from a local or remote peer:
|
||||
|
||||
```{12D... Application error 0x0: conn-27571160: system: cannot reserve inbound connection: resource limit exceeded}```
|
||||
|
||||
This error occurred when a connection had been made with a remote peer but the remote peer dropped the connection (due to it exceeding limits).
|
||||
This was actually an `Application error` emitted by `quic-go` and it was a bug in go-libp2p that we sent the whole message.
|
||||
For now, we decided to stop sending this confusing error message. In the future, we will report such errors via [error codes](https://github.com/libp2p/specs/issues/479).
|
||||
|
||||
**Full Changelog**: https://github.com/libp2p/go-libp2p/compare/v0.25.1...v0.26.0
|
||||
|
||||
# [v0.25.1](https://github.com/libp2p/go-libp2p/releases/tag/v0.25.1)
|
||||
|
||||
Fix some test-utils used by https://github.com/libp2p/go-libp2p-kad-dht
|
||||
|
||||
* mocknet: Start host in mocknet by @MarcoPolo in https://github.com/libp2p/go-libp2p/pull/2078
|
||||
* chore: update go-multistream by @MarcoPolo in https://github.com/libp2p/go-libp2p/pull/2081
|
||||
|
||||
**Full Changelog**: https://github.com/libp2p/go-libp2p/compare/v0.25.0...v0.25.1
|
||||
|
||||
# [v0.25.0](https://github.com/libp2p/go-libp2p/releases/tag/v0.25.0)
|
||||
|
||||
## 🔦 Highlights <!-- omit in toc -->
|
||||
|
||||
### Metrics <!-- omit in toc -->
|
||||
|
||||
We've started instrumenting the entire stack. In this release, we're adding metrics for:
|
||||
* the swarm: tracking incoming and outgoing connections, transports, security protocols and stream multiplexers in use: (https://github.com/libp2p/go-libp2p/blob/master/dashboards/swarm/swarm.json)
|
||||
* the event bus: tracking how different events are propagated through the stack and to external consumers (https://github.com/libp2p/go-libp2p/blob/master/dashboards/eventbus/eventbus.json)
|
||||
|
||||
Our metrics effort is still ongoing, see https://github.com/libp2p/go-libp2p/issues/1356 for progress. We'll add metrics and dashboards for more libp2p components in a future release.
|
||||
|
||||
### Switching to Google's official Protobuf compiler <!-- omit in toc -->
|
||||
|
||||
So far, we were using GoGo Protobuf to compile our Protobuf definitions to Go code. However, this library was deprecated in October last year: https://twitter.com/awalterschulze/status/1584553056100057088. We [benchmarked](https://github.com/libp2p/go-libp2p/issues/1976#issuecomment-1371527732) serialization and deserialization, and found that it's (only) 20% slower than GoGo. Since the vast majority of go-libp2p's CPU time is spent in code paths other than Protobuf handling, switching to the official compiler seemed like a worthwhile tradeoff.
|
||||
|
||||
### Removal of OpenSSL <!-- omit in toc -->
|
||||
|
||||
Before this release, go-libp2p had an option to use OpenSSL bindings for certain cryptographic primitives, mostly to speed up the generation of signatures and their verification. When building go-libp2p using `go build`, we'd use the standard library crypto packages. OpenSSL was only used when passing in a build tag: `go build -tags openssl`.
|
||||
Maintaining our own fork of the long unmaintained [go-openssl package](https://github.com/libp2p/go-openssl) has proven to place a larger than expected maintenance burden on the libp2p stewards, and when we recently discovered a range of new bugs ([this](https://github.com/libp2p/go-openssl/issues/38) and [this](https://github.com/libp2p/go-libp2p/issues/1892) and [this](https://github.com/libp2p/go-libp2p/issues/1951)), we decided to re-evaluate if this code path is really worth it. The results surprised us, it turns out that:
|
||||
* The Go standard library is faster than OpenSSL for all key types that are not RSA.
|
||||
* Verifying RSA signatures is as fast as Ed25519 signatures using the Go standard library, and even faster in OpenSSL.
|
||||
* Generating RSA signatures is painfully slow, both using Go standard library crypto and using OpenSSL (but even slower using Go standard library).
|
||||
|
||||
Now the good news is, that if your node is not using an RSA key, it will never create any RSA signatures (it might need to verify them though, when it connects to a node that uses RSA keys). If you're concerned about CPU performance, it's a good idea to avoid RSA keys (the same applies to bandwidth, RSA keys are huge!). Even for nodes using RSA keys, it turns out that generating the signatures is not a significant part of their CPU load, as verified by profiling one of Kubo's bootstrap nodes.
|
||||
|
||||
We therefore concluded that it's safe to drop this code path altogether, and thereby reduce our maintenance burden.
|
||||
|
||||
### New Resource Manager types <!-- omit in toc -->
|
||||
|
||||
* Introduces a new type `LimitVal` which can explicitly specify "use default", "unlimited", "block all", as well as any positive number. The zero value of `LimitVal` (the value when you create the object in Go) is "Use default".
|
||||
* The JSON marshalling of this is straightforward.
|
||||
* Introduces a new `ResourceLimits` type which uses `LimitVal` instead of ints so it can encode the above for the resources.
|
||||
* Changes `LimitConfig` to `PartialLimitConfig` and uses `ResourceLimits`. This along with the marshalling changes means you can now marshal the fact that some resource limit is set to block all.
|
||||
* Because the default is to use the defaults, this avoids the footgun of initializing the resource manager with 0 limits (that would block everything).
|
||||
|
||||
In general, you can go from a resource config with defaults to a concrete one with `.Build()`. e.g. `ResourceLimits.Build() => BaseLimit`, `PartialLimitConfig.Build() => ConcreteLimitConfig`, `LimitVal.Build() => int`. See PR #2000 for more details.
|
||||
|
||||
If you're using the defaults for the resource manager, there should be no changes needed.
|
||||
|
||||
### Other Breaking Changes <!-- omit in toc -->
|
||||
|
||||
We've cleaned up our API to consistently use `protocol.ID` for libp2p and application protocols. Specifically, this means that the peer store now uses `protocol.ID`s, and the host's `SetStreamHandler` as well.
|
||||
|
||||
## What's Changed <!-- omit in toc -->
|
||||
* chore: use generic LRU cache by @muXxer in https://github.com/libp2p/go-libp2p/pull/1980
|
||||
* core/crypto: drop all OpenSSL code paths by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1953
|
||||
* add WebTransport to the list of default transports by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1915
|
||||
* identify: remove old code targeting Go 1.17 by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1964
|
||||
* core: remove introspection package by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1978
|
||||
* identify: remove support for Identify Delta by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1975
|
||||
* roadmap: remove optimizations of the TCP-based handshake by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1959
|
||||
* circuitv2: correctly set the transport in the ConnectionState by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1972
|
||||
* switch to Google's Protobuf library, make protobufs compile with go generate by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1979
|
||||
* ci: run go generate as part of the go-check workflow by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1986
|
||||
* ci: use GitHub token to install protoc by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1996
|
||||
* feat: add some users to the readme by @p-shahi in https://github.com/libp2p/go-libp2p/pull/1981
|
||||
* CI: Fast multidimensional Interop tests by @MarcoPolo in https://github.com/libp2p/go-libp2p/pull/1991
|
||||
* Fix: Ignore zero values when marshalling Limits. by @ajnavarro in https://github.com/libp2p/go-libp2p/pull/1998
|
||||
* feat: add ci flakiness score to readme by @MarcoPolo in https://github.com/libp2p/go-libp2p/pull/2002
|
||||
* peerstore: make it possible to use an empty peer ID by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/2006
|
||||
* feat: rcmgr: Export resource manager errors by @MarcoPolo in https://github.com/libp2p/go-libp2p/pull/2008
|
||||
* feat: ci test-plans: Parse test timeout parameter for interop test by @MarcoPolo in https://github.com/libp2p/go-libp2p/pull/2014
|
||||
* Clean addresses with peer id before adding to addrbook by @sukunrt in https://github.com/libp2p/go-libp2p/pull/2007
|
||||
* Expose muxer ids by @aschmahmann in https://github.com/libp2p/go-libp2p/pull/2012
|
||||
* swarm: add a basic metrics tracer by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1973
|
||||
* consistently use protocol.ID instead of strings by @sukunrt in https://github.com/libp2p/go-libp2p/pull/2004
|
||||
* swarm metrics: fix datasource for dashboard by @MarcoPolo in https://github.com/libp2p/go-libp2p/pull/2024
|
||||
* chore: remove textual roadmap in favor for Starmap by @p-shahi in https://github.com/libp2p/go-libp2p/pull/2036
|
||||
* rcmgr: *: Always close connscope by @MarcoPolo in https://github.com/libp2p/go-libp2p/pull/2037
|
||||
* chore: remove license files from the eventbus package by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/2042
|
||||
* Migrate to test-plan composite action by @thomaseizinger in https://github.com/libp2p/go-libp2p/pull/2039
|
||||
* use quic-go and webtransport-go from quic-go organization by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/2040
|
||||
* holepunch: fix flaky test by not removing holepunch protocol handler by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1948
|
||||
* quic / webtransport: extend test to test dialing a draft-29 and a v1 by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1957
|
||||
* p2p/test: add test for EvtLocalAddressesUpdated event by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/2016
|
||||
* quic, tcp: only register Prometheus counters when metrics are enabled by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1971
|
||||
* p2p/test: fix flaky notification test by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/2051
|
||||
* quic: disable sending of Version Negotiation packets by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/2015
|
||||
* eventbus: add metrics by @sukunrt in https://github.com/libp2p/go-libp2p/pull/2038
|
||||
* metrics: use a single slice pool for all metrics tracer by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/2054
|
||||
* webtransport: tidy up some test output by @MarcoPolo in https://github.com/libp2p/go-libp2p/pull/2053
|
||||
* set names for eventbus event subscriptions by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/2057
|
||||
* autorelay: Split libp2p.EnableAutoRelay into 2 functions by @sukunrt in https://github.com/libp2p/go-libp2p/pull/2022
|
||||
* rcmgr: Use prometheus SDK for rcmgr metrics by @MarcoPolo in https://github.com/libp2p/go-libp2p/pull/2044
|
||||
* websocket: Replace gorilla websocket transport with nhooyr websocket transport by @MarcoPolo in https://github.com/libp2p/go-libp2p/pull/1982
|
||||
* rcmgr: add libp2p prefix to all metrics by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/2063
|
||||
* chore: git-ignore various flavors of qlog files by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/2064
|
||||
* interop: Update interop test to match spec by @MarcoPolo in https://github.com/libp2p/go-libp2p/pull/2049
|
||||
* chore: update webtransport-go to v0.5.1 by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/2072
|
||||
* identify: refactor sending of Identify pushes by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/1984
|
||||
* feat!: rcmgr: Change LimitConfig to use LimitVal type by @MarcoPolo in https://github.com/libp2p/go-libp2p/pull/2000
|
||||
* p2p/test/quic: use contexts with a timeout for Connect calls by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/2070
|
||||
* identify: add some basic metrics by @marten-seemann in https://github.com/libp2p/go-libp2p/pull/2069
|
||||
* chore: Release v0.25.0 by @MarcoPolo in https://github.com/libp2p/go-libp2p/pull/2077
|
||||
|
||||
## New Contributors <!-- omit in toc -->
|
||||
* @muXxer made their first contribution in https://github.com/libp2p/go-libp2p/pull/1980
|
||||
* @ajnavarro made their first contribution in https://github.com/libp2p/go-libp2p/pull/1998
|
||||
* @sukunrt made their first contribution in https://github.com/libp2p/go-libp2p/pull/2007
|
||||
* @thomaseizinger made their first contribution in https://github.com/libp2p/go-libp2p/pull/2039
|
||||
|
||||
**Full Changelog**: https://github.com/libp2p/go-libp2p/compare/v0.24.2...v0.25.0
|
||||
21
vendor/github.com/libp2p/go-libp2p/LICENSE
generated
vendored
Normal file
21
vendor/github.com/libp2p/go-libp2p/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Juan Batiz-Benet
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
108
vendor/github.com/libp2p/go-libp2p/README.md
generated
vendored
Normal file
108
vendor/github.com/libp2p/go-libp2p/README.md
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
|
||||
<h1 align="center">
|
||||
<a href="libp2p.io"><img width="250" src="https://github.com/libp2p/libp2p/blob/master/logo/black-bg-2.png?raw=true" alt="libp2p hex logo" /></a>
|
||||
</h1>
|
||||
|
||||
<h3 align="center">The Go implementation of the libp2p Networking Stack.</h3>
|
||||
|
||||
<p align="center">
|
||||
<a href="http://protocol.ai"><img src="https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square" /></a>
|
||||
<a href="http://libp2p.io/"><img src="https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square" /></a>
|
||||
<a href="https://pkg.go.dev/github.com/libp2p/go-libp2p"><img src="https://pkg.go.dev/badge/github.com/libp2p/go-libp2p.svg" alt="Go Reference"></a>
|
||||
<a href="https://discuss.libp2p.io"><img src="https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg"/></a>
|
||||
<a href="https://marcopolo.github.io/FlakyTests/"><img src="https://marcopolo.github.io/FlakyTests/current-score.svg"/></a>
|
||||
</p>
|
||||
|
||||
# Table of Contents <!-- omit in toc -->
|
||||
- [Background](#background)
|
||||
- [Roadmap](#roadmap)
|
||||
- [Usage](#usage)
|
||||
- [Examples](#examples)
|
||||
- [Dashboards](#dashboards)
|
||||
- [Contribute](#contribute)
|
||||
- [Supported Go Versions](#supported-go-versions)
|
||||
- [Notable Users](#notable-users)
|
||||
|
||||
# Background
|
||||
|
||||
[libp2p](https://github.com/libp2p/specs) is a networking stack and library modularized out of [The IPFS Project](https://github.com/ipfs/ipfs), and bundled separately for other tools to use.
|
||||
>
|
||||
libp2p is the product of a long, and arduous quest of understanding -- a deep dive into the internet's network stack, and plentiful peer-to-peer protocols from the past. Building large-scale peer-to-peer systems has been complex and difficult in the last 15 years, and libp2p is a way to fix that. It is a "network stack" -- a protocol suite -- that cleanly separates concerns, and enables sophisticated applications to only use the protocols they absolutely need, without giving up interoperability and upgradeability. libp2p grew out of IPFS, but it is built so that lots of people can use it, for lots of different projects.
|
||||
|
||||
To learn more, check out the following resources:
|
||||
- [**Our documentation**](https://docs.libp2p.io)
|
||||
- [**Our community discussion forum**](https://discuss.libp2p.io)
|
||||
- [**The libp2p Specification**](https://github.com/libp2p/specs)
|
||||
- [**js-libp2p implementation**](https://github.com/libp2p/js-libp2p)
|
||||
- [**rust-libp2p implementation**](https://github.com/libp2p/rust-libp2p)
|
||||
|
||||
# Roadmap
|
||||
|
||||
Our roadmap for go-libp2p can be found here: https://github.com/libp2p/go-libp2p/blob/master/ROADMAP.md
|
||||
This document represents current projects the go-libp2p team is focused on and provides an estimation of completion targets. It is a complementary roadmap to the overarching libp2p project roadmap: https://github.com/libp2p/specs/blob/master/ROADMAP.md
|
||||
|
||||
# Usage
|
||||
|
||||
This repository (`go-libp2p`) serves as the entrypoint to the universe of packages that compose the Go implementation of the libp2p stack.
|
||||
|
||||
You can start using go-libp2p in your Go application simply by adding imports from our repos, e.g.:
|
||||
|
||||
```go
|
||||
import "github.com/libp2p/go-libp2p"
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Examples can be found in the [examples folder](examples).
|
||||
|
||||
## Dashboards
|
||||
|
||||
We provide prebuilt Grafana dashboards so that applications can better monitor libp2p in production.
|
||||
You can find the [dashboard JSON files here](https://github.com/libp2p/go-libp2p/tree/master/dashboards).
|
||||
|
||||
We also have live [Public Dashboards](https://github.com/libp2p/go-libp2p/tree/master/dashboards/README.md#public-dashboards) that you can check out to see real time monitoring in action.
|
||||
|
||||
|
||||
# Contribute
|
||||
|
||||
go-libp2p is MIT-licensed open source software. We welcome contributions big and small! Take a look at the [community contributing notes](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md). Please make sure to check the [issues](https://github.com/libp2p/go-libp2p/issues). Search the closed ones before reporting things, and help us with the open ones.
|
||||
|
||||
Guidelines:
|
||||
|
||||
- read the [libp2p spec](https://github.com/libp2p/specs)
|
||||
- ask questions or talk about things in our [discussion forums](https://discuss.libp2p.io), or open an [issue](https://github.com/libp2p/go-libp2p/issues) for bug reports, or #libp2p-implementers on [Filecoin slack](https://filecoin.io/slack).
|
||||
- ensure you are able to contribute (no legal issues please -- we use the DCO)
|
||||
- get in touch with @libp2p/go-libp2p-maintainers about how best to contribute
|
||||
- have fun!
|
||||
|
||||
There's a few things you can do right now to help out:
|
||||
- Go through the modules below and **check out existing issues**. This would be especially useful for modules in active development. Some knowledge of IPFS/libp2p may be required, as well as the infrastructure behind it - for instance, you may need to read up on p2p and more complex operations like muxing to be able to help technically.
|
||||
- **Perform code reviews**.
|
||||
- **Add tests**. There can never be enough tests.
|
||||
|
||||
## Supported Go Versions
|
||||
|
||||
We test against and support the two most recent major releases of Go. This is
|
||||
informed by Go's own [security policy](https://go.dev/security).
|
||||
|
||||
# Notable Users
|
||||
Some notable users of go-libp2p are:
|
||||
- [Kubo](https://github.com/ipfs/kubo) - The original Go implementation of IPFS
|
||||
- [Lotus](https://github.com/filecoin-project/lotus) - An implementation of the Filecoin protocol
|
||||
- [Drand](https://github.com/drand/drand) - A distributed random beacon daemon
|
||||
- [Prysm](https://github.com/prysmaticlabs/prysm) - An Ethereum Beacon Chain consensus client built by [Prysmatic Labs](https://prysmaticlabs.com/)
|
||||
- [Berty](https://github.com/berty/berty) - An open, secure, offline-first, peer-to-peer and zero trust messaging app.
|
||||
- [Wasp](https://github.com/iotaledger/wasp) - A node that runs IOTA Smart Contracts built by the [IOTA Foundation](https://www.iota.org/)
|
||||
- [Mina](https://github.com/minaprotocol/mina) - A lightweight, constant-sized blockchain that runs zero-knowledge smart contracts
|
||||
- [Polygon Edge](https://github.com/0xPolygon/polygon-edge) - A modular, extensible framework for building Ethereum compatible networks
|
||||
- [Celestia Node](https://github.com/celestiaorg/celestia-node) - The Go implementation of Celestia's data availability nodes
|
||||
- [Status go](https://github.com/status-im/status-go) - Status bindings for go-ethereum, built by [Status.im](https://status.im/)
|
||||
- [Flow](https://github.com/onflow/flow-go) - A blockchain built to support games, apps, and digital assets built by [Dapper Labs](https://www.dapperlabs.com/)
|
||||
- [Swarm Bee](https://github.com/ethersphere/bee) - A client for connecting to the [Swarm network](https://www.ethswarm.org/)
|
||||
- [Elrond Go](https://github.com/multiversx/mx-chain-go) - The Go implementation of the the Elrond network protocol
|
||||
- [Sonr](https://github.com/sonr-io/sonr) - A platform to integrate DID Documents, WebAuthn, and IPFS and manage digital identity and assets.
|
||||
- [EdgeVPN](https://github.com/mudler/edgevpn) - A decentralized, immutable, portable VPN and reverse proxy over p2p.
|
||||
- [Kairos](https://github.com/kairos-io/kairos) - A Kubernetes-focused, Cloud Native Linux meta-distribution.
|
||||
- [Oasis Core](https://github.com/oasisprotocol/oasis-core) - The consensus and runtime layers of the [Oasis protocol](https://oasisprotocol.org/).
|
||||
|
||||
Please open a pull request if you want your project (min. 250 GitHub stars) to be added here.
|
||||
5
vendor/github.com/libp2p/go-libp2p/ROADMAP.md
generated
vendored
Normal file
5
vendor/github.com/libp2p/go-libp2p/ROADMAP.md
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# go-libp2p roadmap Q4’22/Q1’23
|
||||
|
||||
Please see our roadmap in [Starmap](https://starmap.site/roadmap/github.com/libp2p/go-libp2p/issues/1806#simple)
|
||||
|
||||
Please add any feedback or questions in: https://github.com/libp2p/go-libp2p/issues/1806
|
||||
20
vendor/github.com/libp2p/go-libp2p/SECURITY.md
generated
vendored
Normal file
20
vendor/github.com/libp2p/go-libp2p/SECURITY.md
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
# Security Policy
|
||||
|
||||
go-libp2p is still in development. This means that there may be problems in our protocols,
|
||||
or there may be mistakes in our implementations.
|
||||
We take security vulnerabilities very seriously. If you discover a security issue,
|
||||
please bring it to our attention right away!
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you find a vulnerability that may affect live deployments -- for example, by exposing
|
||||
a remote execution exploit -- please [**report privately**](https://github.com/libp2p/go-libp2p/security/advisories/new).
|
||||
Please **DO NOT file a public issue**.
|
||||
|
||||
If the issue is an implementation weakness that cannot be immediately exploited or
|
||||
something not yet deployed, just discuss it openly.
|
||||
If you need assistance, please reach out to [security@libp2p.io](mailto:security@libp2p.io).
|
||||
|
||||
## Reporting a non security bug
|
||||
|
||||
For non-security bugs, please simply file a GitHub [issue](https://github.com/libp2p/go-libp2p/issues/new).
|
||||
498
vendor/github.com/libp2p/go-libp2p/config/config.go
generated
vendored
Normal file
498
vendor/github.com/libp2p/go-libp2p/config/config.go
generated
vendored
Normal file
@@ -0,0 +1,498 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/connmgr"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/event"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/metrics"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/peerstore"
|
||||
"github.com/libp2p/go-libp2p/core/pnet"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
"github.com/libp2p/go-libp2p/core/routing"
|
||||
"github.com/libp2p/go-libp2p/core/sec"
|
||||
"github.com/libp2p/go-libp2p/core/sec/insecure"
|
||||
"github.com/libp2p/go-libp2p/core/transport"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/autonat"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/autorelay"
|
||||
bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
|
||||
blankhost "github.com/libp2p/go-libp2p/p2p/host/blank"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem"
|
||||
rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
|
||||
routed "github.com/libp2p/go-libp2p/p2p/host/routed"
|
||||
"github.com/libp2p/go-libp2p/p2p/net/swarm"
|
||||
tptu "github.com/libp2p/go-libp2p/p2p/net/upgrader"
|
||||
circuitv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client"
|
||||
relayv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/holepunch"
|
||||
"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
madns "github.com/multiformats/go-multiaddr-dns"
|
||||
"go.uber.org/fx"
|
||||
"go.uber.org/fx/fxevent"
|
||||
)
|
||||
|
||||
// AddrsFactory is a function that takes a set of multiaddrs we're listening on and
|
||||
// returns the set of multiaddrs we should advertise to the network.
|
||||
type AddrsFactory = bhost.AddrsFactory
|
||||
|
||||
// NATManagerC is a NATManager constructor.
|
||||
type NATManagerC func(network.Network) bhost.NATManager
|
||||
|
||||
type RoutingC func(host.Host) (routing.PeerRouting, error)
|
||||
|
||||
// AutoNATConfig defines the AutoNAT behavior for the libp2p host.
|
||||
type AutoNATConfig struct {
|
||||
ForceReachability *network.Reachability
|
||||
EnableService bool
|
||||
ThrottleGlobalLimit int
|
||||
ThrottlePeerLimit int
|
||||
ThrottleInterval time.Duration
|
||||
}
|
||||
|
||||
type Security struct {
|
||||
ID protocol.ID
|
||||
Constructor interface{}
|
||||
}
|
||||
|
||||
// Config describes a set of settings for a libp2p node
|
||||
//
|
||||
// This is *not* a stable interface. Use the options defined in the root
|
||||
// package.
|
||||
type Config struct {
|
||||
// UserAgent is the identifier this node will send to other peers when
|
||||
// identifying itself, e.g. via the identify protocol.
|
||||
//
|
||||
// Set it via the UserAgent option function.
|
||||
UserAgent string
|
||||
|
||||
// ProtocolVersion is the protocol version that identifies the family
|
||||
// of protocols used by the peer in the Identify protocol. It is set
|
||||
// using the [ProtocolVersion] option.
|
||||
ProtocolVersion string
|
||||
|
||||
PeerKey crypto.PrivKey
|
||||
|
||||
QUICReuse []fx.Option
|
||||
Transports []fx.Option
|
||||
Muxers []tptu.StreamMuxer
|
||||
SecurityTransports []Security
|
||||
Insecure bool
|
||||
PSK pnet.PSK
|
||||
|
||||
DialTimeout time.Duration
|
||||
|
||||
RelayCustom bool
|
||||
Relay bool // should the relay transport be used
|
||||
|
||||
EnableRelayService bool // should we run a circuitv2 relay (if publicly reachable)
|
||||
RelayServiceOpts []relayv2.Option
|
||||
|
||||
ListenAddrs []ma.Multiaddr
|
||||
AddrsFactory bhost.AddrsFactory
|
||||
ConnectionGater connmgr.ConnectionGater
|
||||
|
||||
ConnManager connmgr.ConnManager
|
||||
ResourceManager network.ResourceManager
|
||||
|
||||
NATManager NATManagerC
|
||||
Peerstore peerstore.Peerstore
|
||||
Reporter metrics.Reporter
|
||||
|
||||
MultiaddrResolver *madns.Resolver
|
||||
|
||||
DisablePing bool
|
||||
|
||||
Routing RoutingC
|
||||
|
||||
EnableAutoRelay bool
|
||||
AutoRelayOpts []autorelay.Option
|
||||
AutoNATConfig
|
||||
|
||||
EnableHolePunching bool
|
||||
HolePunchingOptions []holepunch.Option
|
||||
|
||||
DisableMetrics bool
|
||||
PrometheusRegisterer prometheus.Registerer
|
||||
|
||||
DialRanker network.DialRanker
|
||||
|
||||
SwarmOpts []swarm.Option
|
||||
}
|
||||
|
||||
func (cfg *Config) makeSwarm(eventBus event.Bus, enableMetrics bool) (*swarm.Swarm, error) {
|
||||
if cfg.Peerstore == nil {
|
||||
return nil, fmt.Errorf("no peerstore specified")
|
||||
}
|
||||
|
||||
// Check this early. Prevents us from even *starting* without verifying this.
|
||||
if pnet.ForcePrivateNetwork && len(cfg.PSK) == 0 {
|
||||
log.Error("tried to create a libp2p node with no Private" +
|
||||
" Network Protector but usage of Private Networks" +
|
||||
" is forced by the environment")
|
||||
// Note: This is *also* checked the upgrader itself, so it'll be
|
||||
// enforced even *if* you don't use the libp2p constructor.
|
||||
return nil, pnet.ErrNotInPrivateNetwork
|
||||
}
|
||||
|
||||
if cfg.PeerKey == nil {
|
||||
return nil, fmt.Errorf("no peer key specified")
|
||||
}
|
||||
|
||||
// Obtain Peer ID from public key
|
||||
pid, err := peer.IDFromPublicKey(cfg.PeerKey.GetPublic())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := cfg.Peerstore.AddPrivKey(pid, cfg.PeerKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := cfg.Peerstore.AddPubKey(pid, cfg.PeerKey.GetPublic()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
opts := cfg.SwarmOpts
|
||||
if cfg.Reporter != nil {
|
||||
opts = append(opts, swarm.WithMetrics(cfg.Reporter))
|
||||
}
|
||||
if cfg.ConnectionGater != nil {
|
||||
opts = append(opts, swarm.WithConnectionGater(cfg.ConnectionGater))
|
||||
}
|
||||
if cfg.DialTimeout != 0 {
|
||||
opts = append(opts, swarm.WithDialTimeout(cfg.DialTimeout))
|
||||
}
|
||||
if cfg.ResourceManager != nil {
|
||||
opts = append(opts, swarm.WithResourceManager(cfg.ResourceManager))
|
||||
}
|
||||
if cfg.MultiaddrResolver != nil {
|
||||
opts = append(opts, swarm.WithMultiaddrResolver(cfg.MultiaddrResolver))
|
||||
}
|
||||
if cfg.DialRanker != nil {
|
||||
opts = append(opts, swarm.WithDialRanker(cfg.DialRanker))
|
||||
}
|
||||
|
||||
if enableMetrics {
|
||||
opts = append(opts,
|
||||
swarm.WithMetricsTracer(swarm.NewMetricsTracer(swarm.WithRegisterer(cfg.PrometheusRegisterer))))
|
||||
}
|
||||
// TODO: Make the swarm implementation configurable.
|
||||
return swarm.NewSwarm(pid, cfg.Peerstore, eventBus, opts...)
|
||||
}
|
||||
|
||||
func (cfg *Config) addTransports(h host.Host) error {
|
||||
swrm, ok := h.Network().(transport.TransportNetwork)
|
||||
if !ok {
|
||||
// Should probably skip this if no transports.
|
||||
return fmt.Errorf("swarm does not support transports")
|
||||
}
|
||||
|
||||
fxopts := []fx.Option{
|
||||
fx.WithLogger(func() fxevent.Logger { return getFXLogger() }),
|
||||
fx.Provide(fx.Annotate(tptu.New, fx.ParamTags(`name:"security"`))),
|
||||
fx.Supply(cfg.Muxers),
|
||||
fx.Supply(h.ID()),
|
||||
fx.Provide(func() host.Host { return h }),
|
||||
fx.Provide(func() crypto.PrivKey { return h.Peerstore().PrivKey(h.ID()) }),
|
||||
fx.Provide(func() connmgr.ConnectionGater { return cfg.ConnectionGater }),
|
||||
fx.Provide(func() pnet.PSK { return cfg.PSK }),
|
||||
fx.Provide(func() network.ResourceManager { return cfg.ResourceManager }),
|
||||
fx.Provide(func() *madns.Resolver { return cfg.MultiaddrResolver }),
|
||||
}
|
||||
fxopts = append(fxopts, cfg.Transports...)
|
||||
if cfg.Insecure {
|
||||
fxopts = append(fxopts,
|
||||
fx.Provide(
|
||||
fx.Annotate(
|
||||
func(id peer.ID, priv crypto.PrivKey) []sec.SecureTransport {
|
||||
return []sec.SecureTransport{insecure.NewWithIdentity(insecure.ID, id, priv)}
|
||||
},
|
||||
fx.ResultTags(`name:"security"`),
|
||||
),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
// fx groups are unordered, but we need to preserve the order of the security transports
|
||||
// First of all, we construct the security transports that are needed,
|
||||
// and save them to a group call security_unordered.
|
||||
for _, s := range cfg.SecurityTransports {
|
||||
fxName := fmt.Sprintf(`name:"security_%s"`, s.ID)
|
||||
fxopts = append(fxopts, fx.Supply(fx.Annotate(s.ID, fx.ResultTags(fxName))))
|
||||
fxopts = append(fxopts,
|
||||
fx.Provide(fx.Annotate(
|
||||
s.Constructor,
|
||||
fx.ParamTags(fxName),
|
||||
fx.As(new(sec.SecureTransport)),
|
||||
fx.ResultTags(`group:"security_unordered"`),
|
||||
)),
|
||||
)
|
||||
}
|
||||
// Then we consume the group security_unordered, and order them by the user's preference.
|
||||
fxopts = append(fxopts, fx.Provide(
|
||||
fx.Annotate(
|
||||
func(secs []sec.SecureTransport) ([]sec.SecureTransport, error) {
|
||||
if len(secs) != len(cfg.SecurityTransports) {
|
||||
return nil, errors.New("inconsistent length for security transports")
|
||||
}
|
||||
t := make([]sec.SecureTransport, 0, len(secs))
|
||||
for _, s := range cfg.SecurityTransports {
|
||||
for _, st := range secs {
|
||||
if s.ID != st.ID() {
|
||||
continue
|
||||
}
|
||||
t = append(t, st)
|
||||
}
|
||||
}
|
||||
return t, nil
|
||||
},
|
||||
fx.ParamTags(`group:"security_unordered"`),
|
||||
fx.ResultTags(`name:"security"`),
|
||||
)))
|
||||
}
|
||||
|
||||
fxopts = append(fxopts, fx.Provide(PrivKeyToStatelessResetKey))
|
||||
fxopts = append(fxopts, fx.Provide(PrivKeyToTokenGeneratorKey))
|
||||
if cfg.QUICReuse != nil {
|
||||
fxopts = append(fxopts, cfg.QUICReuse...)
|
||||
} else {
|
||||
fxopts = append(fxopts, fx.Provide(quicreuse.NewConnManager)) // TODO: close the ConnManager when shutting down the node
|
||||
}
|
||||
|
||||
fxopts = append(fxopts, fx.Invoke(
|
||||
fx.Annotate(
|
||||
func(tpts []transport.Transport) error {
|
||||
for _, t := range tpts {
|
||||
if err := swrm.AddTransport(t); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
fx.ParamTags(`group:"transport"`),
|
||||
)),
|
||||
)
|
||||
if cfg.Relay {
|
||||
fxopts = append(fxopts, fx.Invoke(circuitv2.AddTransport))
|
||||
}
|
||||
app := fx.New(fxopts...)
|
||||
if err := app.Err(); err != nil {
|
||||
h.Close()
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewNode constructs a new libp2p Host from the Config.
|
||||
//
|
||||
// This function consumes the config. Do not reuse it (really!).
|
||||
func (cfg *Config) NewNode() (host.Host, error) {
|
||||
// If possible check that the resource manager conn limit is higher than the
|
||||
// limit set in the conn manager.
|
||||
if l, ok := cfg.ResourceManager.(connmgr.GetConnLimiter); ok {
|
||||
err := cfg.ConnManager.CheckLimit(l)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("rcmgr limit conflicts with connmgr limit: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
eventBus := eventbus.NewBus(eventbus.WithMetricsTracer(eventbus.NewMetricsTracer(eventbus.WithRegisterer(cfg.PrometheusRegisterer))))
|
||||
swrm, err := cfg.makeSwarm(eventBus, !cfg.DisableMetrics)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !cfg.DisableMetrics {
|
||||
rcmgr.MustRegisterWith(cfg.PrometheusRegisterer)
|
||||
}
|
||||
|
||||
h, err := bhost.NewHost(swrm, &bhost.HostOpts{
|
||||
EventBus: eventBus,
|
||||
ConnManager: cfg.ConnManager,
|
||||
AddrsFactory: cfg.AddrsFactory,
|
||||
NATManager: cfg.NATManager,
|
||||
EnablePing: !cfg.DisablePing,
|
||||
UserAgent: cfg.UserAgent,
|
||||
ProtocolVersion: cfg.ProtocolVersion,
|
||||
EnableHolePunching: cfg.EnableHolePunching,
|
||||
HolePunchingOptions: cfg.HolePunchingOptions,
|
||||
EnableRelayService: cfg.EnableRelayService,
|
||||
RelayServiceOpts: cfg.RelayServiceOpts,
|
||||
EnableMetrics: !cfg.DisableMetrics,
|
||||
PrometheusRegisterer: cfg.PrometheusRegisterer,
|
||||
})
|
||||
if err != nil {
|
||||
swrm.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cfg.Relay {
|
||||
// If we've enabled the relay, we should filter out relay
|
||||
// addresses by default.
|
||||
//
|
||||
// TODO: We shouldn't be doing this here.
|
||||
oldFactory := h.AddrsFactory
|
||||
h.AddrsFactory = func(addrs []ma.Multiaddr) []ma.Multiaddr {
|
||||
return oldFactory(autorelay.Filter(addrs))
|
||||
}
|
||||
}
|
||||
|
||||
if err := cfg.addTransports(h); err != nil {
|
||||
h.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: This method succeeds if listening on one address succeeds. We
|
||||
// should probably fail if listening on *any* addr fails.
|
||||
if err := h.Network().Listen(cfg.ListenAddrs...); err != nil {
|
||||
h.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Configure routing and autorelay
|
||||
var router routing.PeerRouting
|
||||
if cfg.Routing != nil {
|
||||
router, err = cfg.Routing(h)
|
||||
if err != nil {
|
||||
h.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Note: h.AddrsFactory may be changed by relayFinder, but non-relay version is
|
||||
// used by AutoNAT below.
|
||||
var ar *autorelay.AutoRelay
|
||||
addrF := h.AddrsFactory
|
||||
if cfg.EnableAutoRelay {
|
||||
if !cfg.Relay {
|
||||
h.Close()
|
||||
return nil, fmt.Errorf("cannot enable autorelay; relay is not enabled")
|
||||
}
|
||||
if !cfg.DisableMetrics {
|
||||
mt := autorelay.WithMetricsTracer(
|
||||
autorelay.NewMetricsTracer(autorelay.WithRegisterer(cfg.PrometheusRegisterer)))
|
||||
mtOpts := []autorelay.Option{mt}
|
||||
cfg.AutoRelayOpts = append(mtOpts, cfg.AutoRelayOpts...)
|
||||
}
|
||||
|
||||
ar, err = autorelay.NewAutoRelay(h, cfg.AutoRelayOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
autonatOpts := []autonat.Option{
|
||||
autonat.UsingAddresses(func() []ma.Multiaddr {
|
||||
return addrF(h.AllAddrs())
|
||||
}),
|
||||
}
|
||||
if !cfg.DisableMetrics {
|
||||
autonatOpts = append(autonatOpts,
|
||||
autonat.WithMetricsTracer(
|
||||
autonat.NewMetricsTracer(autonat.WithRegisterer(cfg.PrometheusRegisterer))))
|
||||
}
|
||||
if cfg.AutoNATConfig.ThrottleInterval != 0 {
|
||||
autonatOpts = append(autonatOpts,
|
||||
autonat.WithThrottling(cfg.AutoNATConfig.ThrottleGlobalLimit, cfg.AutoNATConfig.ThrottleInterval),
|
||||
autonat.WithPeerThrottling(cfg.AutoNATConfig.ThrottlePeerLimit))
|
||||
}
|
||||
if cfg.AutoNATConfig.EnableService {
|
||||
autonatPrivKey, _, err := crypto.GenerateEd25519Key(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ps, err := pstoremem.NewPeerstore()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Pull out the pieces of the config that we _actually_ care about.
|
||||
// Specifically, don't set up things like autorelay, listeners,
|
||||
// identify, etc.
|
||||
autoNatCfg := Config{
|
||||
Transports: cfg.Transports,
|
||||
Muxers: cfg.Muxers,
|
||||
SecurityTransports: cfg.SecurityTransports,
|
||||
Insecure: cfg.Insecure,
|
||||
PSK: cfg.PSK,
|
||||
ConnectionGater: cfg.ConnectionGater,
|
||||
Reporter: cfg.Reporter,
|
||||
PeerKey: autonatPrivKey,
|
||||
Peerstore: ps,
|
||||
DialRanker: swarm.NoDelayDialRanker,
|
||||
SwarmOpts: []swarm.Option{
|
||||
// It is better to disable black hole detection and just attempt a dial for autonat
|
||||
swarm.WithUDPBlackHoleConfig(false, 0, 0),
|
||||
swarm.WithIPv6BlackHoleConfig(false, 0, 0),
|
||||
},
|
||||
}
|
||||
|
||||
dialer, err := autoNatCfg.makeSwarm(eventbus.NewBus(), false)
|
||||
if err != nil {
|
||||
h.Close()
|
||||
return nil, err
|
||||
}
|
||||
dialerHost := blankhost.NewBlankHost(dialer)
|
||||
if err := autoNatCfg.addTransports(dialerHost); err != nil {
|
||||
dialerHost.Close()
|
||||
h.Close()
|
||||
return nil, err
|
||||
}
|
||||
// NOTE: We're dropping the blank host here but that's fine. It
|
||||
// doesn't really _do_ anything and doesn't even need to be
|
||||
// closed (as long as we close the underlying network).
|
||||
autonatOpts = append(autonatOpts, autonat.EnableService(dialerHost.Network()))
|
||||
}
|
||||
if cfg.AutoNATConfig.ForceReachability != nil {
|
||||
autonatOpts = append(autonatOpts, autonat.WithReachability(*cfg.AutoNATConfig.ForceReachability))
|
||||
}
|
||||
|
||||
autonat, err := autonat.New(h, autonatOpts...)
|
||||
if err != nil {
|
||||
h.Close()
|
||||
return nil, fmt.Errorf("cannot enable autorelay; autonat failed to start: %v", err)
|
||||
}
|
||||
h.SetAutoNat(autonat)
|
||||
|
||||
// start the host background tasks
|
||||
h.Start()
|
||||
|
||||
var ho host.Host
|
||||
ho = h
|
||||
if router != nil {
|
||||
ho = routed.Wrap(h, router)
|
||||
}
|
||||
if ar != nil {
|
||||
arh := autorelay.NewAutoRelayHost(ho, ar)
|
||||
arh.Start()
|
||||
ho = arh
|
||||
}
|
||||
return ho, nil
|
||||
}
|
||||
|
||||
// Option is a libp2p config option that can be given to the libp2p constructor
|
||||
// (`libp2p.New`).
|
||||
type Option func(cfg *Config) error
|
||||
|
||||
// Apply applies the given options to the config, returning the first error
|
||||
// encountered (if any).
|
||||
func (cfg *Config) Apply(opts ...Option) error {
|
||||
for _, opt := range opts {
|
||||
if opt == nil {
|
||||
continue
|
||||
}
|
||||
if err := opt(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
28
vendor/github.com/libp2p/go-libp2p/config/log.go
generated
vendored
Normal file
28
vendor/github.com/libp2p/go-libp2p/config/log.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"go.uber.org/fx/fxevent"
|
||||
)
|
||||
|
||||
var log = logging.Logger("p2p-config")
|
||||
|
||||
var (
|
||||
fxLogger fxevent.Logger
|
||||
logInitOnce sync.Once
|
||||
)
|
||||
|
||||
type fxLogWriter struct{}
|
||||
|
||||
func (l *fxLogWriter) Write(b []byte) (int, error) {
|
||||
log.Debug(strings.TrimSuffix(string(b), "\n"))
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func getFXLogger() fxevent.Logger {
|
||||
logInitOnce.Do(func() { fxLogger = &fxevent.ConsoleLogger{W: &fxLogWriter{}} })
|
||||
return fxLogger
|
||||
}
|
||||
43
vendor/github.com/libp2p/go-libp2p/config/quic.go
generated
vendored
Normal file
43
vendor/github.com/libp2p/go-libp2p/config/quic.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"io"
|
||||
|
||||
"golang.org/x/crypto/hkdf"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
|
||||
"github.com/quic-go/quic-go"
|
||||
)
|
||||
|
||||
const (
|
||||
statelessResetKeyInfo = "libp2p quic stateless reset key"
|
||||
tokenGeneratorKeyInfo = "libp2p quic token generator key"
|
||||
)
|
||||
|
||||
func PrivKeyToStatelessResetKey(key crypto.PrivKey) (quic.StatelessResetKey, error) {
|
||||
var statelessResetKey quic.StatelessResetKey
|
||||
keyBytes, err := key.Raw()
|
||||
if err != nil {
|
||||
return statelessResetKey, err
|
||||
}
|
||||
keyReader := hkdf.New(sha256.New, keyBytes, nil, []byte(statelessResetKeyInfo))
|
||||
if _, err := io.ReadFull(keyReader, statelessResetKey[:]); err != nil {
|
||||
return statelessResetKey, err
|
||||
}
|
||||
return statelessResetKey, nil
|
||||
}
|
||||
|
||||
func PrivKeyToTokenGeneratorKey(key crypto.PrivKey) (quic.TokenGeneratorKey, error) {
|
||||
var tokenKey quic.TokenGeneratorKey
|
||||
keyBytes, err := key.Raw()
|
||||
if err != nil {
|
||||
return tokenKey, err
|
||||
}
|
||||
keyReader := hkdf.New(sha256.New, keyBytes, nil, []byte(tokenGeneratorKeyInfo))
|
||||
if _, err := io.ReadFull(keyReader, tokenKey[:]); err != nil {
|
||||
return tokenKey, err
|
||||
}
|
||||
return tokenKey, nil
|
||||
}
|
||||
57
vendor/github.com/libp2p/go-libp2p/core/canonicallog/canonicallog.go
generated
vendored
Normal file
57
vendor/github.com/libp2p/go-libp2p/core/canonicallog/canonicallog.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package canonicallog
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
)
|
||||
|
||||
var log = logging.WithSkip(logging.Logger("canonical-log"), 1)
|
||||
|
||||
// LogMisbehavingPeer is the canonical way to log a misbehaving peer.
|
||||
// Protocols should use this to identify a misbehaving peer to allow the end
|
||||
// user to easily identify these nodes across protocols and libp2p.
|
||||
func LogMisbehavingPeer(p peer.ID, peerAddr multiaddr.Multiaddr, component string, err error, msg string) {
|
||||
log.Warnf("CANONICAL_MISBEHAVING_PEER: peer=%s addr=%s component=%s err=%q msg=%q", p, peerAddr.String(), component, err, msg)
|
||||
}
|
||||
|
||||
// LogMisbehavingPeerNetAddr is the canonical way to log a misbehaving peer.
|
||||
// Protocols should use this to identify a misbehaving peer to allow the end
|
||||
// user to easily identify these nodes across protocols and libp2p.
|
||||
func LogMisbehavingPeerNetAddr(p peer.ID, peerAddr net.Addr, component string, originalErr error, msg string) {
|
||||
ma, err := manet.FromNetAddr(peerAddr)
|
||||
if err != nil {
|
||||
log.Warnf("CANONICAL_MISBEHAVING_PEER: peer=%s net_addr=%s component=%s err=%q msg=%q", p, peerAddr.String(), component, originalErr, msg)
|
||||
return
|
||||
}
|
||||
|
||||
LogMisbehavingPeer(p, ma, component, originalErr, msg)
|
||||
}
|
||||
|
||||
// LogPeerStatus logs any useful information about a peer. It takes in a sample
|
||||
// rate and will only log one in every sampleRate messages (randomly). This is
|
||||
// useful in surfacing events that are normal in isolation, but may be abnormal
|
||||
// in large quantities. For example, a successful connection from an IP address
|
||||
// is normal. 10,000 connections from that same IP address is not normal. libp2p
|
||||
// itself does nothing besides emitting this log. Hook this up to another tool
|
||||
// like fail2ban to action on the log.
|
||||
func LogPeerStatus(sampleRate int, p peer.ID, peerAddr multiaddr.Multiaddr, keyVals ...string) {
|
||||
if rand.Intn(sampleRate) == 0 {
|
||||
keyValsStr := strings.Builder{}
|
||||
for i, kOrV := range keyVals {
|
||||
if i%2 == 0 {
|
||||
fmt.Fprintf(&keyValsStr, " %v=", kOrV)
|
||||
} else {
|
||||
fmt.Fprintf(&keyValsStr, "%q", kOrV)
|
||||
}
|
||||
}
|
||||
log.Infof("CANONICAL_PEER_STATUS: peer=%s addr=%s sample_rate=%v%s", p, peerAddr.String(), sampleRate, keyValsStr.String())
|
||||
}
|
||||
}
|
||||
109
vendor/github.com/libp2p/go-libp2p/core/connmgr/decay.go
generated
vendored
Normal file
109
vendor/github.com/libp2p/go-libp2p/core/connmgr/decay.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
package connmgr
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
|
||||
// Decayer is implemented by connection managers supporting decaying tags. A
|
||||
// decaying tag is one whose value automatically decays over time.
|
||||
//
|
||||
// The actual application of the decay behaviour is encapsulated in a
|
||||
// user-provided decaying function (DecayFn). The function is called on every
|
||||
// tick (determined by the interval parameter), and returns either the new value
|
||||
// of the tag, or whether it should be erased altogether.
|
||||
//
|
||||
// We do not set values on a decaying tag. Rather, we "bump" decaying tags by a
|
||||
// delta. This calls the BumpFn with the old value and the delta, to determine
|
||||
// the new value.
|
||||
//
|
||||
// Such a pluggable design affords a great deal of flexibility and versatility.
|
||||
// Behaviours that are straightforward to implement include:
|
||||
//
|
||||
// - Decay a tag by -1, or by half its current value, on every tick.
|
||||
// - Every time a value is bumped, sum it to its current value.
|
||||
// - Exponentially boost a score with every bump.
|
||||
// - Sum the incoming score, but keep it within min, max bounds.
|
||||
//
|
||||
// Commonly used DecayFns and BumpFns are provided in this package.
|
||||
type Decayer interface {
|
||||
io.Closer
|
||||
|
||||
// RegisterDecayingTag creates and registers a new decaying tag, if and only
|
||||
// if a tag with the supplied name doesn't exist yet. Otherwise, an error is
|
||||
// returned.
|
||||
//
|
||||
// The caller provides the interval at which the tag is refreshed, as well
|
||||
// as the decay function and the bump function. Refer to godocs on DecayFn
|
||||
// and BumpFn for more info.
|
||||
RegisterDecayingTag(name string, interval time.Duration, decayFn DecayFn, bumpFn BumpFn) (DecayingTag, error)
|
||||
}
|
||||
|
||||
// DecayFn applies a decay to the peer's score. The implementation must call
|
||||
// DecayFn at the interval supplied when registering the tag.
|
||||
//
|
||||
// It receives a copy of the decaying value, and returns the score after
|
||||
// applying the decay, as well as a flag to signal if the tag should be erased.
|
||||
type DecayFn func(value DecayingValue) (after int, rm bool)
|
||||
|
||||
// BumpFn applies a delta onto an existing score, and returns the new score.
|
||||
//
|
||||
// Non-trivial bump functions include exponential boosting, moving averages,
|
||||
// ceilings, etc.
|
||||
type BumpFn func(value DecayingValue, delta int) (after int)
|
||||
|
||||
// DecayingTag represents a decaying tag. The tag is a long-lived general
|
||||
// object, used to operate on tag values for peers.
|
||||
type DecayingTag interface {
|
||||
// Name returns the name of the tag.
|
||||
Name() string
|
||||
|
||||
// Interval is the effective interval at which this tag will tick. Upon
|
||||
// registration, the desired interval may be overwritten depending on the
|
||||
// decayer's resolution, and this method allows you to obtain the effective
|
||||
// interval.
|
||||
Interval() time.Duration
|
||||
|
||||
// Bump applies a delta to a tag value, calling its bump function. The bump
|
||||
// will be applied asynchronously, and a non-nil error indicates a fault
|
||||
// when queuing.
|
||||
Bump(peer peer.ID, delta int) error
|
||||
|
||||
// Remove removes a decaying tag from a peer. The removal will be applied
|
||||
// asynchronously, and a non-nil error indicates a fault when queuing.
|
||||
Remove(peer peer.ID) error
|
||||
|
||||
// Close closes a decaying tag. The Decayer will stop tracking this tag,
|
||||
// and the state of all peers in the Connection Manager holding this tag
|
||||
// will be updated.
|
||||
//
|
||||
// The deletion is performed asynchronously.
|
||||
//
|
||||
// Once deleted, a tag should not be used, and further calls to Bump/Remove
|
||||
// will error.
|
||||
//
|
||||
// Duplicate calls to Remove will not return errors, but a failure to queue
|
||||
// the first actual removal, will (e.g. when the system is backlogged).
|
||||
Close() error
|
||||
}
|
||||
|
||||
// DecayingValue represents a value for a decaying tag.
|
||||
type DecayingValue struct {
|
||||
// Tag points to the tag this value belongs to.
|
||||
Tag DecayingTag
|
||||
|
||||
// Peer is the peer ID to whom this value is associated.
|
||||
Peer peer.ID
|
||||
|
||||
// Added is the timestamp when this value was added for the first time for
|
||||
// a tag and a peer.
|
||||
Added time.Time
|
||||
|
||||
// LastVisit is the timestamp of the last visit.
|
||||
LastVisit time.Time
|
||||
|
||||
// Value is the current value of the tag.
|
||||
Value int
|
||||
}
|
||||
89
vendor/github.com/libp2p/go-libp2p/core/connmgr/gater.go
generated
vendored
Normal file
89
vendor/github.com/libp2p/go-libp2p/core/connmgr/gater.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
package connmgr
|
||||
|
||||
import (
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/control"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
|
||||
// ConnectionGater can be implemented by a type that supports active
|
||||
// inbound or outbound connection gating.
|
||||
//
|
||||
// ConnectionGaters are active, whereas ConnManagers tend to be passive.
|
||||
//
|
||||
// A ConnectionGater will be consulted during different states in the lifecycle
|
||||
// of a connection being established/upgraded. Specific functions will be called
|
||||
// throughout the process, to allow you to intercept the connection at that stage.
|
||||
//
|
||||
// InterceptPeerDial is called on an imminent outbound peer dial request, prior
|
||||
// to the addresses of that peer being available/resolved. Blocking connections
|
||||
// at this stage is typical for blacklisting scenarios.
|
||||
//
|
||||
// InterceptAddrDial is called on an imminent outbound dial to a peer on a
|
||||
// particular address. Blocking connections at this stage is typical for
|
||||
// address filtering.
|
||||
//
|
||||
// InterceptAccept is called as soon as a transport listener receives an
|
||||
// inbound connection request, before any upgrade takes place. Transports who
|
||||
// accept already secure and/or multiplexed connections (e.g. possibly QUIC)
|
||||
// MUST call this method regardless, for correctness/consistency.
|
||||
//
|
||||
// InterceptSecured is called for both inbound and outbound connections,
|
||||
// after a security handshake has taken place and we've authenticated the peer.
|
||||
//
|
||||
// InterceptUpgraded is called for inbound and outbound connections, after
|
||||
// libp2p has finished upgrading the connection entirely to a secure,
|
||||
// multiplexed channel.
|
||||
//
|
||||
// This interface can be used to implement *strict/active* connection management
|
||||
// policies, such as hard limiting of connections once a maximum count has been
|
||||
// reached, maintaining a peer blacklist, or limiting connections by transport
|
||||
// quotas.
|
||||
//
|
||||
// EXPERIMENTAL: a DISCONNECT protocol/message will be supported in the future.
|
||||
// This allows gaters and other components to communicate the intention behind
|
||||
// a connection closure, to curtail potential reconnection attempts.
|
||||
//
|
||||
// For now, InterceptUpgraded can return a non-zero DisconnectReason when
|
||||
// blocking a connection, but this interface is likely to change in the future
|
||||
// as we solidify this feature. The reason why only this method can handle
|
||||
// DisconnectReasons is that we require stream multiplexing capability to open a
|
||||
// control protocol stream to transmit the message.
|
||||
type ConnectionGater interface {
|
||||
// InterceptPeerDial tests whether we're permitted to Dial the specified peer.
|
||||
//
|
||||
// This is called by the network.Network implementation when dialling a peer.
|
||||
InterceptPeerDial(p peer.ID) (allow bool)
|
||||
|
||||
// InterceptAddrDial tests whether we're permitted to dial the specified
|
||||
// multiaddr for the given peer.
|
||||
//
|
||||
// This is called by the network.Network implementation after it has
|
||||
// resolved the peer's addrs, and prior to dialling each.
|
||||
InterceptAddrDial(peer.ID, ma.Multiaddr) (allow bool)
|
||||
|
||||
// InterceptAccept tests whether an incipient inbound connection is allowed.
|
||||
//
|
||||
// This is called by the upgrader, or by the transport directly (e.g. QUIC,
|
||||
// Bluetooth), straight after it has accepted a connection from its socket.
|
||||
InterceptAccept(network.ConnMultiaddrs) (allow bool)
|
||||
|
||||
// InterceptSecured tests whether a given connection, now authenticated,
|
||||
// is allowed.
|
||||
//
|
||||
// This is called by the upgrader, after it has performed the security
|
||||
// handshake, and before it negotiates the muxer, or by the directly by the
|
||||
// transport, at the exact same checkpoint.
|
||||
InterceptSecured(network.Direction, peer.ID, network.ConnMultiaddrs) (allow bool)
|
||||
|
||||
// InterceptUpgraded tests whether a fully capable connection is allowed.
|
||||
//
|
||||
// At this point, the connection a multiplexer has been selected.
|
||||
// When rejecting a connection, the gater can return a DisconnectReason.
|
||||
// Refer to the godoc on the ConnectionGater type for more information.
|
||||
//
|
||||
// NOTE: the go-libp2p implementation currently IGNORES the disconnect reason.
|
||||
InterceptUpgraded(network.Conn) (allow bool, reason control.DisconnectReason)
|
||||
}
|
||||
101
vendor/github.com/libp2p/go-libp2p/core/connmgr/manager.go
generated
vendored
Normal file
101
vendor/github.com/libp2p/go-libp2p/core/connmgr/manager.go
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
// Package connmgr provides connection tracking and management interfaces for libp2p.
|
||||
//
|
||||
// The ConnManager interface exported from this package allows libp2p to enforce an
|
||||
// upper bound on the total number of open connections. To avoid service disruptions,
|
||||
// connections can be tagged with metadata and optionally "protected" to ensure that
|
||||
// essential connections are not arbitrarily cut.
|
||||
package connmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
|
||||
// SupportsDecay evaluates if the provided ConnManager supports decay, and if
|
||||
// so, it returns the Decayer object. Refer to godocs on Decayer for more info.
|
||||
func SupportsDecay(mgr ConnManager) (Decayer, bool) {
|
||||
d, ok := mgr.(Decayer)
|
||||
return d, ok
|
||||
}
|
||||
|
||||
// ConnManager tracks connections to peers, and allows consumers to associate
|
||||
// metadata with each peer.
|
||||
//
|
||||
// It enables connections to be trimmed based on implementation-defined
|
||||
// heuristics. The ConnManager allows libp2p to enforce an upper bound on the
|
||||
// total number of open connections.
|
||||
//
|
||||
// ConnManagers supporting decaying tags implement Decayer. Use the
|
||||
// SupportsDecay function to safely cast an instance to Decayer, if supported.
|
||||
type ConnManager interface {
|
||||
// TagPeer tags a peer with a string, associating a weight with the tag.
|
||||
TagPeer(peer.ID, string, int)
|
||||
|
||||
// Untag removes the tagged value from the peer.
|
||||
UntagPeer(p peer.ID, tag string)
|
||||
|
||||
// UpsertTag updates an existing tag or inserts a new one.
|
||||
//
|
||||
// The connection manager calls the upsert function supplying the current
|
||||
// value of the tag (or zero if inexistent). The return value is used as
|
||||
// the new value of the tag.
|
||||
UpsertTag(p peer.ID, tag string, upsert func(int) int)
|
||||
|
||||
// GetTagInfo returns the metadata associated with the peer,
|
||||
// or nil if no metadata has been recorded for the peer.
|
||||
GetTagInfo(p peer.ID) *TagInfo
|
||||
|
||||
// TrimOpenConns terminates open connections based on an implementation-defined
|
||||
// heuristic.
|
||||
TrimOpenConns(ctx context.Context)
|
||||
|
||||
// Notifee returns an implementation that can be called back to inform of
|
||||
// opened and closed connections.
|
||||
Notifee() network.Notifiee
|
||||
|
||||
// Protect protects a peer from having its connection(s) pruned.
|
||||
//
|
||||
// Tagging allows different parts of the system to manage protections without interfering with one another.
|
||||
//
|
||||
// Calls to Protect() with the same tag are idempotent. They are not refcounted, so after multiple calls
|
||||
// to Protect() with the same tag, a single Unprotect() call bearing the same tag will revoke the protection.
|
||||
Protect(id peer.ID, tag string)
|
||||
|
||||
// Unprotect removes a protection that may have been placed on a peer, under the specified tag.
|
||||
//
|
||||
// The return value indicates whether the peer continues to be protected after this call, by way of a different tag.
|
||||
// See notes on Protect() for more info.
|
||||
Unprotect(id peer.ID, tag string) (protected bool)
|
||||
|
||||
// IsProtected returns true if the peer is protected for some tag; if the tag is the empty string
|
||||
// then it will return true if the peer is protected for any tag
|
||||
IsProtected(id peer.ID, tag string) (protected bool)
|
||||
|
||||
// CheckLimit will return an error if the connection manager's internal
|
||||
// connection limit exceeds the provided system limit.
|
||||
CheckLimit(l GetConnLimiter) error
|
||||
|
||||
// Close closes the connection manager and stops background processes.
|
||||
Close() error
|
||||
}
|
||||
|
||||
// TagInfo stores metadata associated with a peer.
|
||||
type TagInfo struct {
|
||||
FirstSeen time.Time
|
||||
Value int
|
||||
|
||||
// Tags maps tag ids to the numerical values.
|
||||
Tags map[string]int
|
||||
|
||||
// Conns maps connection ids (such as remote multiaddr) to their creation time.
|
||||
Conns map[string]time.Time
|
||||
}
|
||||
|
||||
// GetConnLimiter provides access to a component's total connection limit.
|
||||
type GetConnLimiter interface {
|
||||
// GetConnLimit returns the total connection limit of the implementing component.
|
||||
GetConnLimit() int
|
||||
}
|
||||
25
vendor/github.com/libp2p/go-libp2p/core/connmgr/null.go
generated
vendored
Normal file
25
vendor/github.com/libp2p/go-libp2p/core/connmgr/null.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package connmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
|
||||
// NullConnMgr is a ConnMgr that provides no functionality.
|
||||
type NullConnMgr struct{}
|
||||
|
||||
var _ ConnManager = (*NullConnMgr)(nil)
|
||||
|
||||
func (NullConnMgr) TagPeer(peer.ID, string, int) {}
|
||||
func (NullConnMgr) UntagPeer(peer.ID, string) {}
|
||||
func (NullConnMgr) UpsertTag(peer.ID, string, func(int) int) {}
|
||||
func (NullConnMgr) GetTagInfo(peer.ID) *TagInfo { return &TagInfo{} }
|
||||
func (NullConnMgr) TrimOpenConns(ctx context.Context) {}
|
||||
func (NullConnMgr) Notifee() network.Notifiee { return network.GlobalNoopNotifiee }
|
||||
func (NullConnMgr) Protect(peer.ID, string) {}
|
||||
func (NullConnMgr) Unprotect(peer.ID, string) bool { return false }
|
||||
func (NullConnMgr) IsProtected(peer.ID, string) bool { return false }
|
||||
func (NullConnMgr) CheckLimit(l GetConnLimiter) error { return nil }
|
||||
func (NullConnMgr) Close() error { return nil }
|
||||
67
vendor/github.com/libp2p/go-libp2p/core/connmgr/presets.go
generated
vendored
Normal file
67
vendor/github.com/libp2p/go-libp2p/core/connmgr/presets.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package connmgr
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DecayNone applies no decay.
|
||||
func DecayNone() DecayFn {
|
||||
return func(value DecayingValue) (_ int, rm bool) {
|
||||
return value.Value, false
|
||||
}
|
||||
}
|
||||
|
||||
// DecayFixed subtracts from by the provided minuend, and deletes the tag when
|
||||
// first reaching 0 or negative.
|
||||
func DecayFixed(minuend int) DecayFn {
|
||||
return func(value DecayingValue) (_ int, rm bool) {
|
||||
v := value.Value - minuend
|
||||
return v, v <= 0
|
||||
}
|
||||
}
|
||||
|
||||
// DecayLinear applies a fractional coefficient to the value of the current tag,
|
||||
// rounding down via math.Floor. It erases the tag when the result is zero.
|
||||
func DecayLinear(coef float64) DecayFn {
|
||||
return func(value DecayingValue) (after int, rm bool) {
|
||||
v := math.Floor(float64(value.Value) * coef)
|
||||
return int(v), v <= 0
|
||||
}
|
||||
}
|
||||
|
||||
// DecayExpireWhenInactive expires a tag after a certain period of no bumps.
|
||||
func DecayExpireWhenInactive(after time.Duration) DecayFn {
|
||||
return func(value DecayingValue) (_ int, rm bool) {
|
||||
rm = time.Until(value.LastVisit) >= after
|
||||
return 0, rm
|
||||
}
|
||||
}
|
||||
|
||||
// BumpSumUnbounded adds the incoming value to the peer's score.
|
||||
func BumpSumUnbounded() BumpFn {
|
||||
return func(value DecayingValue, delta int) (after int) {
|
||||
return value.Value + delta
|
||||
}
|
||||
}
|
||||
|
||||
// BumpSumBounded keeps summing the incoming score, keeping it within a
|
||||
// [min, max] range.
|
||||
func BumpSumBounded(min, max int) BumpFn {
|
||||
return func(value DecayingValue, delta int) (after int) {
|
||||
v := value.Value + delta
|
||||
if v >= max {
|
||||
return max
|
||||
} else if v <= min {
|
||||
return min
|
||||
}
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
// BumpOverwrite replaces the current value of the tag with the incoming one.
|
||||
func BumpOverwrite() BumpFn {
|
||||
return func(value DecayingValue, delta int) (after int) {
|
||||
return delta
|
||||
}
|
||||
}
|
||||
9
vendor/github.com/libp2p/go-libp2p/core/control/disconnect.go
generated
vendored
Normal file
9
vendor/github.com/libp2p/go-libp2p/core/control/disconnect.go
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package control
|
||||
|
||||
// DisconnectReason communicates the reason why a connection is being closed.
|
||||
//
|
||||
// A zero value stands for "no reason" / NA.
|
||||
//
|
||||
// This is an EXPERIMENTAL type. It will change in the future. Refer to the
|
||||
// connmgr.ConnectionGater godoc for more info.
|
||||
type DisconnectReason int
|
||||
186
vendor/github.com/libp2p/go-libp2p/core/crypto/ecdsa.go
generated
vendored
Normal file
186
vendor/github.com/libp2p/go-libp2p/core/crypto/ecdsa.go
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
pb "github.com/libp2p/go-libp2p/core/crypto/pb"
|
||||
"github.com/libp2p/go-libp2p/core/internal/catch"
|
||||
"github.com/libp2p/go-libp2p/internal/sha256"
|
||||
)
|
||||
|
||||
// ECDSAPrivateKey is an implementation of an ECDSA private key
|
||||
type ECDSAPrivateKey struct {
|
||||
priv *ecdsa.PrivateKey
|
||||
}
|
||||
|
||||
// ECDSAPublicKey is an implementation of an ECDSA public key
|
||||
type ECDSAPublicKey struct {
|
||||
pub *ecdsa.PublicKey
|
||||
}
|
||||
|
||||
// ECDSASig holds the r and s values of an ECDSA signature
|
||||
type ECDSASig struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrNotECDSAPubKey is returned when the public key passed is not an ecdsa public key
|
||||
ErrNotECDSAPubKey = errors.New("not an ecdsa public key")
|
||||
// ErrNilSig is returned when the signature is nil
|
||||
ErrNilSig = errors.New("sig is nil")
|
||||
// ErrNilPrivateKey is returned when a nil private key is provided
|
||||
ErrNilPrivateKey = errors.New("private key is nil")
|
||||
// ErrNilPublicKey is returned when a nil public key is provided
|
||||
ErrNilPublicKey = errors.New("public key is nil")
|
||||
// ECDSACurve is the default ecdsa curve used
|
||||
ECDSACurve = elliptic.P256()
|
||||
)
|
||||
|
||||
// GenerateECDSAKeyPair generates a new ecdsa private and public key
|
||||
func GenerateECDSAKeyPair(src io.Reader) (PrivKey, PubKey, error) {
|
||||
return GenerateECDSAKeyPairWithCurve(ECDSACurve, src)
|
||||
}
|
||||
|
||||
// GenerateECDSAKeyPairWithCurve generates a new ecdsa private and public key with a specified curve
|
||||
func GenerateECDSAKeyPairWithCurve(curve elliptic.Curve, src io.Reader) (PrivKey, PubKey, error) {
|
||||
priv, err := ecdsa.GenerateKey(curve, src)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &ECDSAPrivateKey{priv}, &ECDSAPublicKey{&priv.PublicKey}, nil
|
||||
}
|
||||
|
||||
// ECDSAKeyPairFromKey generates a new ecdsa private and public key from an input private key
|
||||
func ECDSAKeyPairFromKey(priv *ecdsa.PrivateKey) (PrivKey, PubKey, error) {
|
||||
if priv == nil {
|
||||
return nil, nil, ErrNilPrivateKey
|
||||
}
|
||||
|
||||
return &ECDSAPrivateKey{priv}, &ECDSAPublicKey{&priv.PublicKey}, nil
|
||||
}
|
||||
|
||||
// ECDSAPublicKeyFromPubKey generates a new ecdsa public key from an input public key
|
||||
func ECDSAPublicKeyFromPubKey(pub ecdsa.PublicKey) (PubKey, error) {
|
||||
return &ECDSAPublicKey{pub: &pub}, nil
|
||||
}
|
||||
|
||||
// MarshalECDSAPrivateKey returns x509 bytes from a private key
|
||||
func MarshalECDSAPrivateKey(ePriv ECDSAPrivateKey) (res []byte, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "ECDSA private-key marshal") }()
|
||||
return x509.MarshalECPrivateKey(ePriv.priv)
|
||||
}
|
||||
|
||||
// MarshalECDSAPublicKey returns x509 bytes from a public key
|
||||
func MarshalECDSAPublicKey(ePub ECDSAPublicKey) (res []byte, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "ECDSA public-key marshal") }()
|
||||
return x509.MarshalPKIXPublicKey(ePub.pub)
|
||||
}
|
||||
|
||||
// UnmarshalECDSAPrivateKey returns a private key from x509 bytes
|
||||
func UnmarshalECDSAPrivateKey(data []byte) (res PrivKey, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "ECDSA private-key unmarshal") }()
|
||||
|
||||
priv, err := x509.ParseECPrivateKey(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ECDSAPrivateKey{priv}, nil
|
||||
}
|
||||
|
||||
// UnmarshalECDSAPublicKey returns the public key from x509 bytes
|
||||
func UnmarshalECDSAPublicKey(data []byte) (key PubKey, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "ECDSA public-key unmarshal") }()
|
||||
|
||||
pubIfc, err := x509.ParsePKIXPublicKey(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pub, ok := pubIfc.(*ecdsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, ErrNotECDSAPubKey
|
||||
}
|
||||
|
||||
return &ECDSAPublicKey{pub}, nil
|
||||
}
|
||||
|
||||
// Type returns the key type
|
||||
func (ePriv *ECDSAPrivateKey) Type() pb.KeyType {
|
||||
return pb.KeyType_ECDSA
|
||||
}
|
||||
|
||||
// Raw returns x509 bytes from a private key
|
||||
func (ePriv *ECDSAPrivateKey) Raw() (res []byte, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "ECDSA private-key marshal") }()
|
||||
return x509.MarshalECPrivateKey(ePriv.priv)
|
||||
}
|
||||
|
||||
// Equals compares two private keys
|
||||
func (ePriv *ECDSAPrivateKey) Equals(o Key) bool {
|
||||
return basicEquals(ePriv, o)
|
||||
}
|
||||
|
||||
// Sign returns the signature of the input data
|
||||
func (ePriv *ECDSAPrivateKey) Sign(data []byte) (sig []byte, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "ECDSA signing") }()
|
||||
hash := sha256.Sum256(data)
|
||||
r, s, err := ecdsa.Sign(rand.Reader, ePriv.priv, hash[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return asn1.Marshal(ECDSASig{
|
||||
R: r,
|
||||
S: s,
|
||||
})
|
||||
}
|
||||
|
||||
// GetPublic returns a public key
|
||||
func (ePriv *ECDSAPrivateKey) GetPublic() PubKey {
|
||||
return &ECDSAPublicKey{&ePriv.priv.PublicKey}
|
||||
}
|
||||
|
||||
// Type returns the key type
|
||||
func (ePub *ECDSAPublicKey) Type() pb.KeyType {
|
||||
return pb.KeyType_ECDSA
|
||||
}
|
||||
|
||||
// Raw returns x509 bytes from a public key
|
||||
func (ePub *ECDSAPublicKey) Raw() ([]byte, error) {
|
||||
return x509.MarshalPKIXPublicKey(ePub.pub)
|
||||
}
|
||||
|
||||
// Equals compares to public keys
|
||||
func (ePub *ECDSAPublicKey) Equals(o Key) bool {
|
||||
return basicEquals(ePub, o)
|
||||
}
|
||||
|
||||
// Verify compares data to a signature
|
||||
func (ePub *ECDSAPublicKey) Verify(data, sigBytes []byte) (success bool, err error) {
|
||||
defer func() {
|
||||
catch.HandlePanic(recover(), &err, "ECDSA signature verification")
|
||||
|
||||
// Just to be extra paranoid.
|
||||
if err != nil {
|
||||
success = false
|
||||
}
|
||||
}()
|
||||
|
||||
sig := new(ECDSASig)
|
||||
if _, err := asn1.Unmarshal(sigBytes, sig); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
hash := sha256.Sum256(data)
|
||||
|
||||
return ecdsa.Verify(ePub.pub, hash[:], sig.R, sig.S), nil
|
||||
}
|
||||
156
vendor/github.com/libp2p/go-libp2p/core/crypto/ed25519.go
generated
vendored
Normal file
156
vendor/github.com/libp2p/go-libp2p/core/crypto/ed25519.go
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
pb "github.com/libp2p/go-libp2p/core/crypto/pb"
|
||||
"github.com/libp2p/go-libp2p/core/internal/catch"
|
||||
)
|
||||
|
||||
// Ed25519PrivateKey is an ed25519 private key.
|
||||
type Ed25519PrivateKey struct {
|
||||
k ed25519.PrivateKey
|
||||
}
|
||||
|
||||
// Ed25519PublicKey is an ed25519 public key.
|
||||
type Ed25519PublicKey struct {
|
||||
k ed25519.PublicKey
|
||||
}
|
||||
|
||||
// GenerateEd25519Key generates a new ed25519 private and public key pair.
|
||||
func GenerateEd25519Key(src io.Reader) (PrivKey, PubKey, error) {
|
||||
pub, priv, err := ed25519.GenerateKey(src)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &Ed25519PrivateKey{
|
||||
k: priv,
|
||||
},
|
||||
&Ed25519PublicKey{
|
||||
k: pub,
|
||||
},
|
||||
nil
|
||||
}
|
||||
|
||||
// Type of the private key (Ed25519).
|
||||
func (k *Ed25519PrivateKey) Type() pb.KeyType {
|
||||
return pb.KeyType_Ed25519
|
||||
}
|
||||
|
||||
// Raw private key bytes.
|
||||
func (k *Ed25519PrivateKey) Raw() ([]byte, error) {
|
||||
// The Ed25519 private key contains two 32-bytes curve points, the private
|
||||
// key and the public key.
|
||||
// It makes it more efficient to get the public key without re-computing an
|
||||
// elliptic curve multiplication.
|
||||
buf := make([]byte, len(k.k))
|
||||
copy(buf, k.k)
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (k *Ed25519PrivateKey) pubKeyBytes() []byte {
|
||||
return k.k[ed25519.PrivateKeySize-ed25519.PublicKeySize:]
|
||||
}
|
||||
|
||||
// Equals compares two ed25519 private keys.
|
||||
func (k *Ed25519PrivateKey) Equals(o Key) bool {
|
||||
edk, ok := o.(*Ed25519PrivateKey)
|
||||
if !ok {
|
||||
return basicEquals(k, o)
|
||||
}
|
||||
|
||||
return subtle.ConstantTimeCompare(k.k, edk.k) == 1
|
||||
}
|
||||
|
||||
// GetPublic returns an ed25519 public key from a private key.
|
||||
func (k *Ed25519PrivateKey) GetPublic() PubKey {
|
||||
return &Ed25519PublicKey{k: k.pubKeyBytes()}
|
||||
}
|
||||
|
||||
// Sign returns a signature from an input message.
|
||||
func (k *Ed25519PrivateKey) Sign(msg []byte) (res []byte, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "ed15519 signing") }()
|
||||
|
||||
return ed25519.Sign(k.k, msg), nil
|
||||
}
|
||||
|
||||
// Type of the public key (Ed25519).
|
||||
func (k *Ed25519PublicKey) Type() pb.KeyType {
|
||||
return pb.KeyType_Ed25519
|
||||
}
|
||||
|
||||
// Raw public key bytes.
|
||||
func (k *Ed25519PublicKey) Raw() ([]byte, error) {
|
||||
return k.k, nil
|
||||
}
|
||||
|
||||
// Equals compares two ed25519 public keys.
|
||||
func (k *Ed25519PublicKey) Equals(o Key) bool {
|
||||
edk, ok := o.(*Ed25519PublicKey)
|
||||
if !ok {
|
||||
return basicEquals(k, o)
|
||||
}
|
||||
|
||||
return bytes.Equal(k.k, edk.k)
|
||||
}
|
||||
|
||||
// Verify checks a signature against the input data.
|
||||
func (k *Ed25519PublicKey) Verify(data []byte, sig []byte) (success bool, err error) {
|
||||
defer func() {
|
||||
catch.HandlePanic(recover(), &err, "ed15519 signature verification")
|
||||
|
||||
// To be safe.
|
||||
if err != nil {
|
||||
success = false
|
||||
}
|
||||
}()
|
||||
return ed25519.Verify(k.k, data, sig), nil
|
||||
}
|
||||
|
||||
// UnmarshalEd25519PublicKey returns a public key from input bytes.
|
||||
func UnmarshalEd25519PublicKey(data []byte) (PubKey, error) {
|
||||
if len(data) != 32 {
|
||||
return nil, errors.New("expect ed25519 public key data size to be 32")
|
||||
}
|
||||
|
||||
return &Ed25519PublicKey{
|
||||
k: ed25519.PublicKey(data),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UnmarshalEd25519PrivateKey returns a private key from input bytes.
|
||||
func UnmarshalEd25519PrivateKey(data []byte) (PrivKey, error) {
|
||||
switch len(data) {
|
||||
case ed25519.PrivateKeySize + ed25519.PublicKeySize:
|
||||
// Remove the redundant public key. See issue #36.
|
||||
redundantPk := data[ed25519.PrivateKeySize:]
|
||||
pk := data[ed25519.PrivateKeySize-ed25519.PublicKeySize : ed25519.PrivateKeySize]
|
||||
if subtle.ConstantTimeCompare(pk, redundantPk) == 0 {
|
||||
return nil, errors.New("expected redundant ed25519 public key to be redundant")
|
||||
}
|
||||
|
||||
// No point in storing the extra data.
|
||||
newKey := make([]byte, ed25519.PrivateKeySize)
|
||||
copy(newKey, data[:ed25519.PrivateKeySize])
|
||||
data = newKey
|
||||
case ed25519.PrivateKeySize:
|
||||
default:
|
||||
return nil, fmt.Errorf(
|
||||
"expected ed25519 data size to be %d or %d, got %d",
|
||||
ed25519.PrivateKeySize,
|
||||
ed25519.PrivateKeySize+ed25519.PublicKeySize,
|
||||
len(data),
|
||||
)
|
||||
}
|
||||
|
||||
return &Ed25519PrivateKey{
|
||||
k: ed25519.PrivateKey(data),
|
||||
}, nil
|
||||
}
|
||||
291
vendor/github.com/libp2p/go-libp2p/core/crypto/key.go
generated
vendored
Normal file
291
vendor/github.com/libp2p/go-libp2p/core/crypto/key.go
generated
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
// Package crypto implements various cryptographic utilities used by libp2p.
|
||||
// This includes a Public and Private key interface and key implementations
|
||||
// for supported key algorithms.
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/crypto/pb"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
//go:generate protoc --go_out=. --go_opt=Mpb/crypto.proto=./pb pb/crypto.proto
|
||||
|
||||
const (
|
||||
// RSA is an enum for the supported RSA key type
|
||||
RSA = iota
|
||||
// Ed25519 is an enum for the supported Ed25519 key type
|
||||
Ed25519
|
||||
// Secp256k1 is an enum for the supported Secp256k1 key type
|
||||
Secp256k1
|
||||
// ECDSA is an enum for the supported ECDSA key type
|
||||
ECDSA
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrBadKeyType is returned when a key is not supported
|
||||
ErrBadKeyType = errors.New("invalid or unsupported key type")
|
||||
// KeyTypes is a list of supported keys
|
||||
KeyTypes = []int{
|
||||
RSA,
|
||||
Ed25519,
|
||||
Secp256k1,
|
||||
ECDSA,
|
||||
}
|
||||
)
|
||||
|
||||
// PubKeyUnmarshaller is a func that creates a PubKey from a given slice of bytes
|
||||
type PubKeyUnmarshaller func(data []byte) (PubKey, error)
|
||||
|
||||
// PrivKeyUnmarshaller is a func that creates a PrivKey from a given slice of bytes
|
||||
type PrivKeyUnmarshaller func(data []byte) (PrivKey, error)
|
||||
|
||||
// PubKeyUnmarshallers is a map of unmarshallers by key type
|
||||
var PubKeyUnmarshallers = map[pb.KeyType]PubKeyUnmarshaller{
|
||||
pb.KeyType_RSA: UnmarshalRsaPublicKey,
|
||||
pb.KeyType_Ed25519: UnmarshalEd25519PublicKey,
|
||||
pb.KeyType_Secp256k1: UnmarshalSecp256k1PublicKey,
|
||||
pb.KeyType_ECDSA: UnmarshalECDSAPublicKey,
|
||||
}
|
||||
|
||||
// PrivKeyUnmarshallers is a map of unmarshallers by key type
|
||||
var PrivKeyUnmarshallers = map[pb.KeyType]PrivKeyUnmarshaller{
|
||||
pb.KeyType_RSA: UnmarshalRsaPrivateKey,
|
||||
pb.KeyType_Ed25519: UnmarshalEd25519PrivateKey,
|
||||
pb.KeyType_Secp256k1: UnmarshalSecp256k1PrivateKey,
|
||||
pb.KeyType_ECDSA: UnmarshalECDSAPrivateKey,
|
||||
}
|
||||
|
||||
// Key represents a crypto key that can be compared to another key
|
||||
type Key interface {
|
||||
// Equals checks whether two PubKeys are the same
|
||||
Equals(Key) bool
|
||||
|
||||
// Raw returns the raw bytes of the key (not wrapped in the
|
||||
// libp2p-crypto protobuf).
|
||||
//
|
||||
// This function is the inverse of {Priv,Pub}KeyUnmarshaler.
|
||||
Raw() ([]byte, error)
|
||||
|
||||
// Type returns the protobuf key type.
|
||||
Type() pb.KeyType
|
||||
}
|
||||
|
||||
// PrivKey represents a private key that can be used to generate a public key and sign data
|
||||
type PrivKey interface {
|
||||
Key
|
||||
|
||||
// Cryptographically sign the given bytes
|
||||
Sign([]byte) ([]byte, error)
|
||||
|
||||
// Return a public key paired with this private key
|
||||
GetPublic() PubKey
|
||||
}
|
||||
|
||||
// PubKey is a public key that can be used to verify data signed with the corresponding private key
|
||||
type PubKey interface {
|
||||
Key
|
||||
|
||||
// Verify that 'sig' is the signed hash of 'data'
|
||||
Verify(data []byte, sig []byte) (bool, error)
|
||||
}
|
||||
|
||||
// GenSharedKey generates the shared key from a given private key
|
||||
type GenSharedKey func([]byte) ([]byte, error)
|
||||
|
||||
// GenerateKeyPair generates a private and public key
|
||||
func GenerateKeyPair(typ, bits int) (PrivKey, PubKey, error) {
|
||||
return GenerateKeyPairWithReader(typ, bits, rand.Reader)
|
||||
}
|
||||
|
||||
// GenerateKeyPairWithReader returns a keypair of the given type and bit-size
|
||||
func GenerateKeyPairWithReader(typ, bits int, src io.Reader) (PrivKey, PubKey, error) {
|
||||
switch typ {
|
||||
case RSA:
|
||||
return GenerateRSAKeyPair(bits, src)
|
||||
case Ed25519:
|
||||
return GenerateEd25519Key(src)
|
||||
case Secp256k1:
|
||||
return GenerateSecp256k1Key(src)
|
||||
case ECDSA:
|
||||
return GenerateECDSAKeyPair(src)
|
||||
default:
|
||||
return nil, nil, ErrBadKeyType
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateEKeyPair returns an ephemeral public key and returns a function that will compute
|
||||
// the shared secret key. Used in the identify module.
|
||||
//
|
||||
// Focuses only on ECDH now, but can be made more general in the future.
|
||||
func GenerateEKeyPair(curveName string) ([]byte, GenSharedKey, error) {
|
||||
var curve elliptic.Curve
|
||||
|
||||
switch curveName {
|
||||
case "P-256":
|
||||
curve = elliptic.P256()
|
||||
case "P-384":
|
||||
curve = elliptic.P384()
|
||||
case "P-521":
|
||||
curve = elliptic.P521()
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("unknown curve name")
|
||||
}
|
||||
|
||||
priv, x, y, err := elliptic.GenerateKey(curve, rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pubKey := elliptic.Marshal(curve, x, y)
|
||||
|
||||
done := func(theirPub []byte) ([]byte, error) {
|
||||
// Verify and unpack node's public key.
|
||||
x, y := elliptic.Unmarshal(curve, theirPub)
|
||||
if x == nil {
|
||||
return nil, fmt.Errorf("malformed public key: %d %v", len(theirPub), theirPub)
|
||||
}
|
||||
|
||||
if !curve.IsOnCurve(x, y) {
|
||||
return nil, errors.New("invalid public key")
|
||||
}
|
||||
|
||||
// Generate shared secret.
|
||||
secret, _ := curve.ScalarMult(x, y, priv)
|
||||
|
||||
return secret.Bytes(), nil
|
||||
}
|
||||
|
||||
return pubKey, done, nil
|
||||
}
|
||||
|
||||
// UnmarshalPublicKey converts a protobuf serialized public key into its
|
||||
// representative object
|
||||
func UnmarshalPublicKey(data []byte) (PubKey, error) {
|
||||
pmes := new(pb.PublicKey)
|
||||
err := proto.Unmarshal(data, pmes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return PublicKeyFromProto(pmes)
|
||||
}
|
||||
|
||||
// PublicKeyFromProto converts an unserialized protobuf PublicKey message
|
||||
// into its representative object.
|
||||
func PublicKeyFromProto(pmes *pb.PublicKey) (PubKey, error) {
|
||||
um, ok := PubKeyUnmarshallers[pmes.GetType()]
|
||||
if !ok {
|
||||
return nil, ErrBadKeyType
|
||||
}
|
||||
|
||||
data := pmes.GetData()
|
||||
|
||||
pk, err := um(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch tpk := pk.(type) {
|
||||
case *RsaPublicKey:
|
||||
tpk.cached, _ = proto.Marshal(pmes)
|
||||
}
|
||||
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
// MarshalPublicKey converts a public key object into a protobuf serialized
|
||||
// public key
|
||||
func MarshalPublicKey(k PubKey) ([]byte, error) {
|
||||
pbmes, err := PublicKeyToProto(k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return proto.Marshal(pbmes)
|
||||
}
|
||||
|
||||
// PublicKeyToProto converts a public key object into an unserialized
|
||||
// protobuf PublicKey message.
|
||||
func PublicKeyToProto(k PubKey) (*pb.PublicKey, error) {
|
||||
data, err := k.Raw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.PublicKey{
|
||||
Type: k.Type().Enum(),
|
||||
Data: data,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UnmarshalPrivateKey converts a protobuf serialized private key into its
|
||||
// representative object
|
||||
func UnmarshalPrivateKey(data []byte) (PrivKey, error) {
|
||||
pmes := new(pb.PrivateKey)
|
||||
err := proto.Unmarshal(data, pmes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
um, ok := PrivKeyUnmarshallers[pmes.GetType()]
|
||||
if !ok {
|
||||
return nil, ErrBadKeyType
|
||||
}
|
||||
|
||||
return um(pmes.GetData())
|
||||
}
|
||||
|
||||
// MarshalPrivateKey converts a key object into its protobuf serialized form.
|
||||
func MarshalPrivateKey(k PrivKey) ([]byte, error) {
|
||||
data, err := k.Raw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.Marshal(&pb.PrivateKey{
|
||||
Type: k.Type().Enum(),
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
// ConfigDecodeKey decodes from b64 (for config file) to a byte array that can be unmarshalled.
|
||||
func ConfigDecodeKey(b string) ([]byte, error) {
|
||||
return base64.StdEncoding.DecodeString(b)
|
||||
}
|
||||
|
||||
// ConfigEncodeKey encodes a marshalled key to b64 (for config file).
|
||||
func ConfigEncodeKey(b []byte) string {
|
||||
return base64.StdEncoding.EncodeToString(b)
|
||||
}
|
||||
|
||||
// KeyEqual checks whether two Keys are equivalent (have identical byte representations).
|
||||
func KeyEqual(k1, k2 Key) bool {
|
||||
if k1 == k2 {
|
||||
return true
|
||||
}
|
||||
|
||||
return k1.Equals(k2)
|
||||
}
|
||||
|
||||
func basicEquals(k1, k2 Key) bool {
|
||||
if k1.Type() != k2.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
a, err := k1.Raw()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
b, err := k2.Raw()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return subtle.ConstantTimeCompare(a, b) == 1
|
||||
}
|
||||
78
vendor/github.com/libp2p/go-libp2p/core/crypto/key_to_stdlib.go
generated
vendored
Normal file
78
vendor/github.com/libp2p/go-libp2p/core/crypto/key_to_stdlib.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/rsa"
|
||||
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
)
|
||||
|
||||
// KeyPairFromStdKey wraps standard library (and secp256k1) private keys in libp2p/go-libp2p/core/crypto keys
|
||||
func KeyPairFromStdKey(priv crypto.PrivateKey) (PrivKey, PubKey, error) {
|
||||
if priv == nil {
|
||||
return nil, nil, ErrNilPrivateKey
|
||||
}
|
||||
|
||||
switch p := priv.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
return &RsaPrivateKey{*p}, &RsaPublicKey{k: p.PublicKey}, nil
|
||||
|
||||
case *ecdsa.PrivateKey:
|
||||
return &ECDSAPrivateKey{p}, &ECDSAPublicKey{&p.PublicKey}, nil
|
||||
|
||||
case *ed25519.PrivateKey:
|
||||
pubIfc := p.Public()
|
||||
pub, _ := pubIfc.(ed25519.PublicKey)
|
||||
return &Ed25519PrivateKey{*p}, &Ed25519PublicKey{pub}, nil
|
||||
|
||||
case *secp256k1.PrivateKey:
|
||||
sPriv := Secp256k1PrivateKey(*p)
|
||||
sPub := Secp256k1PublicKey(*p.PubKey())
|
||||
return &sPriv, &sPub, nil
|
||||
|
||||
default:
|
||||
return nil, nil, ErrBadKeyType
|
||||
}
|
||||
}
|
||||
|
||||
// PrivKeyToStdKey converts libp2p/go-libp2p/core/crypto private keys to standard library (and secp256k1) private keys
|
||||
func PrivKeyToStdKey(priv PrivKey) (crypto.PrivateKey, error) {
|
||||
if priv == nil {
|
||||
return nil, ErrNilPrivateKey
|
||||
}
|
||||
|
||||
switch p := priv.(type) {
|
||||
case *RsaPrivateKey:
|
||||
return &p.sk, nil
|
||||
case *ECDSAPrivateKey:
|
||||
return p.priv, nil
|
||||
case *Ed25519PrivateKey:
|
||||
return &p.k, nil
|
||||
case *Secp256k1PrivateKey:
|
||||
return p, nil
|
||||
default:
|
||||
return nil, ErrBadKeyType
|
||||
}
|
||||
}
|
||||
|
||||
// PubKeyToStdKey converts libp2p/go-libp2p/core/crypto private keys to standard library (and secp256k1) public keys
|
||||
func PubKeyToStdKey(pub PubKey) (crypto.PublicKey, error) {
|
||||
if pub == nil {
|
||||
return nil, ErrNilPublicKey
|
||||
}
|
||||
|
||||
switch p := pub.(type) {
|
||||
case *RsaPublicKey:
|
||||
return &p.k, nil
|
||||
case *ECDSAPublicKey:
|
||||
return p.pub, nil
|
||||
case *Ed25519PublicKey:
|
||||
return p.k, nil
|
||||
case *Secp256k1PublicKey:
|
||||
return p, nil
|
||||
default:
|
||||
return nil, ErrBadKeyType
|
||||
}
|
||||
}
|
||||
297
vendor/github.com/libp2p/go-libp2p/core/crypto/pb/crypto.pb.go
generated
vendored
Normal file
297
vendor/github.com/libp2p/go-libp2p/core/crypto/pb/crypto.pb.go
generated
vendored
Normal file
@@ -0,0 +1,297 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v3.21.12
|
||||
// source: pb/crypto.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type KeyType int32
|
||||
|
||||
const (
|
||||
KeyType_RSA KeyType = 0
|
||||
KeyType_Ed25519 KeyType = 1
|
||||
KeyType_Secp256k1 KeyType = 2
|
||||
KeyType_ECDSA KeyType = 3
|
||||
)
|
||||
|
||||
// Enum value maps for KeyType.
|
||||
var (
|
||||
KeyType_name = map[int32]string{
|
||||
0: "RSA",
|
||||
1: "Ed25519",
|
||||
2: "Secp256k1",
|
||||
3: "ECDSA",
|
||||
}
|
||||
KeyType_value = map[string]int32{
|
||||
"RSA": 0,
|
||||
"Ed25519": 1,
|
||||
"Secp256k1": 2,
|
||||
"ECDSA": 3,
|
||||
}
|
||||
)
|
||||
|
||||
func (x KeyType) Enum() *KeyType {
|
||||
p := new(KeyType)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x KeyType) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (KeyType) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_pb_crypto_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (KeyType) Type() protoreflect.EnumType {
|
||||
return &file_pb_crypto_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x KeyType) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Do not use.
|
||||
func (x *KeyType) UnmarshalJSON(b []byte) error {
|
||||
num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*x = KeyType(num)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deprecated: Use KeyType.Descriptor instead.
|
||||
func (KeyType) EnumDescriptor() ([]byte, []int) {
|
||||
return file_pb_crypto_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type PublicKey struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Type *KeyType `protobuf:"varint,1,req,name=Type,enum=crypto.pb.KeyType" json:"Type,omitempty"`
|
||||
Data []byte `protobuf:"bytes,2,req,name=Data" json:"Data,omitempty"`
|
||||
}
|
||||
|
||||
func (x *PublicKey) Reset() {
|
||||
*x = PublicKey{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_pb_crypto_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PublicKey) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PublicKey) ProtoMessage() {}
|
||||
|
||||
func (x *PublicKey) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_pb_crypto_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PublicKey.ProtoReflect.Descriptor instead.
|
||||
func (*PublicKey) Descriptor() ([]byte, []int) {
|
||||
return file_pb_crypto_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *PublicKey) GetType() KeyType {
|
||||
if x != nil && x.Type != nil {
|
||||
return *x.Type
|
||||
}
|
||||
return KeyType_RSA
|
||||
}
|
||||
|
||||
func (x *PublicKey) GetData() []byte {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Type *KeyType `protobuf:"varint,1,req,name=Type,enum=crypto.pb.KeyType" json:"Type,omitempty"`
|
||||
Data []byte `protobuf:"bytes,2,req,name=Data" json:"Data,omitempty"`
|
||||
}
|
||||
|
||||
func (x *PrivateKey) Reset() {
|
||||
*x = PrivateKey{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_pb_crypto_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PrivateKey) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PrivateKey) ProtoMessage() {}
|
||||
|
||||
func (x *PrivateKey) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_pb_crypto_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PrivateKey.ProtoReflect.Descriptor instead.
|
||||
func (*PrivateKey) Descriptor() ([]byte, []int) {
|
||||
return file_pb_crypto_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *PrivateKey) GetType() KeyType {
|
||||
if x != nil && x.Type != nil {
|
||||
return *x.Type
|
||||
}
|
||||
return KeyType_RSA
|
||||
}
|
||||
|
||||
func (x *PrivateKey) GetData() []byte {
|
||||
if x != nil {
|
||||
return x.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_pb_crypto_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_pb_crypto_proto_rawDesc = []byte{
|
||||
0x0a, 0x0f, 0x70, 0x62, 0x2f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x12, 0x09, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x70, 0x62, 0x22, 0x47, 0x0a, 0x09,
|
||||
0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x04, 0x54, 0x79, 0x70,
|
||||
0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f,
|
||||
0x2e, 0x70, 0x62, 0x2e, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70,
|
||||
0x65, 0x12, 0x12, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x02, 0x28, 0x0c, 0x52,
|
||||
0x04, 0x44, 0x61, 0x74, 0x61, 0x22, 0x48, 0x0a, 0x0a, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
|
||||
0x4b, 0x65, 0x79, 0x12, 0x26, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28,
|
||||
0x0e, 0x32, 0x12, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x70, 0x62, 0x2e, 0x4b, 0x65,
|
||||
0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x44,
|
||||
0x61, 0x74, 0x61, 0x18, 0x02, 0x20, 0x02, 0x28, 0x0c, 0x52, 0x04, 0x44, 0x61, 0x74, 0x61, 0x2a,
|
||||
0x39, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x52, 0x53,
|
||||
0x41, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x10, 0x01,
|
||||
0x12, 0x0d, 0x0a, 0x09, 0x53, 0x65, 0x63, 0x70, 0x32, 0x35, 0x36, 0x6b, 0x31, 0x10, 0x02, 0x12,
|
||||
0x09, 0x0a, 0x05, 0x45, 0x43, 0x44, 0x53, 0x41, 0x10, 0x03, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f,
|
||||
0x67, 0x6f, 0x2d, 0x6c, 0x69, 0x62, 0x70, 0x32, 0x70, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63,
|
||||
0x72, 0x79, 0x70, 0x74, 0x6f, 0x2f, 0x70, 0x62,
|
||||
}
|
||||
|
||||
var (
|
||||
file_pb_crypto_proto_rawDescOnce sync.Once
|
||||
file_pb_crypto_proto_rawDescData = file_pb_crypto_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_pb_crypto_proto_rawDescGZIP() []byte {
|
||||
file_pb_crypto_proto_rawDescOnce.Do(func() {
|
||||
file_pb_crypto_proto_rawDescData = protoimpl.X.CompressGZIP(file_pb_crypto_proto_rawDescData)
|
||||
})
|
||||
return file_pb_crypto_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_pb_crypto_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_pb_crypto_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_pb_crypto_proto_goTypes = []interface{}{
|
||||
(KeyType)(0), // 0: crypto.pb.KeyType
|
||||
(*PublicKey)(nil), // 1: crypto.pb.PublicKey
|
||||
(*PrivateKey)(nil), // 2: crypto.pb.PrivateKey
|
||||
}
|
||||
var file_pb_crypto_proto_depIdxs = []int32{
|
||||
0, // 0: crypto.pb.PublicKey.Type:type_name -> crypto.pb.KeyType
|
||||
0, // 1: crypto.pb.PrivateKey.Type:type_name -> crypto.pb.KeyType
|
||||
2, // [2:2] is the sub-list for method output_type
|
||||
2, // [2:2] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_pb_crypto_proto_init() }
|
||||
func file_pb_crypto_proto_init() {
|
||||
if File_pb_crypto_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_pb_crypto_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*PublicKey); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_pb_crypto_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*PrivateKey); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_pb_crypto_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_pb_crypto_proto_goTypes,
|
||||
DependencyIndexes: file_pb_crypto_proto_depIdxs,
|
||||
EnumInfos: file_pb_crypto_proto_enumTypes,
|
||||
MessageInfos: file_pb_crypto_proto_msgTypes,
|
||||
}.Build()
|
||||
File_pb_crypto_proto = out.File
|
||||
file_pb_crypto_proto_rawDesc = nil
|
||||
file_pb_crypto_proto_goTypes = nil
|
||||
file_pb_crypto_proto_depIdxs = nil
|
||||
}
|
||||
22
vendor/github.com/libp2p/go-libp2p/core/crypto/pb/crypto.proto
generated
vendored
Normal file
22
vendor/github.com/libp2p/go-libp2p/core/crypto/pb/crypto.proto
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
syntax = "proto2";
|
||||
|
||||
package crypto.pb;
|
||||
|
||||
option go_package = "github.com/libp2p/go-libp2p/core/crypto/pb";
|
||||
|
||||
enum KeyType {
|
||||
RSA = 0;
|
||||
Ed25519 = 1;
|
||||
Secp256k1 = 2;
|
||||
ECDSA = 3;
|
||||
}
|
||||
|
||||
message PublicKey {
|
||||
required KeyType Type = 1;
|
||||
required bytes Data = 2;
|
||||
}
|
||||
|
||||
message PrivateKey {
|
||||
required KeyType Type = 1;
|
||||
required bytes Data = 2;
|
||||
}
|
||||
28
vendor/github.com/libp2p/go-libp2p/core/crypto/rsa_common.go
generated
vendored
Normal file
28
vendor/github.com/libp2p/go-libp2p/core/crypto/rsa_common.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// WeakRsaKeyEnv is an environment variable which, when set, lowers the
|
||||
// minimum required bits of RSA keys to 512. This should be used exclusively in
|
||||
// test situations.
|
||||
const WeakRsaKeyEnv = "LIBP2P_ALLOW_WEAK_RSA_KEYS"
|
||||
|
||||
var MinRsaKeyBits = 2048
|
||||
|
||||
var maxRsaKeyBits = 8192
|
||||
|
||||
// ErrRsaKeyTooSmall is returned when trying to generate or parse an RSA key
|
||||
// that's smaller than MinRsaKeyBits bits. In test
|
||||
var ErrRsaKeyTooSmall error
|
||||
var ErrRsaKeyTooBig error = fmt.Errorf("rsa keys must be <= %d bits", maxRsaKeyBits)
|
||||
|
||||
func init() {
|
||||
if _, ok := os.LookupEnv(WeakRsaKeyEnv); ok {
|
||||
MinRsaKeyBits = 512
|
||||
}
|
||||
|
||||
ErrRsaKeyTooSmall = fmt.Errorf("rsa keys must be >= %d bits to be useful", MinRsaKeyBits)
|
||||
}
|
||||
154
vendor/github.com/libp2p/go-libp2p/core/crypto/rsa_go.go
generated
vendored
Normal file
154
vendor/github.com/libp2p/go-libp2p/core/crypto/rsa_go.go
generated
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
pb "github.com/libp2p/go-libp2p/core/crypto/pb"
|
||||
"github.com/libp2p/go-libp2p/core/internal/catch"
|
||||
"github.com/libp2p/go-libp2p/internal/sha256"
|
||||
)
|
||||
|
||||
// RsaPrivateKey is a rsa private key
|
||||
type RsaPrivateKey struct {
|
||||
sk rsa.PrivateKey
|
||||
}
|
||||
|
||||
// RsaPublicKey is a rsa public key
|
||||
type RsaPublicKey struct {
|
||||
k rsa.PublicKey
|
||||
|
||||
cached []byte
|
||||
}
|
||||
|
||||
// GenerateRSAKeyPair generates a new rsa private and public key
|
||||
func GenerateRSAKeyPair(bits int, src io.Reader) (PrivKey, PubKey, error) {
|
||||
if bits < MinRsaKeyBits {
|
||||
return nil, nil, ErrRsaKeyTooSmall
|
||||
}
|
||||
if bits > maxRsaKeyBits {
|
||||
return nil, nil, ErrRsaKeyTooBig
|
||||
}
|
||||
priv, err := rsa.GenerateKey(src, bits)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pk := priv.PublicKey
|
||||
return &RsaPrivateKey{sk: *priv}, &RsaPublicKey{k: pk}, nil
|
||||
}
|
||||
|
||||
// Verify compares a signature against input data
|
||||
func (pk *RsaPublicKey) Verify(data, sig []byte) (success bool, err error) {
|
||||
defer func() {
|
||||
catch.HandlePanic(recover(), &err, "RSA signature verification")
|
||||
|
||||
// To be safe
|
||||
if err != nil {
|
||||
success = false
|
||||
}
|
||||
}()
|
||||
hashed := sha256.Sum256(data)
|
||||
err = rsa.VerifyPKCS1v15(&pk.k, crypto.SHA256, hashed[:], sig)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (pk *RsaPublicKey) Type() pb.KeyType {
|
||||
return pb.KeyType_RSA
|
||||
}
|
||||
|
||||
func (pk *RsaPublicKey) Raw() (res []byte, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "RSA public-key marshaling") }()
|
||||
return x509.MarshalPKIXPublicKey(&pk.k)
|
||||
}
|
||||
|
||||
// Equals checks whether this key is equal to another
|
||||
func (pk *RsaPublicKey) Equals(k Key) bool {
|
||||
// make sure this is a rsa public key
|
||||
other, ok := (k).(*RsaPublicKey)
|
||||
if !ok {
|
||||
return basicEquals(pk, k)
|
||||
}
|
||||
|
||||
return pk.k.N.Cmp(other.k.N) == 0 && pk.k.E == other.k.E
|
||||
}
|
||||
|
||||
// Sign returns a signature of the input data
|
||||
func (sk *RsaPrivateKey) Sign(message []byte) (sig []byte, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "RSA signing") }()
|
||||
hashed := sha256.Sum256(message)
|
||||
return rsa.SignPKCS1v15(rand.Reader, &sk.sk, crypto.SHA256, hashed[:])
|
||||
}
|
||||
|
||||
// GetPublic returns a public key
|
||||
func (sk *RsaPrivateKey) GetPublic() PubKey {
|
||||
return &RsaPublicKey{k: sk.sk.PublicKey}
|
||||
}
|
||||
|
||||
func (sk *RsaPrivateKey) Type() pb.KeyType {
|
||||
return pb.KeyType_RSA
|
||||
}
|
||||
|
||||
func (sk *RsaPrivateKey) Raw() (res []byte, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "RSA private-key marshaling") }()
|
||||
b := x509.MarshalPKCS1PrivateKey(&sk.sk)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Equals checks whether this key is equal to another
|
||||
func (sk *RsaPrivateKey) Equals(k Key) bool {
|
||||
// make sure this is a rsa public key
|
||||
other, ok := (k).(*RsaPrivateKey)
|
||||
if !ok {
|
||||
return basicEquals(sk, k)
|
||||
}
|
||||
|
||||
a := sk.sk
|
||||
b := other.sk
|
||||
|
||||
// Don't care about constant time. We're only comparing the public half.
|
||||
return a.PublicKey.N.Cmp(b.PublicKey.N) == 0 && a.PublicKey.E == b.PublicKey.E
|
||||
}
|
||||
|
||||
// UnmarshalRsaPrivateKey returns a private key from the input x509 bytes
|
||||
func UnmarshalRsaPrivateKey(b []byte) (key PrivKey, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "RSA private-key unmarshaling") }()
|
||||
sk, err := x509.ParsePKCS1PrivateKey(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if sk.N.BitLen() < MinRsaKeyBits {
|
||||
return nil, ErrRsaKeyTooSmall
|
||||
}
|
||||
if sk.N.BitLen() > maxRsaKeyBits {
|
||||
return nil, ErrRsaKeyTooBig
|
||||
}
|
||||
return &RsaPrivateKey{sk: *sk}, nil
|
||||
}
|
||||
|
||||
// UnmarshalRsaPublicKey returns a public key from the input x509 bytes
|
||||
func UnmarshalRsaPublicKey(b []byte) (key PubKey, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "RSA public-key unmarshaling") }()
|
||||
pub, err := x509.ParsePKIXPublicKey(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pk, ok := pub.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, errors.New("not actually an rsa public key")
|
||||
}
|
||||
if pk.N.BitLen() < MinRsaKeyBits {
|
||||
return nil, ErrRsaKeyTooSmall
|
||||
}
|
||||
if pk.N.BitLen() > maxRsaKeyBits {
|
||||
return nil, ErrRsaKeyTooBig
|
||||
}
|
||||
|
||||
return &RsaPublicKey{k: *pk}, nil
|
||||
}
|
||||
127
vendor/github.com/libp2p/go-libp2p/core/crypto/secp256k1.go
generated
vendored
Normal file
127
vendor/github.com/libp2p/go-libp2p/core/crypto/secp256k1.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
pb "github.com/libp2p/go-libp2p/core/crypto/pb"
|
||||
"github.com/libp2p/go-libp2p/core/internal/catch"
|
||||
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
|
||||
"github.com/libp2p/go-libp2p/internal/sha256"
|
||||
)
|
||||
|
||||
// Secp256k1PrivateKey is a Secp256k1 private key
|
||||
type Secp256k1PrivateKey secp256k1.PrivateKey
|
||||
|
||||
// Secp256k1PublicKey is a Secp256k1 public key
|
||||
type Secp256k1PublicKey secp256k1.PublicKey
|
||||
|
||||
// GenerateSecp256k1Key generates a new Secp256k1 private and public key pair
|
||||
func GenerateSecp256k1Key(src io.Reader) (PrivKey, PubKey, error) {
|
||||
privk, err := secp256k1.GeneratePrivateKey()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
k := (*Secp256k1PrivateKey)(privk)
|
||||
return k, k.GetPublic(), nil
|
||||
}
|
||||
|
||||
// UnmarshalSecp256k1PrivateKey returns a private key from bytes
|
||||
func UnmarshalSecp256k1PrivateKey(data []byte) (k PrivKey, err error) {
|
||||
if len(data) != secp256k1.PrivKeyBytesLen {
|
||||
return nil, fmt.Errorf("expected secp256k1 data size to be %d", secp256k1.PrivKeyBytesLen)
|
||||
}
|
||||
defer func() { catch.HandlePanic(recover(), &err, "secp256k1 private-key unmarshal") }()
|
||||
|
||||
privk := secp256k1.PrivKeyFromBytes(data)
|
||||
return (*Secp256k1PrivateKey)(privk), nil
|
||||
}
|
||||
|
||||
// UnmarshalSecp256k1PublicKey returns a public key from bytes
|
||||
func UnmarshalSecp256k1PublicKey(data []byte) (_k PubKey, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "secp256k1 public-key unmarshal") }()
|
||||
k, err := secp256k1.ParsePubKey(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return (*Secp256k1PublicKey)(k), nil
|
||||
}
|
||||
|
||||
// Type returns the private key type
|
||||
func (k *Secp256k1PrivateKey) Type() pb.KeyType {
|
||||
return pb.KeyType_Secp256k1
|
||||
}
|
||||
|
||||
// Raw returns the bytes of the key
|
||||
func (k *Secp256k1PrivateKey) Raw() ([]byte, error) {
|
||||
return (*secp256k1.PrivateKey)(k).Serialize(), nil
|
||||
}
|
||||
|
||||
// Equals compares two private keys
|
||||
func (k *Secp256k1PrivateKey) Equals(o Key) bool {
|
||||
sk, ok := o.(*Secp256k1PrivateKey)
|
||||
if !ok {
|
||||
return basicEquals(k, o)
|
||||
}
|
||||
|
||||
return k.GetPublic().Equals(sk.GetPublic())
|
||||
}
|
||||
|
||||
// Sign returns a signature from input data
|
||||
func (k *Secp256k1PrivateKey) Sign(data []byte) (_sig []byte, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "secp256k1 signing") }()
|
||||
key := (*secp256k1.PrivateKey)(k)
|
||||
hash := sha256.Sum256(data)
|
||||
sig := ecdsa.Sign(key, hash[:])
|
||||
|
||||
return sig.Serialize(), nil
|
||||
}
|
||||
|
||||
// GetPublic returns a public key
|
||||
func (k *Secp256k1PrivateKey) GetPublic() PubKey {
|
||||
return (*Secp256k1PublicKey)((*secp256k1.PrivateKey)(k).PubKey())
|
||||
}
|
||||
|
||||
// Type returns the public key type
|
||||
func (k *Secp256k1PublicKey) Type() pb.KeyType {
|
||||
return pb.KeyType_Secp256k1
|
||||
}
|
||||
|
||||
// Raw returns the bytes of the key
|
||||
func (k *Secp256k1PublicKey) Raw() (res []byte, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "secp256k1 public key marshaling") }()
|
||||
return (*secp256k1.PublicKey)(k).SerializeCompressed(), nil
|
||||
}
|
||||
|
||||
// Equals compares two public keys
|
||||
func (k *Secp256k1PublicKey) Equals(o Key) bool {
|
||||
sk, ok := o.(*Secp256k1PublicKey)
|
||||
if !ok {
|
||||
return basicEquals(k, o)
|
||||
}
|
||||
|
||||
return (*secp256k1.PublicKey)(k).IsEqual((*secp256k1.PublicKey)(sk))
|
||||
}
|
||||
|
||||
// Verify compares a signature against the input data
|
||||
func (k *Secp256k1PublicKey) Verify(data []byte, sigStr []byte) (success bool, err error) {
|
||||
defer func() {
|
||||
catch.HandlePanic(recover(), &err, "secp256k1 signature verification")
|
||||
|
||||
// To be extra safe.
|
||||
if err != nil {
|
||||
success = false
|
||||
}
|
||||
}()
|
||||
sig, err := ecdsa.ParseDERSignature(sigStr)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
hash := sha256.Sum256(data)
|
||||
return sig.Verify(hash[:], (*secp256k1.PublicKey)(k)), nil
|
||||
}
|
||||
27
vendor/github.com/libp2p/go-libp2p/core/discovery/discovery.go
generated
vendored
Normal file
27
vendor/github.com/libp2p/go-libp2p/core/discovery/discovery.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// Package discovery provides service advertisement and peer discovery interfaces for libp2p.
|
||||
package discovery
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
|
||||
// Advertiser is an interface for advertising services
|
||||
type Advertiser interface {
|
||||
// Advertise advertises a service
|
||||
Advertise(ctx context.Context, ns string, opts ...Option) (time.Duration, error)
|
||||
}
|
||||
|
||||
// Discoverer is an interface for peer discovery
|
||||
type Discoverer interface {
|
||||
// FindPeers discovers peers providing a service
|
||||
FindPeers(ctx context.Context, ns string, opts ...Option) (<-chan peer.AddrInfo, error)
|
||||
}
|
||||
|
||||
// Discovery is an interface that combines service advertisement and peer discovery
|
||||
type Discovery interface {
|
||||
Advertiser
|
||||
Discoverer
|
||||
}
|
||||
41
vendor/github.com/libp2p/go-libp2p/core/discovery/options.go
generated
vendored
Normal file
41
vendor/github.com/libp2p/go-libp2p/core/discovery/options.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package discovery
|
||||
|
||||
import "time"
|
||||
|
||||
// DiscoveryOpt is a single discovery option.
|
||||
type Option func(opts *Options) error
|
||||
|
||||
// DiscoveryOpts is a set of discovery options.
|
||||
type Options struct {
|
||||
Ttl time.Duration
|
||||
Limit int
|
||||
|
||||
// Other (implementation-specific) options
|
||||
Other map[interface{}]interface{}
|
||||
}
|
||||
|
||||
// Apply applies the given options to this DiscoveryOpts
|
||||
func (opts *Options) Apply(options ...Option) error {
|
||||
for _, o := range options {
|
||||
if err := o(opts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TTL is an option that provides a hint for the duration of an advertisement
|
||||
func TTL(ttl time.Duration) Option {
|
||||
return func(opts *Options) error {
|
||||
opts.Ttl = ttl
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Limit is an option that provides an upper bound on the peer count for discovery
|
||||
func Limit(limit int) Option {
|
||||
return func(opts *Options) error {
|
||||
opts.Limit = limit
|
||||
return nil
|
||||
}
|
||||
}
|
||||
83
vendor/github.com/libp2p/go-libp2p/core/event/addrs.go
generated
vendored
Normal file
83
vendor/github.com/libp2p/go-libp2p/core/event/addrs.go
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/libp2p/go-libp2p/core/record"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
// AddrAction represents an action taken on one of a Host's listen addresses.
|
||||
// It is used to add context to address change events in EvtLocalAddressesUpdated.
|
||||
type AddrAction int
|
||||
|
||||
const (
|
||||
// Unknown means that the event producer was unable to determine why the address
|
||||
// is in the current state.
|
||||
Unknown AddrAction = iota
|
||||
|
||||
// Added means that the address is new and was not present prior to the event.
|
||||
Added
|
||||
|
||||
// Maintained means that the address was not altered between the current and
|
||||
// previous states.
|
||||
Maintained
|
||||
|
||||
// Removed means that the address was removed from the Host.
|
||||
Removed
|
||||
)
|
||||
|
||||
// UpdatedAddress is used in the EvtLocalAddressesUpdated event to convey
|
||||
// address change information.
|
||||
type UpdatedAddress struct {
|
||||
// Address contains the address that was updated.
|
||||
Address ma.Multiaddr
|
||||
|
||||
// Action indicates what action was taken on the address during the
|
||||
// event. May be Unknown if the event producer cannot produce diffs.
|
||||
Action AddrAction
|
||||
}
|
||||
|
||||
// EvtLocalAddressesUpdated should be emitted when the set of listen addresses for
|
||||
// the local host changes. This may happen for a number of reasons. For example,
|
||||
// we may have opened a new relay connection, established a new NAT mapping via
|
||||
// UPnP, or been informed of our observed address by another peer.
|
||||
//
|
||||
// EvtLocalAddressesUpdated contains a snapshot of the current listen addresses,
|
||||
// and may also contain a diff between the current state and the previous state.
|
||||
// If the event producer is capable of creating a diff, the Diffs field will be
|
||||
// true, and event consumers can inspect the Action field of each UpdatedAddress
|
||||
// to see how each address was modified.
|
||||
//
|
||||
// For example, the Action will tell you whether an address in
|
||||
// the Current list was Added by the event producer, or was Maintained without
|
||||
// changes. Addresses that were removed from the Host will have the AddrAction
|
||||
// of Removed, and will be in the Removed list.
|
||||
//
|
||||
// If the event producer is not capable or producing diffs, the Diffs field will
|
||||
// be false, the Removed list will always be empty, and the Action for each
|
||||
// UpdatedAddress in the Current list will be Unknown.
|
||||
//
|
||||
// In addition to the above, EvtLocalAddressesUpdated also contains the updated peer.PeerRecord
|
||||
// for the Current set of listen addresses, wrapped in a record.Envelope and signed by the Host's private key.
|
||||
// This record can be shared with other peers to inform them of what we believe are our diallable addresses
|
||||
// a secure and authenticated way.
|
||||
type EvtLocalAddressesUpdated struct {
|
||||
|
||||
// Diffs indicates whether this event contains a diff of the Host's previous
|
||||
// address set.
|
||||
Diffs bool
|
||||
|
||||
// Current contains all current listen addresses for the Host.
|
||||
// If Diffs == true, the Action field of each UpdatedAddress will tell
|
||||
// you whether an address was Added, or was Maintained from the previous
|
||||
// state.
|
||||
Current []UpdatedAddress
|
||||
|
||||
// Removed contains addresses that were removed from the Host.
|
||||
// This field is only set when Diffs == true.
|
||||
Removed []UpdatedAddress
|
||||
|
||||
// SignedPeerRecord contains our own updated peer.PeerRecord, listing the addresses enumerated in Current.
|
||||
// wrapped in a record.Envelope and signed by the Host's private key.
|
||||
SignedPeerRecord *record.Envelope
|
||||
}
|
||||
100
vendor/github.com/libp2p/go-libp2p/core/event/bus.go
generated
vendored
Normal file
100
vendor/github.com/libp2p/go-libp2p/core/event/bus.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"io"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// SubscriptionOpt represents a subscriber option. Use the options exposed by the implementation of choice.
|
||||
type SubscriptionOpt = func(interface{}) error
|
||||
|
||||
// EmitterOpt represents an emitter option. Use the options exposed by the implementation of choice.
|
||||
type EmitterOpt = func(interface{}) error
|
||||
|
||||
// CancelFunc closes a subscriber.
|
||||
type CancelFunc = func()
|
||||
|
||||
// wildcardSubscriptionType is a virtual type to represent wildcard
|
||||
// subscriptions.
|
||||
type wildcardSubscriptionType interface{}
|
||||
|
||||
// WildcardSubscription is the type to subscribe to receive all events
|
||||
// emitted in the eventbus.
|
||||
var WildcardSubscription = new(wildcardSubscriptionType)
|
||||
|
||||
// Emitter represents an actor that emits events onto the eventbus.
|
||||
type Emitter interface {
|
||||
io.Closer
|
||||
|
||||
// Emit emits an event onto the eventbus. If any channel subscribed to the topic is blocked,
|
||||
// calls to Emit will block.
|
||||
//
|
||||
// Calling this function with wrong event type will cause a panic.
|
||||
Emit(evt interface{}) error
|
||||
}
|
||||
|
||||
// Subscription represents a subscription to one or multiple event types.
|
||||
type Subscription interface {
|
||||
io.Closer
|
||||
|
||||
// Out returns the channel from which to consume events.
|
||||
Out() <-chan interface{}
|
||||
|
||||
// Name returns the name for the subscription
|
||||
Name() string
|
||||
}
|
||||
|
||||
// Bus is an interface for a type-based event delivery system.
|
||||
type Bus interface {
|
||||
// Subscribe creates a new Subscription.
|
||||
//
|
||||
// eventType can be either a pointer to a single event type, or a slice of pointers to
|
||||
// subscribe to multiple event types at once, under a single subscription (and channel).
|
||||
//
|
||||
// Failing to drain the channel may cause publishers to block.
|
||||
//
|
||||
// If you want to subscribe to ALL events emitted in the bus, use
|
||||
// `WildcardSubscription` as the `eventType`:
|
||||
//
|
||||
// eventbus.Subscribe(WildcardSubscription)
|
||||
//
|
||||
// Simple example
|
||||
//
|
||||
// sub, err := eventbus.Subscribe(new(EventType))
|
||||
// defer sub.Close()
|
||||
// for e := range sub.Out() {
|
||||
// event := e.(EventType) // guaranteed safe
|
||||
// [...]
|
||||
// }
|
||||
//
|
||||
// Multi-type example
|
||||
//
|
||||
// sub, err := eventbus.Subscribe([]interface{}{new(EventA), new(EventB)})
|
||||
// defer sub.Close()
|
||||
// for e := range sub.Out() {
|
||||
// select e.(type):
|
||||
// case EventA:
|
||||
// [...]
|
||||
// case EventB:
|
||||
// [...]
|
||||
// }
|
||||
// }
|
||||
Subscribe(eventType interface{}, opts ...SubscriptionOpt) (Subscription, error)
|
||||
|
||||
// Emitter creates a new event emitter.
|
||||
//
|
||||
// eventType accepts typed nil pointers, and uses the type information for wiring purposes.
|
||||
//
|
||||
// Example:
|
||||
// em, err := eventbus.Emitter(new(EventT))
|
||||
// defer em.Close() // MUST call this after being done with the emitter
|
||||
// em.Emit(EventT{})
|
||||
Emitter(eventType interface{}, opts ...EmitterOpt) (Emitter, error)
|
||||
|
||||
// GetAllEventTypes returns all the event types that this bus knows about
|
||||
// (having emitters and subscribers). It omits the WildcardSubscription.
|
||||
//
|
||||
// The caller is guaranteed that this function will only return value types;
|
||||
// no pointer types will be returned.
|
||||
GetAllEventTypes() []reflect.Type
|
||||
}
|
||||
21
vendor/github.com/libp2p/go-libp2p/core/event/dht.go
generated
vendored
Normal file
21
vendor/github.com/libp2p/go-libp2p/core/event/dht.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package event
|
||||
|
||||
// RawJSON is a type that contains a raw JSON string.
|
||||
type RawJSON string
|
||||
|
||||
// GenericDHTEvent is a type that encapsulates an actual DHT event by carrying
|
||||
// its raw JSON.
|
||||
//
|
||||
// Context: the DHT event system is rather bespoke and a bit messy at the time,
|
||||
// so until we unify/clean that up, this event bridges the gap. It should only
|
||||
// be consumed for informational purposes.
|
||||
//
|
||||
// EXPERIMENTAL: this will likely be removed if/when the DHT event types are
|
||||
// hoisted to core, and the DHT event system is reconciled with the eventbus.
|
||||
type GenericDHTEvent struct {
|
||||
// Type is the type of the DHT event that occurred.
|
||||
Type string
|
||||
|
||||
// Raw is the raw JSON representation of the event payload.
|
||||
Raw RawJSON
|
||||
}
|
||||
11
vendor/github.com/libp2p/go-libp2p/core/event/doc.go
generated
vendored
Normal file
11
vendor/github.com/libp2p/go-libp2p/core/event/doc.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Package event contains the abstractions for a local event bus, along with the standard events
|
||||
// that libp2p subsystems may emit.
|
||||
//
|
||||
// Source code is arranged as follows:
|
||||
// - doc.go: this file.
|
||||
// - bus.go: abstractions for the event bus.
|
||||
// - rest: event structs, sensibly categorised in files by entity, and following this naming convention:
|
||||
// Evt[Entity (noun)][Event (verb past tense / gerund)]
|
||||
// The past tense is used to convey that something happened, whereas the gerund form of the verb (-ing)
|
||||
// expresses that a process is in progress. Examples: EvtConnEstablishing, EvtConnEstablished.
|
||||
package event
|
||||
17
vendor/github.com/libp2p/go-libp2p/core/event/identify.go
generated
vendored
Normal file
17
vendor/github.com/libp2p/go-libp2p/core/event/identify.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package event
|
||||
|
||||
import "github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
// EvtPeerIdentificationCompleted is emitted when the initial identification round for a peer is completed.
|
||||
type EvtPeerIdentificationCompleted struct {
|
||||
// Peer is the ID of the peer whose identification succeeded.
|
||||
Peer peer.ID
|
||||
}
|
||||
|
||||
// EvtPeerIdentificationFailed is emitted when the initial identification round for a peer failed.
|
||||
type EvtPeerIdentificationFailed struct {
|
||||
// Peer is the ID of the peer whose identification failed.
|
||||
Peer peer.ID
|
||||
// Reason is the reason why identification failed.
|
||||
Reason error
|
||||
}
|
||||
18
vendor/github.com/libp2p/go-libp2p/core/event/nattype.go
generated
vendored
Normal file
18
vendor/github.com/libp2p/go-libp2p/core/event/nattype.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package event
|
||||
|
||||
import "github.com/libp2p/go-libp2p/core/network"
|
||||
|
||||
// EvtNATDeviceTypeChanged is an event struct to be emitted when the type of the NAT device changes for a Transport Protocol.
|
||||
//
|
||||
// Note: This event is meaningful ONLY if the AutoNAT Reachability is Private.
|
||||
// Consumers of this event should ALSO consume the `EvtLocalReachabilityChanged` event and interpret
|
||||
// this event ONLY if the Reachability on the `EvtLocalReachabilityChanged` is Private.
|
||||
type EvtNATDeviceTypeChanged struct {
|
||||
// TransportProtocol is the Transport Protocol for which the NAT Device Type has been determined.
|
||||
TransportProtocol network.NATTransportProtocol
|
||||
// NatDeviceType indicates the type of the NAT Device for the Transport Protocol.
|
||||
// Currently, it can be either a `Cone NAT` or a `Symmetric NAT`. Please see the detailed documentation
|
||||
// on `network.NATDeviceType` enumerations for a better understanding of what these types mean and
|
||||
// how they impact Connectivity and Hole Punching.
|
||||
NatDeviceType network.NATDeviceType
|
||||
}
|
||||
55
vendor/github.com/libp2p/go-libp2p/core/event/network.go
generated
vendored
Normal file
55
vendor/github.com/libp2p/go-libp2p/core/event/network.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
|
||||
// EvtPeerConnectednessChanged should be emitted every time the "connectedness" to a
|
||||
// given peer changes. Specifically, this event is emitted in the following
|
||||
// cases:
|
||||
//
|
||||
// - Connectedness = Connected: Every time we transition from having no
|
||||
// connections to a peer to having at least one connection to the peer.
|
||||
// - Connectedness = NotConnected: Every time we transition from having at least
|
||||
// one connection to a peer to having no connections to the peer.
|
||||
//
|
||||
// Additional connectedness states may be added in the future. This list should
|
||||
// not be considered exhaustive.
|
||||
//
|
||||
// Take note:
|
||||
//
|
||||
// - It's possible to have _multiple_ connections to a given peer.
|
||||
// - Both libp2p and networks are asynchronous.
|
||||
//
|
||||
// This means that all the following situations are possible:
|
||||
//
|
||||
// A connection is cut and is re-established:
|
||||
//
|
||||
// - Peer A observes a transition from Connected -> NotConnected -> Connected
|
||||
// - Peer B observes a transition from Connected -> NotConnected -> Connected
|
||||
//
|
||||
// Explanation: Both peers observe the connection die. This is the "nice" case.
|
||||
//
|
||||
// A connection is cut and is re-established.
|
||||
//
|
||||
// - Peer A observes a transition from Connected -> NotConnected -> Connected.
|
||||
// - Peer B observes no transition.
|
||||
//
|
||||
// Explanation: Peer A re-establishes the dead connection. Peer B observes the
|
||||
// new connection form before it observes the old connection die.
|
||||
//
|
||||
// A connection is cut:
|
||||
//
|
||||
// - Peer A observes no transition.
|
||||
// - Peer B observes no transition.
|
||||
//
|
||||
// Explanation: There were two connections and one was cut. This connection
|
||||
// might have been in active use but neither peer will observe a change in
|
||||
// "connectedness". Peers should always make sure to retry network requests.
|
||||
type EvtPeerConnectednessChanged struct {
|
||||
// Peer is the remote peer whose connectedness has changed.
|
||||
Peer peer.ID
|
||||
// Connectedness is the new connectedness state.
|
||||
Connectedness network.Connectedness
|
||||
}
|
||||
26
vendor/github.com/libp2p/go-libp2p/core/event/protocol.go
generated
vendored
Normal file
26
vendor/github.com/libp2p/go-libp2p/core/event/protocol.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
peer "github.com/libp2p/go-libp2p/core/peer"
|
||||
protocol "github.com/libp2p/go-libp2p/core/protocol"
|
||||
)
|
||||
|
||||
// EvtPeerProtocolsUpdated should be emitted when a peer we're connected to adds or removes protocols from their stack.
|
||||
type EvtPeerProtocolsUpdated struct {
|
||||
// Peer is the peer whose protocols were updated.
|
||||
Peer peer.ID
|
||||
// Added enumerates the protocols that were added by this peer.
|
||||
Added []protocol.ID
|
||||
// Removed enumerates the protocols that were removed by this peer.
|
||||
Removed []protocol.ID
|
||||
}
|
||||
|
||||
// EvtLocalProtocolsUpdated should be emitted when stream handlers are attached or detached from the local host.
|
||||
// For handlers attached with a matcher predicate (host.SetStreamHandlerMatch()), only the protocol ID will be
|
||||
// included in this event.
|
||||
type EvtLocalProtocolsUpdated struct {
|
||||
// Added enumerates the protocols that were added locally.
|
||||
Added []protocol.ID
|
||||
// Removed enumerates the protocols that were removed locally.
|
||||
Removed []protocol.ID
|
||||
}
|
||||
13
vendor/github.com/libp2p/go-libp2p/core/event/reachability.go
generated
vendored
Normal file
13
vendor/github.com/libp2p/go-libp2p/core/event/reachability.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
)
|
||||
|
||||
// EvtLocalReachabilityChanged is an event struct to be emitted when the local's
|
||||
// node reachability changes state.
|
||||
//
|
||||
// This event is usually emitted by the AutoNAT subsystem.
|
||||
type EvtLocalReachabilityChanged struct {
|
||||
Reachability network.Reachability
|
||||
}
|
||||
11
vendor/github.com/libp2p/go-libp2p/core/host/helpers.go
generated
vendored
Normal file
11
vendor/github.com/libp2p/go-libp2p/core/host/helpers.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package host
|
||||
|
||||
import "github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
// InfoFromHost returns a peer.AddrInfo struct with the Host's ID and all of its Addrs.
|
||||
func InfoFromHost(h Host) *peer.AddrInfo {
|
||||
return &peer.AddrInfo{
|
||||
ID: h.ID(),
|
||||
Addrs: h.Addrs(),
|
||||
}
|
||||
}
|
||||
75
vendor/github.com/libp2p/go-libp2p/core/host/host.go
generated
vendored
Normal file
75
vendor/github.com/libp2p/go-libp2p/core/host/host.go
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
// Package host provides the core Host interface for libp2p.
|
||||
//
|
||||
// Host represents a single libp2p node in a peer-to-peer network.
|
||||
package host
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/connmgr"
|
||||
"github.com/libp2p/go-libp2p/core/event"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/peerstore"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
// Host is an object participating in a p2p network, which
|
||||
// implements protocols or provides services. It handles
|
||||
// requests like a Server, and issues requests like a Client.
|
||||
// It is called Host because it is both Server and Client (and Peer
|
||||
// may be confusing).
|
||||
type Host interface {
|
||||
// ID returns the (local) peer.ID associated with this Host
|
||||
ID() peer.ID
|
||||
|
||||
// Peerstore returns the Host's repository of Peer Addresses and Keys.
|
||||
Peerstore() peerstore.Peerstore
|
||||
|
||||
// Returns the listen addresses of the Host
|
||||
Addrs() []ma.Multiaddr
|
||||
|
||||
// Networks returns the Network interface of the Host
|
||||
Network() network.Network
|
||||
|
||||
// Mux returns the Mux multiplexing incoming streams to protocol handlers
|
||||
Mux() protocol.Switch
|
||||
|
||||
// Connect ensures there is a connection between this host and the peer with
|
||||
// given peer.ID. Connect will absorb the addresses in pi into its internal
|
||||
// peerstore. If there is not an active connection, Connect will issue a
|
||||
// h.Network.Dial, and block until a connection is open, or an error is
|
||||
// returned. // TODO: Relay + NAT.
|
||||
Connect(ctx context.Context, pi peer.AddrInfo) error
|
||||
|
||||
// SetStreamHandler sets the protocol handler on the Host's Mux.
|
||||
// This is equivalent to:
|
||||
// host.Mux().SetHandler(proto, handler)
|
||||
// (Thread-safe)
|
||||
SetStreamHandler(pid protocol.ID, handler network.StreamHandler)
|
||||
|
||||
// SetStreamHandlerMatch sets the protocol handler on the Host's Mux
|
||||
// using a matching function for protocol selection.
|
||||
SetStreamHandlerMatch(protocol.ID, func(protocol.ID) bool, network.StreamHandler)
|
||||
|
||||
// RemoveStreamHandler removes a handler on the mux that was set by
|
||||
// SetStreamHandler
|
||||
RemoveStreamHandler(pid protocol.ID)
|
||||
|
||||
// NewStream opens a new stream to given peer p, and writes a p2p/protocol
|
||||
// header with given ProtocolID. If there is no connection to p, attempts
|
||||
// to create one. If ProtocolID is "", writes no header.
|
||||
// (Thread-safe)
|
||||
NewStream(ctx context.Context, p peer.ID, pids ...protocol.ID) (network.Stream, error)
|
||||
|
||||
// Close shuts down the host, its Network, and services.
|
||||
Close() error
|
||||
|
||||
// ConnManager returns this hosts connection manager
|
||||
ConnManager() connmgr.ConnManager
|
||||
|
||||
// EventBus returns the hosts eventbus
|
||||
EventBus() event.Bus
|
||||
}
|
||||
18
vendor/github.com/libp2p/go-libp2p/core/internal/catch/catch.go
generated
vendored
Normal file
18
vendor/github.com/libp2p/go-libp2p/core/internal/catch/catch.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package catch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
)
|
||||
|
||||
var panicWriter io.Writer = os.Stderr
|
||||
|
||||
// HandlePanic handles and logs panics.
|
||||
func HandlePanic(rerr interface{}, err *error, where string) {
|
||||
if rerr != nil {
|
||||
fmt.Fprintf(panicWriter, "caught panic: %s\n%s\n", rerr, debug.Stack())
|
||||
*err = fmt.Errorf("panic in %s: %s", where, rerr)
|
||||
}
|
||||
}
|
||||
176
vendor/github.com/libp2p/go-libp2p/core/metrics/bandwidth.go
generated
vendored
Normal file
176
vendor/github.com/libp2p/go-libp2p/core/metrics/bandwidth.go
generated
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
// Package metrics provides metrics collection and reporting interfaces for libp2p.
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-flow-metrics"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
)
|
||||
|
||||
// BandwidthCounter tracks incoming and outgoing data transferred by the local peer.
|
||||
// Metrics are available for total bandwidth across all peers / protocols, as well
|
||||
// as segmented by remote peer ID and protocol ID.
|
||||
type BandwidthCounter struct {
|
||||
totalIn flow.Meter
|
||||
totalOut flow.Meter
|
||||
|
||||
protocolIn flow.MeterRegistry
|
||||
protocolOut flow.MeterRegistry
|
||||
|
||||
peerIn flow.MeterRegistry
|
||||
peerOut flow.MeterRegistry
|
||||
}
|
||||
|
||||
// NewBandwidthCounter creates a new BandwidthCounter.
|
||||
func NewBandwidthCounter() *BandwidthCounter {
|
||||
return new(BandwidthCounter)
|
||||
}
|
||||
|
||||
// LogSentMessage records the size of an outgoing message
|
||||
// without associating the bandwidth to a specific peer or protocol.
|
||||
func (bwc *BandwidthCounter) LogSentMessage(size int64) {
|
||||
bwc.totalOut.Mark(uint64(size))
|
||||
}
|
||||
|
||||
// LogRecvMessage records the size of an incoming message
|
||||
// without associating the bandwidth to a specific peer or protocol.
|
||||
func (bwc *BandwidthCounter) LogRecvMessage(size int64) {
|
||||
bwc.totalIn.Mark(uint64(size))
|
||||
}
|
||||
|
||||
// LogSentMessageStream records the size of an outgoing message over a single logical stream.
|
||||
// Bandwidth is associated with the given protocol.ID and peer.ID.
|
||||
func (bwc *BandwidthCounter) LogSentMessageStream(size int64, proto protocol.ID, p peer.ID) {
|
||||
bwc.protocolOut.Get(string(proto)).Mark(uint64(size))
|
||||
bwc.peerOut.Get(string(p)).Mark(uint64(size))
|
||||
}
|
||||
|
||||
// LogRecvMessageStream records the size of an incoming message over a single logical stream.
|
||||
// Bandwidth is associated with the given protocol.ID and peer.ID.
|
||||
func (bwc *BandwidthCounter) LogRecvMessageStream(size int64, proto protocol.ID, p peer.ID) {
|
||||
bwc.protocolIn.Get(string(proto)).Mark(uint64(size))
|
||||
bwc.peerIn.Get(string(p)).Mark(uint64(size))
|
||||
}
|
||||
|
||||
// GetBandwidthForPeer returns a Stats struct with bandwidth metrics associated with the given peer.ID.
|
||||
// The metrics returned include all traffic sent / received for the peer, regardless of protocol.
|
||||
func (bwc *BandwidthCounter) GetBandwidthForPeer(p peer.ID) (out Stats) {
|
||||
inSnap := bwc.peerIn.Get(string(p)).Snapshot()
|
||||
outSnap := bwc.peerOut.Get(string(p)).Snapshot()
|
||||
|
||||
return Stats{
|
||||
TotalIn: int64(inSnap.Total),
|
||||
TotalOut: int64(outSnap.Total),
|
||||
RateIn: inSnap.Rate,
|
||||
RateOut: outSnap.Rate,
|
||||
}
|
||||
}
|
||||
|
||||
// GetBandwidthForProtocol returns a Stats struct with bandwidth metrics associated with the given protocol.ID.
|
||||
// The metrics returned include all traffic sent / received for the protocol, regardless of which peers were
|
||||
// involved.
|
||||
func (bwc *BandwidthCounter) GetBandwidthForProtocol(proto protocol.ID) (out Stats) {
|
||||
inSnap := bwc.protocolIn.Get(string(proto)).Snapshot()
|
||||
outSnap := bwc.protocolOut.Get(string(proto)).Snapshot()
|
||||
|
||||
return Stats{
|
||||
TotalIn: int64(inSnap.Total),
|
||||
TotalOut: int64(outSnap.Total),
|
||||
RateIn: inSnap.Rate,
|
||||
RateOut: outSnap.Rate,
|
||||
}
|
||||
}
|
||||
|
||||
// GetBandwidthTotals returns a Stats struct with bandwidth metrics for all data sent / received by the
|
||||
// local peer, regardless of protocol or remote peer IDs.
|
||||
func (bwc *BandwidthCounter) GetBandwidthTotals() (out Stats) {
|
||||
inSnap := bwc.totalIn.Snapshot()
|
||||
outSnap := bwc.totalOut.Snapshot()
|
||||
|
||||
return Stats{
|
||||
TotalIn: int64(inSnap.Total),
|
||||
TotalOut: int64(outSnap.Total),
|
||||
RateIn: inSnap.Rate,
|
||||
RateOut: outSnap.Rate,
|
||||
}
|
||||
}
|
||||
|
||||
// GetBandwidthByPeer returns a map of all remembered peers and the bandwidth
|
||||
// metrics with respect to each. This method may be very expensive.
|
||||
func (bwc *BandwidthCounter) GetBandwidthByPeer() map[peer.ID]Stats {
|
||||
peers := make(map[peer.ID]Stats)
|
||||
|
||||
bwc.peerIn.ForEach(func(p string, meter *flow.Meter) {
|
||||
id := peer.ID(p)
|
||||
snap := meter.Snapshot()
|
||||
|
||||
stat := peers[id]
|
||||
stat.TotalIn = int64(snap.Total)
|
||||
stat.RateIn = snap.Rate
|
||||
peers[id] = stat
|
||||
})
|
||||
|
||||
bwc.peerOut.ForEach(func(p string, meter *flow.Meter) {
|
||||
id := peer.ID(p)
|
||||
snap := meter.Snapshot()
|
||||
|
||||
stat := peers[id]
|
||||
stat.TotalOut = int64(snap.Total)
|
||||
stat.RateOut = snap.Rate
|
||||
peers[id] = stat
|
||||
})
|
||||
|
||||
return peers
|
||||
}
|
||||
|
||||
// GetBandwidthByProtocol returns a map of all remembered protocols and
|
||||
// the bandwidth metrics with respect to each. This method may be moderately
|
||||
// expensive.
|
||||
func (bwc *BandwidthCounter) GetBandwidthByProtocol() map[protocol.ID]Stats {
|
||||
protocols := make(map[protocol.ID]Stats)
|
||||
|
||||
bwc.protocolIn.ForEach(func(p string, meter *flow.Meter) {
|
||||
id := protocol.ID(p)
|
||||
snap := meter.Snapshot()
|
||||
|
||||
stat := protocols[id]
|
||||
stat.TotalIn = int64(snap.Total)
|
||||
stat.RateIn = snap.Rate
|
||||
protocols[id] = stat
|
||||
})
|
||||
|
||||
bwc.protocolOut.ForEach(func(p string, meter *flow.Meter) {
|
||||
id := protocol.ID(p)
|
||||
snap := meter.Snapshot()
|
||||
|
||||
stat := protocols[id]
|
||||
stat.TotalOut = int64(snap.Total)
|
||||
stat.RateOut = snap.Rate
|
||||
protocols[id] = stat
|
||||
})
|
||||
|
||||
return protocols
|
||||
}
|
||||
|
||||
// Reset clears all stats.
|
||||
func (bwc *BandwidthCounter) Reset() {
|
||||
bwc.totalIn.Reset()
|
||||
bwc.totalOut.Reset()
|
||||
|
||||
bwc.protocolIn.Clear()
|
||||
bwc.protocolOut.Clear()
|
||||
|
||||
bwc.peerIn.Clear()
|
||||
bwc.peerOut.Clear()
|
||||
}
|
||||
|
||||
// TrimIdle trims all timers idle since the given time.
|
||||
func (bwc *BandwidthCounter) TrimIdle(since time.Time) {
|
||||
bwc.peerIn.TrimIdle(since)
|
||||
bwc.peerOut.TrimIdle(since)
|
||||
bwc.protocolIn.TrimIdle(since)
|
||||
bwc.protocolOut.TrimIdle(since)
|
||||
}
|
||||
31
vendor/github.com/libp2p/go-libp2p/core/metrics/reporter.go
generated
vendored
Normal file
31
vendor/github.com/libp2p/go-libp2p/core/metrics/reporter.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
// Package metrics provides metrics collection and reporting interfaces for libp2p.
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
)
|
||||
|
||||
// Stats represents a point-in-time snapshot of bandwidth metrics.
|
||||
//
|
||||
// The TotalIn and TotalOut fields record cumulative bytes sent / received.
|
||||
// The RateIn and RateOut fields record bytes sent / received per second.
|
||||
type Stats struct {
|
||||
TotalIn int64
|
||||
TotalOut int64
|
||||
RateIn float64
|
||||
RateOut float64
|
||||
}
|
||||
|
||||
// Reporter provides methods for logging and retrieving metrics.
|
||||
type Reporter interface {
|
||||
LogSentMessage(int64)
|
||||
LogRecvMessage(int64)
|
||||
LogSentMessageStream(int64, protocol.ID, peer.ID)
|
||||
LogRecvMessageStream(int64, protocol.ID, peer.ID)
|
||||
GetBandwidthForPeer(peer.ID) Stats
|
||||
GetBandwidthForProtocol(protocol.ID) Stats
|
||||
GetBandwidthTotals() Stats
|
||||
GetBandwidthByPeer() map[peer.ID]Stats
|
||||
GetBandwidthByProtocol() map[protocol.ID]Stats
|
||||
}
|
||||
93
vendor/github.com/libp2p/go-libp2p/core/network/conn.go
generated
vendored
Normal file
93
vendor/github.com/libp2p/go-libp2p/core/network/conn.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
ic "github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
// Conn is a connection to a remote peer. It multiplexes streams.
|
||||
// Usually there is no need to use a Conn directly, but it may
|
||||
// be useful to get information about the peer on the other side:
|
||||
//
|
||||
// stream.Conn().RemotePeer()
|
||||
type Conn interface {
|
||||
io.Closer
|
||||
|
||||
ConnSecurity
|
||||
ConnMultiaddrs
|
||||
ConnStat
|
||||
ConnScoper
|
||||
|
||||
// ID returns an identifier that uniquely identifies this Conn within this
|
||||
// host, during this run. Connection IDs may repeat across restarts.
|
||||
ID() string
|
||||
|
||||
// NewStream constructs a new Stream over this conn.
|
||||
NewStream(context.Context) (Stream, error)
|
||||
|
||||
// GetStreams returns all open streams over this conn.
|
||||
GetStreams() []Stream
|
||||
|
||||
// IsClosed returns whether a connection is fully closed, so it can
|
||||
// be garbage collected.
|
||||
IsClosed() bool
|
||||
}
|
||||
|
||||
// ConnectionState holds information about the connection.
|
||||
type ConnectionState struct {
|
||||
// The stream multiplexer used on this connection (if any). For example: /yamux/1.0.0
|
||||
StreamMultiplexer protocol.ID
|
||||
// The security protocol used on this connection (if any). For example: /tls/1.0.0
|
||||
Security protocol.ID
|
||||
// the transport used on this connection. For example: tcp
|
||||
Transport string
|
||||
// indicates whether StreamMultiplexer was selected using inlined muxer negotiation
|
||||
UsedEarlyMuxerNegotiation bool
|
||||
}
|
||||
|
||||
// ConnSecurity is the interface that one can mix into a connection interface to
|
||||
// give it the security methods.
|
||||
type ConnSecurity interface {
|
||||
// LocalPeer returns our peer ID
|
||||
LocalPeer() peer.ID
|
||||
|
||||
// RemotePeer returns the peer ID of the remote peer.
|
||||
RemotePeer() peer.ID
|
||||
|
||||
// RemotePublicKey returns the public key of the remote peer.
|
||||
RemotePublicKey() ic.PubKey
|
||||
|
||||
// ConnState returns information about the connection state.
|
||||
ConnState() ConnectionState
|
||||
}
|
||||
|
||||
// ConnMultiaddrs is an interface mixin for connection types that provide multiaddr
|
||||
// addresses for the endpoints.
|
||||
type ConnMultiaddrs interface {
|
||||
// LocalMultiaddr returns the local Multiaddr associated
|
||||
// with this connection
|
||||
LocalMultiaddr() ma.Multiaddr
|
||||
|
||||
// RemoteMultiaddr returns the remote Multiaddr associated
|
||||
// with this connection
|
||||
RemoteMultiaddr() ma.Multiaddr
|
||||
}
|
||||
|
||||
// ConnStat is an interface mixin for connection types that provide connection statistics.
|
||||
type ConnStat interface {
|
||||
// Stat stores metadata pertaining to this conn.
|
||||
Stat() ConnStats
|
||||
}
|
||||
|
||||
// ConnScoper is the interface that one can mix into a connection interface to give it a resource
|
||||
// management scope
|
||||
type ConnScoper interface {
|
||||
// Scope returns the user view of this connection's resource scope
|
||||
Scope() ConnScope
|
||||
}
|
||||
110
vendor/github.com/libp2p/go-libp2p/core/network/context.go
generated
vendored
Normal file
110
vendor/github.com/libp2p/go-libp2p/core/network/context.go
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DialPeerTimeout is the default timeout for a single call to `DialPeer`. When
|
||||
// there are multiple concurrent calls to `DialPeer`, this timeout will apply to
|
||||
// each independently.
|
||||
var DialPeerTimeout = 60 * time.Second
|
||||
|
||||
type noDialCtxKey struct{}
|
||||
type dialPeerTimeoutCtxKey struct{}
|
||||
type forceDirectDialCtxKey struct{}
|
||||
type useTransientCtxKey struct{}
|
||||
type simConnectCtxKey struct{ isClient bool }
|
||||
|
||||
var noDial = noDialCtxKey{}
|
||||
var forceDirectDial = forceDirectDialCtxKey{}
|
||||
var useTransient = useTransientCtxKey{}
|
||||
var simConnectIsServer = simConnectCtxKey{}
|
||||
var simConnectIsClient = simConnectCtxKey{isClient: true}
|
||||
|
||||
// EXPERIMENTAL
|
||||
// WithForceDirectDial constructs a new context with an option that instructs the network
|
||||
// to attempt to force a direct connection to a peer via a dial even if a proxied connection to it already exists.
|
||||
func WithForceDirectDial(ctx context.Context, reason string) context.Context {
|
||||
return context.WithValue(ctx, forceDirectDial, reason)
|
||||
}
|
||||
|
||||
// EXPERIMENTAL
|
||||
// GetForceDirectDial returns true if the force direct dial option is set in the context.
|
||||
func GetForceDirectDial(ctx context.Context) (forceDirect bool, reason string) {
|
||||
v := ctx.Value(forceDirectDial)
|
||||
if v != nil {
|
||||
return true, v.(string)
|
||||
}
|
||||
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// WithSimultaneousConnect constructs a new context with an option that instructs the transport
|
||||
// to apply hole punching logic where applicable.
|
||||
// EXPERIMENTAL
|
||||
func WithSimultaneousConnect(ctx context.Context, isClient bool, reason string) context.Context {
|
||||
if isClient {
|
||||
return context.WithValue(ctx, simConnectIsClient, reason)
|
||||
}
|
||||
return context.WithValue(ctx, simConnectIsServer, reason)
|
||||
}
|
||||
|
||||
// GetSimultaneousConnect returns true if the simultaneous connect option is set in the context.
|
||||
// EXPERIMENTAL
|
||||
func GetSimultaneousConnect(ctx context.Context) (simconnect bool, isClient bool, reason string) {
|
||||
if v := ctx.Value(simConnectIsClient); v != nil {
|
||||
return true, true, v.(string)
|
||||
}
|
||||
if v := ctx.Value(simConnectIsServer); v != nil {
|
||||
return true, false, v.(string)
|
||||
}
|
||||
return false, false, ""
|
||||
}
|
||||
|
||||
// WithNoDial constructs a new context with an option that instructs the network
|
||||
// to not attempt a new dial when opening a stream.
|
||||
func WithNoDial(ctx context.Context, reason string) context.Context {
|
||||
return context.WithValue(ctx, noDial, reason)
|
||||
}
|
||||
|
||||
// GetNoDial returns true if the no dial option is set in the context.
|
||||
func GetNoDial(ctx context.Context) (nodial bool, reason string) {
|
||||
v := ctx.Value(noDial)
|
||||
if v != nil {
|
||||
return true, v.(string)
|
||||
}
|
||||
|
||||
return false, ""
|
||||
}
|
||||
|
||||
// GetDialPeerTimeout returns the current DialPeer timeout (or the default).
|
||||
func GetDialPeerTimeout(ctx context.Context) time.Duration {
|
||||
if to, ok := ctx.Value(dialPeerTimeoutCtxKey{}).(time.Duration); ok {
|
||||
return to
|
||||
}
|
||||
return DialPeerTimeout
|
||||
}
|
||||
|
||||
// WithDialPeerTimeout returns a new context with the DialPeer timeout applied.
|
||||
//
|
||||
// This timeout overrides the default DialPeerTimeout and applies per-dial
|
||||
// independently.
|
||||
func WithDialPeerTimeout(ctx context.Context, timeout time.Duration) context.Context {
|
||||
return context.WithValue(ctx, dialPeerTimeoutCtxKey{}, timeout)
|
||||
}
|
||||
|
||||
// WithUseTransient constructs a new context with an option that instructs the network
|
||||
// that it is acceptable to use a transient connection when opening a new stream.
|
||||
func WithUseTransient(ctx context.Context, reason string) context.Context {
|
||||
return context.WithValue(ctx, useTransient, reason)
|
||||
}
|
||||
|
||||
// GetUseTransient returns true if the use transient option is set in the context.
|
||||
func GetUseTransient(ctx context.Context) (usetransient bool, reason string) {
|
||||
v := ctx.Value(useTransient)
|
||||
if v != nil {
|
||||
return true, v.(string)
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
33
vendor/github.com/libp2p/go-libp2p/core/network/errors.go
generated
vendored
Normal file
33
vendor/github.com/libp2p/go-libp2p/core/network/errors.go
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
)
|
||||
|
||||
type temporaryError string
|
||||
|
||||
func (e temporaryError) Error() string { return string(e) }
|
||||
func (e temporaryError) Temporary() bool { return true }
|
||||
func (e temporaryError) Timeout() bool { return false }
|
||||
|
||||
var _ net.Error = temporaryError("")
|
||||
|
||||
// ErrNoRemoteAddrs is returned when there are no addresses associated with a peer during a dial.
|
||||
var ErrNoRemoteAddrs = errors.New("no remote addresses")
|
||||
|
||||
// ErrNoConn is returned when attempting to open a stream to a peer with the NoDial
|
||||
// option and no usable connection is available.
|
||||
var ErrNoConn = errors.New("no usable connection to peer")
|
||||
|
||||
// ErrTransientConn is returned when attempting to open a stream to a peer with only a transient
|
||||
// connection, without specifying the UseTransient option.
|
||||
var ErrTransientConn = errors.New("transient connection to peer")
|
||||
|
||||
// ErrResourceLimitExceeded is returned when attempting to perform an operation that would
|
||||
// exceed system resource limits.
|
||||
var ErrResourceLimitExceeded = temporaryError("resource limit exceeded")
|
||||
|
||||
// ErrResourceScopeClosed is returned when attempting to reserve resources in a closed resource
|
||||
// scope.
|
||||
var ErrResourceScopeClosed = errors.New("resource scope closed")
|
||||
95
vendor/github.com/libp2p/go-libp2p/core/network/mux.go
generated
vendored
Normal file
95
vendor/github.com/libp2p/go-libp2p/core/network/mux.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ErrReset is returned when reading or writing on a reset stream.
|
||||
var ErrReset = errors.New("stream reset")
|
||||
|
||||
// MuxedStream is a bidirectional io pipe within a connection.
|
||||
type MuxedStream interface {
|
||||
io.Reader
|
||||
io.Writer
|
||||
|
||||
// Close closes the stream.
|
||||
//
|
||||
// * Any buffered data for writing will be flushed.
|
||||
// * Future reads will fail.
|
||||
// * Any in-progress reads/writes will be interrupted.
|
||||
//
|
||||
// Close may be asynchronous and _does not_ guarantee receipt of the
|
||||
// data.
|
||||
//
|
||||
// Close closes the stream for both reading and writing.
|
||||
// Close is equivalent to calling `CloseRead` and `CloseWrite`. Importantly, Close will not wait for any form of acknowledgment.
|
||||
// If acknowledgment is required, the caller must call `CloseWrite`, then wait on the stream for a response (or an EOF),
|
||||
// then call Close() to free the stream object.
|
||||
//
|
||||
// When done with a stream, the user must call either Close() or `Reset()` to discard the stream, even after calling `CloseRead` and/or `CloseWrite`.
|
||||
io.Closer
|
||||
|
||||
// CloseWrite closes the stream for writing but leaves it open for
|
||||
// reading.
|
||||
//
|
||||
// CloseWrite does not free the stream, users must still call Close or
|
||||
// Reset.
|
||||
CloseWrite() error
|
||||
|
||||
// CloseRead closes the stream for reading but leaves it open for
|
||||
// writing.
|
||||
//
|
||||
// When CloseRead is called, all in-progress Read calls are interrupted with a non-EOF error and
|
||||
// no further calls to Read will succeed.
|
||||
//
|
||||
// The handling of new incoming data on the stream after calling this function is implementation defined.
|
||||
//
|
||||
// CloseRead does not free the stream, users must still call Close or
|
||||
// Reset.
|
||||
CloseRead() error
|
||||
|
||||
// Reset closes both ends of the stream. Use this to tell the remote
|
||||
// side to hang up and go away.
|
||||
Reset() error
|
||||
|
||||
SetDeadline(time.Time) error
|
||||
SetReadDeadline(time.Time) error
|
||||
SetWriteDeadline(time.Time) error
|
||||
}
|
||||
|
||||
// MuxedConn represents a connection to a remote peer that has been
|
||||
// extended to support stream multiplexing.
|
||||
//
|
||||
// A MuxedConn allows a single net.Conn connection to carry many logically
|
||||
// independent bidirectional streams of binary data.
|
||||
//
|
||||
// Together with network.ConnSecurity, MuxedConn is a component of the
|
||||
// transport.CapableConn interface, which represents a "raw" network
|
||||
// connection that has been "upgraded" to support the libp2p capabilities
|
||||
// of secure communication and stream multiplexing.
|
||||
type MuxedConn interface {
|
||||
// Close closes the stream muxer and the the underlying net.Conn.
|
||||
io.Closer
|
||||
|
||||
// IsClosed returns whether a connection is fully closed, so it can
|
||||
// be garbage collected.
|
||||
IsClosed() bool
|
||||
|
||||
// OpenStream creates a new stream.
|
||||
OpenStream(context.Context) (MuxedStream, error)
|
||||
|
||||
// AcceptStream accepts a stream opened by the other side.
|
||||
AcceptStream() (MuxedStream, error)
|
||||
}
|
||||
|
||||
// Multiplexer wraps a net.Conn with a stream multiplexing
|
||||
// implementation and returns a MuxedConn that supports opening
|
||||
// multiple streams over the underlying net.Conn
|
||||
type Multiplexer interface {
|
||||
// NewConn constructs a new connection
|
||||
NewConn(c net.Conn, isServer bool, scope PeerScope) (MuxedConn, error)
|
||||
}
|
||||
58
vendor/github.com/libp2p/go-libp2p/core/network/nattype.go
generated
vendored
Normal file
58
vendor/github.com/libp2p/go-libp2p/core/network/nattype.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
package network
|
||||
|
||||
// NATDeviceType indicates the type of the NAT device.
|
||||
type NATDeviceType int
|
||||
|
||||
const (
|
||||
// NATDeviceTypeUnknown indicates that the type of the NAT device is unknown.
|
||||
NATDeviceTypeUnknown NATDeviceType = iota
|
||||
|
||||
// NATDeviceTypeCone indicates that the NAT device is a Cone NAT.
|
||||
// A Cone NAT is a NAT where all outgoing connections from the same source IP address and port are mapped by the NAT device
|
||||
// to the same IP address and port irrespective of the destination address.
|
||||
// With regards to RFC 3489, this could be either a Full Cone NAT, a Restricted Cone NAT or a
|
||||
// Port Restricted Cone NAT. However, we do NOT differentiate between them here and simply classify all such NATs as a Cone NAT.
|
||||
// NAT traversal with hole punching is possible with a Cone NAT ONLY if the remote peer is ALSO behind a Cone NAT.
|
||||
// If the remote peer is behind a Symmetric NAT, hole punching will fail.
|
||||
NATDeviceTypeCone
|
||||
|
||||
// NATDeviceTypeSymmetric indicates that the NAT device is a Symmetric NAT.
|
||||
// A Symmetric NAT maps outgoing connections with different destination addresses to different IP addresses and ports,
|
||||
// even if they originate from the same source IP address and port.
|
||||
// NAT traversal with hole-punching is currently NOT possible in libp2p with Symmetric NATs irrespective of the remote peer's NAT type.
|
||||
NATDeviceTypeSymmetric
|
||||
)
|
||||
|
||||
func (r NATDeviceType) String() string {
|
||||
switch r {
|
||||
case 0:
|
||||
return "Unknown"
|
||||
case 1:
|
||||
return "Cone"
|
||||
case 2:
|
||||
return "Symmetric"
|
||||
default:
|
||||
return "unrecognized"
|
||||
}
|
||||
}
|
||||
|
||||
// NATTransportProtocol is the transport protocol for which the NAT Device Type has been determined.
|
||||
type NATTransportProtocol int
|
||||
|
||||
const (
|
||||
// NATTransportUDP means that the NAT Device Type has been determined for the UDP Protocol.
|
||||
NATTransportUDP NATTransportProtocol = iota
|
||||
// NATTransportTCP means that the NAT Device Type has been determined for the TCP Protocol.
|
||||
NATTransportTCP
|
||||
)
|
||||
|
||||
func (n NATTransportProtocol) String() string {
|
||||
switch n {
|
||||
case 0:
|
||||
return "UDP"
|
||||
case 1:
|
||||
return "TCP"
|
||||
default:
|
||||
return "unrecognized"
|
||||
}
|
||||
}
|
||||
198
vendor/github.com/libp2p/go-libp2p/core/network/network.go
generated
vendored
Normal file
198
vendor/github.com/libp2p/go-libp2p/core/network/network.go
generated
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
// Package network provides core networking abstractions for libp2p.
|
||||
//
|
||||
// The network package provides the high-level Network interface for interacting
|
||||
// with other libp2p peers, which is the primary public API for initiating and
|
||||
// accepting connections to remote peers.
|
||||
package network
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/peerstore"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
// MessageSizeMax is a soft (recommended) maximum for network messages.
|
||||
// One can write more, as the interface is a stream. But it is useful
|
||||
// to bunch it up into multiple read/writes when the whole message is
|
||||
// a single, large serialized object.
|
||||
const MessageSizeMax = 1 << 22 // 4 MB
|
||||
|
||||
// Direction represents which peer in a stream initiated a connection.
|
||||
type Direction int
|
||||
|
||||
const (
|
||||
// DirUnknown is the default direction.
|
||||
DirUnknown Direction = iota
|
||||
// DirInbound is for when the remote peer initiated a connection.
|
||||
DirInbound
|
||||
// DirOutbound is for when the local peer initiated a connection.
|
||||
DirOutbound
|
||||
)
|
||||
|
||||
const unrecognized = "(unrecognized)"
|
||||
|
||||
func (d Direction) String() string {
|
||||
str := [...]string{"Unknown", "Inbound", "Outbound"}
|
||||
if d < 0 || int(d) >= len(str) {
|
||||
return unrecognized
|
||||
}
|
||||
return str[d]
|
||||
}
|
||||
|
||||
// Connectedness signals the capacity for a connection with a given node.
|
||||
// It is used to signal to services and other peers whether a node is reachable.
|
||||
type Connectedness int
|
||||
|
||||
const (
|
||||
// NotConnected means no connection to peer, and no extra information (default)
|
||||
NotConnected Connectedness = iota
|
||||
|
||||
// Connected means has an open, live connection to peer
|
||||
Connected
|
||||
|
||||
// CanConnect means recently connected to peer, terminated gracefully
|
||||
CanConnect
|
||||
|
||||
// CannotConnect means recently attempted connecting but failed to connect.
|
||||
// (should signal "made effort, failed")
|
||||
CannotConnect
|
||||
)
|
||||
|
||||
func (c Connectedness) String() string {
|
||||
str := [...]string{"NotConnected", "Connected", "CanConnect", "CannotConnect"}
|
||||
if c < 0 || int(c) >= len(str) {
|
||||
return unrecognized
|
||||
}
|
||||
return str[c]
|
||||
}
|
||||
|
||||
// Reachability indicates how reachable a node is.
|
||||
type Reachability int
|
||||
|
||||
const (
|
||||
// ReachabilityUnknown indicates that the reachability status of the
|
||||
// node is unknown.
|
||||
ReachabilityUnknown Reachability = iota
|
||||
|
||||
// ReachabilityPublic indicates that the node is reachable from the
|
||||
// public internet.
|
||||
ReachabilityPublic
|
||||
|
||||
// ReachabilityPrivate indicates that the node is not reachable from the
|
||||
// public internet.
|
||||
//
|
||||
// NOTE: This node may _still_ be reachable via relays.
|
||||
ReachabilityPrivate
|
||||
)
|
||||
|
||||
func (r Reachability) String() string {
|
||||
str := [...]string{"Unknown", "Public", "Private"}
|
||||
if r < 0 || int(r) >= len(str) {
|
||||
return unrecognized
|
||||
}
|
||||
return str[r]
|
||||
}
|
||||
|
||||
// ConnStats stores metadata pertaining to a given Conn.
|
||||
type ConnStats struct {
|
||||
Stats
|
||||
// NumStreams is the number of streams on the connection.
|
||||
NumStreams int
|
||||
}
|
||||
|
||||
// Stats stores metadata pertaining to a given Stream / Conn.
|
||||
type Stats struct {
|
||||
// Direction specifies whether this is an inbound or an outbound connection.
|
||||
Direction Direction
|
||||
// Opened is the timestamp when this connection was opened.
|
||||
Opened time.Time
|
||||
// Transient indicates that this connection is transient and may be closed soon.
|
||||
Transient bool
|
||||
// Extra stores additional metadata about this connection.
|
||||
Extra map[interface{}]interface{}
|
||||
}
|
||||
|
||||
// StreamHandler is the type of function used to listen for
|
||||
// streams opened by the remote side.
|
||||
type StreamHandler func(Stream)
|
||||
|
||||
// Network is the interface used to connect to the outside world.
|
||||
// It dials and listens for connections. it uses a Swarm to pool
|
||||
// connections (see swarm pkg, and peerstream.Swarm). Connections
|
||||
// are encrypted with a TLS-like protocol.
|
||||
type Network interface {
|
||||
Dialer
|
||||
io.Closer
|
||||
|
||||
// SetStreamHandler sets the handler for new streams opened by the
|
||||
// remote side. This operation is thread-safe.
|
||||
SetStreamHandler(StreamHandler)
|
||||
|
||||
// NewStream returns a new stream to given peer p.
|
||||
// If there is no connection to p, attempts to create one.
|
||||
NewStream(context.Context, peer.ID) (Stream, error)
|
||||
|
||||
// Listen tells the network to start listening on given multiaddrs.
|
||||
Listen(...ma.Multiaddr) error
|
||||
|
||||
// ListenAddresses returns a list of addresses at which this network listens.
|
||||
ListenAddresses() []ma.Multiaddr
|
||||
|
||||
// InterfaceListenAddresses returns a list of addresses at which this network
|
||||
// listens. It expands "any interface" addresses (/ip4/0.0.0.0, /ip6/::) to
|
||||
// use the known local interfaces.
|
||||
InterfaceListenAddresses() ([]ma.Multiaddr, error)
|
||||
|
||||
// ResourceManager returns the ResourceManager associated with this network
|
||||
ResourceManager() ResourceManager
|
||||
}
|
||||
|
||||
// Dialer represents a service that can dial out to peers
|
||||
// (this is usually just a Network, but other services may not need the whole
|
||||
// stack, and thus it becomes easier to mock)
|
||||
type Dialer interface {
|
||||
// Peerstore returns the internal peerstore
|
||||
// This is useful to tell the dialer about a new address for a peer.
|
||||
// Or use one of the public keys found out over the network.
|
||||
Peerstore() peerstore.Peerstore
|
||||
|
||||
// LocalPeer returns the local peer associated with this network
|
||||
LocalPeer() peer.ID
|
||||
|
||||
// DialPeer establishes a connection to a given peer
|
||||
DialPeer(context.Context, peer.ID) (Conn, error)
|
||||
|
||||
// ClosePeer closes the connection to a given peer
|
||||
ClosePeer(peer.ID) error
|
||||
|
||||
// Connectedness returns a state signaling connection capabilities
|
||||
Connectedness(peer.ID) Connectedness
|
||||
|
||||
// Peers returns the peers connected
|
||||
Peers() []peer.ID
|
||||
|
||||
// Conns returns the connections in this Network
|
||||
Conns() []Conn
|
||||
|
||||
// ConnsToPeer returns the connections in this Network for given peer.
|
||||
ConnsToPeer(p peer.ID) []Conn
|
||||
|
||||
// Notify/StopNotify register and unregister a notifiee for signals
|
||||
Notify(Notifiee)
|
||||
StopNotify(Notifiee)
|
||||
}
|
||||
|
||||
// AddrDelay provides an address along with the delay after which the address
|
||||
// should be dialed
|
||||
type AddrDelay struct {
|
||||
Addr ma.Multiaddr
|
||||
Delay time.Duration
|
||||
}
|
||||
|
||||
// DialRanker provides a schedule of dialing the provided addresses
|
||||
type DialRanker func([]ma.Multiaddr) []AddrDelay
|
||||
67
vendor/github.com/libp2p/go-libp2p/core/network/notifee.go
generated
vendored
Normal file
67
vendor/github.com/libp2p/go-libp2p/core/network/notifee.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
// Notifiee is an interface for an object wishing to receive
|
||||
// notifications from a Network.
|
||||
type Notifiee interface {
|
||||
Listen(Network, ma.Multiaddr) // called when network starts listening on an addr
|
||||
ListenClose(Network, ma.Multiaddr) // called when network stops listening on an addr
|
||||
Connected(Network, Conn) // called when a connection opened
|
||||
Disconnected(Network, Conn) // called when a connection closed
|
||||
}
|
||||
|
||||
// NotifyBundle implements Notifiee by calling any of the functions set on it,
|
||||
// and nop'ing if they are unset. This is the easy way to register for
|
||||
// notifications.
|
||||
type NotifyBundle struct {
|
||||
ListenF func(Network, ma.Multiaddr)
|
||||
ListenCloseF func(Network, ma.Multiaddr)
|
||||
|
||||
ConnectedF func(Network, Conn)
|
||||
DisconnectedF func(Network, Conn)
|
||||
}
|
||||
|
||||
var _ Notifiee = (*NotifyBundle)(nil)
|
||||
|
||||
// Listen calls ListenF if it is not null.
|
||||
func (nb *NotifyBundle) Listen(n Network, a ma.Multiaddr) {
|
||||
if nb.ListenF != nil {
|
||||
nb.ListenF(n, a)
|
||||
}
|
||||
}
|
||||
|
||||
// ListenClose calls ListenCloseF if it is not null.
|
||||
func (nb *NotifyBundle) ListenClose(n Network, a ma.Multiaddr) {
|
||||
if nb.ListenCloseF != nil {
|
||||
nb.ListenCloseF(n, a)
|
||||
}
|
||||
}
|
||||
|
||||
// Connected calls ConnectedF if it is not null.
|
||||
func (nb *NotifyBundle) Connected(n Network, c Conn) {
|
||||
if nb.ConnectedF != nil {
|
||||
nb.ConnectedF(n, c)
|
||||
}
|
||||
}
|
||||
|
||||
// Disconnected calls DisconnectedF if it is not null.
|
||||
func (nb *NotifyBundle) Disconnected(n Network, c Conn) {
|
||||
if nb.DisconnectedF != nil {
|
||||
nb.DisconnectedF(n, c)
|
||||
}
|
||||
}
|
||||
|
||||
// Global noop notifiee. Do not change.
|
||||
var GlobalNoopNotifiee = &NoopNotifiee{}
|
||||
|
||||
type NoopNotifiee struct{}
|
||||
|
||||
var _ Notifiee = (*NoopNotifiee)(nil)
|
||||
|
||||
func (nn *NoopNotifiee) Connected(n Network, c Conn) {}
|
||||
func (nn *NoopNotifiee) Disconnected(n Network, c Conn) {}
|
||||
func (nn *NoopNotifiee) Listen(n Network, addr ma.Multiaddr) {}
|
||||
func (nn *NoopNotifiee) ListenClose(n Network, addr ma.Multiaddr) {}
|
||||
326
vendor/github.com/libp2p/go-libp2p/core/network/rcmgr.go
generated
vendored
Normal file
326
vendor/github.com/libp2p/go-libp2p/core/network/rcmgr.go
generated
vendored
Normal file
@@ -0,0 +1,326 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
// ResourceManager is the interface to the network resource management subsystem.
|
||||
// The ResourceManager tracks and accounts for resource usage in the stack, from the internals
|
||||
// to the application, and provides a mechanism to limit resource usage according to a user
|
||||
// configurable policy.
|
||||
//
|
||||
// Resource Management through the ResourceManager is based on the concept of Resource
|
||||
// Management Scopes, whereby resource usage is constrained by a DAG of scopes,
|
||||
// The following diagram illustrates the structure of the resource constraint DAG:
|
||||
// System
|
||||
//
|
||||
// +------------> Transient.............+................+
|
||||
// | . .
|
||||
// +------------> Service------------- . ----------+ .
|
||||
// | . | .
|
||||
// +-------------> Protocol----------- . ----------+ .
|
||||
// | . | .
|
||||
// +--------------> Peer \ | .
|
||||
// +------------> Connection | .
|
||||
// | \ \
|
||||
// +---------------------------> Stream
|
||||
//
|
||||
// The basic resources accounted by the ResourceManager include memory, streams, connections,
|
||||
// and file descriptors. These account for both space and time used by
|
||||
// the stack, as each resource has a direct effect on the system
|
||||
// availability and performance.
|
||||
//
|
||||
// The modus operandi of the resource manager is to restrict resource usage at the time of
|
||||
// reservation. When a component of the stack needs to use a resource, it reserves it in the
|
||||
// appropriate scope. The resource manager gates the reservation against the scope applicable
|
||||
// limits; if the limit is exceeded, then an error (wrapping ErrResourceLimitExceeded) and it
|
||||
// is up the component to act accordingly. At the lower levels of the stack, this will normally
|
||||
// signal a failure of some sorts, like failing to opening a stream or a connection, which will
|
||||
// propagate to the programmer. Some components may be able to handle resource reservation failure
|
||||
// more gracefully; for instance a muxer trying to grow a buffer for a window change, will simply
|
||||
// retain the existing window size and continue to operate normally albeit with some degraded
|
||||
// throughput.
|
||||
// All resources reserved in some scope are released when the scope is closed. For low level
|
||||
// scopes, mainly Connection and Stream scopes, this happens when the connection or stream is
|
||||
// closed.
|
||||
//
|
||||
// Service programmers will typically use the resource manager to reserve memory
|
||||
// for their subsystem.
|
||||
// This happens with two avenues: the programmer can attach a stream to a service, whereby
|
||||
// resources reserved by the stream are automatically accounted in the service budget; or the
|
||||
// programmer may directly interact with the service scope, by using ViewService through the
|
||||
// resource manager interface.
|
||||
//
|
||||
// Application programmers can also directly reserve memory in some applicable scope. In order
|
||||
// to facilitate control flow delimited resource accounting, all scopes defined in the system
|
||||
// allow for the user to create spans. Spans are temporary scopes rooted at some
|
||||
// other scope and release their resources when the programmer is done with them. Span
|
||||
// scopes can form trees, with nested spans.
|
||||
//
|
||||
// Typical Usage:
|
||||
// - Low level components of the system (transports, muxers) all have access to the resource
|
||||
// manager and create connection and stream scopes through it. These scopes are accessible
|
||||
// to the user, albeit with a narrower interface, through Conn and Stream objects who have
|
||||
// a Scope method.
|
||||
// - Services typically center around streams, where the programmer can attach streams to a
|
||||
// particular service. They can also directly reserve memory for a service by accessing the
|
||||
// service scope using the ResourceManager interface.
|
||||
// - Applications that want to account for their network resource usage can reserve memory,
|
||||
// typically using a span, directly in the System or a Service scope; they can also
|
||||
// opt to use appropriate stream scopes for streams that they create or own.
|
||||
//
|
||||
// User Serviceable Parts: the user has the option to specify their own implementation of the
|
||||
// interface. We provide a canonical implementation in the go-libp2p-resource-manager package.
|
||||
// The user of that package can specify limits for the various scopes, which can be static
|
||||
// or dynamic.
|
||||
//
|
||||
// WARNING The ResourceManager interface is considered experimental and subject to change
|
||||
// in subsequent releases.
|
||||
type ResourceManager interface {
|
||||
ResourceScopeViewer
|
||||
|
||||
// OpenConnection creates a new connection scope not yet associated with any peer; the connection
|
||||
// is scoped at the transient scope.
|
||||
// The caller owns the returned scope and is responsible for calling Done in order to signify
|
||||
// the end of the scope's span.
|
||||
OpenConnection(dir Direction, usefd bool, endpoint multiaddr.Multiaddr) (ConnManagementScope, error)
|
||||
|
||||
// OpenStream creates a new stream scope, initially unnegotiated.
|
||||
// An unnegotiated stream will be initially unattached to any protocol scope
|
||||
// and constrained by the transient scope.
|
||||
// The caller owns the returned scope and is responsible for calling Done in order to signify
|
||||
// the end of th scope's span.
|
||||
OpenStream(p peer.ID, dir Direction) (StreamManagementScope, error)
|
||||
|
||||
// Close closes the resource manager
|
||||
Close() error
|
||||
}
|
||||
|
||||
// ResourceScopeViewer is a mixin interface providing view methods for accessing top level
|
||||
// scopes.
|
||||
type ResourceScopeViewer interface {
|
||||
// ViewSystem views the system-wide resource scope.
|
||||
// The system scope is the top level scope that accounts for global
|
||||
// resource usage at all levels of the system. This scope constrains all
|
||||
// other scopes and institutes global hard limits.
|
||||
ViewSystem(func(ResourceScope) error) error
|
||||
|
||||
// ViewTransient views the transient (DMZ) resource scope.
|
||||
// The transient scope accounts for resources that are in the process of
|
||||
// full establishment. For instance, a new connection prior to the
|
||||
// handshake does not belong to any peer, but it still needs to be
|
||||
// constrained as this opens an avenue for attacks in transient resource
|
||||
// usage. Similarly, a stream that has not negotiated a protocol yet is
|
||||
// constrained by the transient scope.
|
||||
ViewTransient(func(ResourceScope) error) error
|
||||
|
||||
// ViewService retrieves a service-specific scope.
|
||||
ViewService(string, func(ServiceScope) error) error
|
||||
|
||||
// ViewProtocol views the resource management scope for a specific protocol.
|
||||
ViewProtocol(protocol.ID, func(ProtocolScope) error) error
|
||||
|
||||
// ViewPeer views the resource management scope for a specific peer.
|
||||
ViewPeer(peer.ID, func(PeerScope) error) error
|
||||
}
|
||||
|
||||
const (
|
||||
// ReservationPriorityLow is a reservation priority that indicates a reservation if the scope
|
||||
// memory utilization is at 40% or less.
|
||||
ReservationPriorityLow uint8 = 101
|
||||
// Reservation PriorityMedium is a reservation priority that indicates a reservation if the scope
|
||||
// memory utilization is at 60% or less.
|
||||
ReservationPriorityMedium uint8 = 152
|
||||
// ReservationPriorityHigh is a reservation priority that indicates a reservation if the scope
|
||||
// memory utilization is at 80% or less.
|
||||
ReservationPriorityHigh uint8 = 203
|
||||
// ReservationPriorityAlways is a reservation priority that indicates a reservation if there is
|
||||
// enough memory, regardless of scope utilization.
|
||||
ReservationPriorityAlways uint8 = 255
|
||||
)
|
||||
|
||||
// ResourceScope is the interface for all scopes.
|
||||
type ResourceScope interface {
|
||||
// ReserveMemory reserves memory/buffer space in the scope; the unit is bytes.
|
||||
//
|
||||
// If ReserveMemory returns an error, then no memory was reserved and the caller should handle
|
||||
// the failure condition.
|
||||
//
|
||||
// The priority argument indicates the priority of the memory reservation. A reservation
|
||||
// will fail if the available memory is less than (1+prio)/256 of the scope limit, providing
|
||||
// a mechanism to gracefully handle optional reservations that might overload the system.
|
||||
// For instance, a muxer growing a window buffer will use a low priority and only grow the buffer
|
||||
// if there is no memory pressure in the system.
|
||||
//
|
||||
// There are 4 predefined priority levels, Low, Medium, High and Always,
|
||||
// capturing common patterns, but the user is free to use any granularity applicable to his case.
|
||||
ReserveMemory(size int, prio uint8) error
|
||||
|
||||
// ReleaseMemory explicitly releases memory previously reserved with ReserveMemory
|
||||
ReleaseMemory(size int)
|
||||
|
||||
// Stat retrieves current resource usage for the scope.
|
||||
Stat() ScopeStat
|
||||
|
||||
// BeginSpan creates a new span scope rooted at this scope
|
||||
BeginSpan() (ResourceScopeSpan, error)
|
||||
}
|
||||
|
||||
// ResourceScopeSpan is a ResourceScope with a delimited span.
|
||||
// Span scopes are control flow delimited and release all their associated resources
|
||||
// when the programmer calls Done.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// s, err := someScope.BeginSpan()
|
||||
// if err != nil { ... }
|
||||
// defer s.Done()
|
||||
//
|
||||
// if err := s.ReserveMemory(...); err != nil { ... }
|
||||
// // ... use memory
|
||||
type ResourceScopeSpan interface {
|
||||
ResourceScope
|
||||
// Done ends the span and releases associated resources.
|
||||
Done()
|
||||
}
|
||||
|
||||
// ServiceScope is the interface for service resource scopes
|
||||
type ServiceScope interface {
|
||||
ResourceScope
|
||||
|
||||
// Name returns the name of this service
|
||||
Name() string
|
||||
}
|
||||
|
||||
// ProtocolScope is the interface for protocol resource scopes.
|
||||
type ProtocolScope interface {
|
||||
ResourceScope
|
||||
|
||||
// Protocol returns the protocol for this scope
|
||||
Protocol() protocol.ID
|
||||
}
|
||||
|
||||
// PeerScope is the interface for peer resource scopes.
|
||||
type PeerScope interface {
|
||||
ResourceScope
|
||||
|
||||
// Peer returns the peer ID for this scope
|
||||
Peer() peer.ID
|
||||
}
|
||||
|
||||
// ConnManagementScope is the low level interface for connection resource scopes.
|
||||
// This interface is used by the low level components of the system who create and own
|
||||
// the span of a connection scope.
|
||||
type ConnManagementScope interface {
|
||||
ResourceScopeSpan
|
||||
|
||||
// PeerScope returns the peer scope associated with this connection.
|
||||
// It returns nil if the connection is not yet associated with any peer.
|
||||
PeerScope() PeerScope
|
||||
|
||||
// SetPeer sets the peer for a previously unassociated connection
|
||||
SetPeer(peer.ID) error
|
||||
}
|
||||
|
||||
// ConnScope is the user view of a connection scope
|
||||
type ConnScope interface {
|
||||
ResourceScope
|
||||
}
|
||||
|
||||
// StreamManagementScope is the interface for stream resource scopes.
|
||||
// This interface is used by the low level components of the system who create and own
|
||||
// the span of a stream scope.
|
||||
type StreamManagementScope interface {
|
||||
ResourceScopeSpan
|
||||
|
||||
// ProtocolScope returns the protocol resource scope associated with this stream.
|
||||
// It returns nil if the stream is not associated with any protocol scope.
|
||||
ProtocolScope() ProtocolScope
|
||||
// SetProtocol sets the protocol for a previously unnegotiated stream
|
||||
SetProtocol(proto protocol.ID) error
|
||||
|
||||
// ServiceScope returns the service owning the stream, if any.
|
||||
ServiceScope() ServiceScope
|
||||
// SetService sets the service owning this stream.
|
||||
SetService(srv string) error
|
||||
|
||||
// PeerScope returns the peer resource scope associated with this stream.
|
||||
PeerScope() PeerScope
|
||||
}
|
||||
|
||||
// StreamScope is the user view of a StreamScope.
|
||||
type StreamScope interface {
|
||||
ResourceScope
|
||||
|
||||
// SetService sets the service owning this stream.
|
||||
SetService(srv string) error
|
||||
}
|
||||
|
||||
// ScopeStat is a struct containing resource accounting information.
|
||||
type ScopeStat struct {
|
||||
NumStreamsInbound int
|
||||
NumStreamsOutbound int
|
||||
NumConnsInbound int
|
||||
NumConnsOutbound int
|
||||
NumFD int
|
||||
|
||||
Memory int64
|
||||
}
|
||||
|
||||
// NullResourceManager is a stub for tests and initialization of default values
|
||||
type NullResourceManager struct{}
|
||||
|
||||
var _ ResourceScope = (*NullScope)(nil)
|
||||
var _ ResourceScopeSpan = (*NullScope)(nil)
|
||||
var _ ServiceScope = (*NullScope)(nil)
|
||||
var _ ProtocolScope = (*NullScope)(nil)
|
||||
var _ PeerScope = (*NullScope)(nil)
|
||||
var _ ConnManagementScope = (*NullScope)(nil)
|
||||
var _ ConnScope = (*NullScope)(nil)
|
||||
var _ StreamManagementScope = (*NullScope)(nil)
|
||||
var _ StreamScope = (*NullScope)(nil)
|
||||
|
||||
// NullScope is a stub for tests and initialization of default values
|
||||
type NullScope struct{}
|
||||
|
||||
func (n *NullResourceManager) ViewSystem(f func(ResourceScope) error) error {
|
||||
return f(&NullScope{})
|
||||
}
|
||||
func (n *NullResourceManager) ViewTransient(f func(ResourceScope) error) error {
|
||||
return f(&NullScope{})
|
||||
}
|
||||
func (n *NullResourceManager) ViewService(svc string, f func(ServiceScope) error) error {
|
||||
return f(&NullScope{})
|
||||
}
|
||||
func (n *NullResourceManager) ViewProtocol(p protocol.ID, f func(ProtocolScope) error) error {
|
||||
return f(&NullScope{})
|
||||
}
|
||||
func (n *NullResourceManager) ViewPeer(p peer.ID, f func(PeerScope) error) error {
|
||||
return f(&NullScope{})
|
||||
}
|
||||
func (n *NullResourceManager) OpenConnection(dir Direction, usefd bool, endpoint multiaddr.Multiaddr) (ConnManagementScope, error) {
|
||||
return &NullScope{}, nil
|
||||
}
|
||||
func (n *NullResourceManager) OpenStream(p peer.ID, dir Direction) (StreamManagementScope, error) {
|
||||
return &NullScope{}, nil
|
||||
}
|
||||
func (n *NullResourceManager) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *NullScope) ReserveMemory(size int, prio uint8) error { return nil }
|
||||
func (n *NullScope) ReleaseMemory(size int) {}
|
||||
func (n *NullScope) Stat() ScopeStat { return ScopeStat{} }
|
||||
func (n *NullScope) BeginSpan() (ResourceScopeSpan, error) { return &NullScope{}, nil }
|
||||
func (n *NullScope) Done() {}
|
||||
func (n *NullScope) Name() string { return "" }
|
||||
func (n *NullScope) Protocol() protocol.ID { return "" }
|
||||
func (n *NullScope) Peer() peer.ID { return "" }
|
||||
func (n *NullScope) PeerScope() PeerScope { return &NullScope{} }
|
||||
func (n *NullScope) SetPeer(peer.ID) error { return nil }
|
||||
func (n *NullScope) ProtocolScope() ProtocolScope { return &NullScope{} }
|
||||
func (n *NullScope) SetProtocol(proto protocol.ID) error { return nil }
|
||||
func (n *NullScope) ServiceScope() ServiceScope { return &NullScope{} }
|
||||
func (n *NullScope) SetService(srv string) error { return nil }
|
||||
30
vendor/github.com/libp2p/go-libp2p/core/network/stream.go
generated
vendored
Normal file
30
vendor/github.com/libp2p/go-libp2p/core/network/stream.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
)
|
||||
|
||||
// Stream represents a bidirectional channel between two agents in
|
||||
// a libp2p network. "agent" is as granular as desired, potentially
|
||||
// being a "request -> reply" pair, or whole protocols.
|
||||
//
|
||||
// Streams are backed by a multiplexer underneath the hood.
|
||||
type Stream interface {
|
||||
MuxedStream
|
||||
|
||||
// ID returns an identifier that uniquely identifies this Stream within this
|
||||
// host, during this run. Stream IDs may repeat across restarts.
|
||||
ID() string
|
||||
|
||||
Protocol() protocol.ID
|
||||
SetProtocol(id protocol.ID) error
|
||||
|
||||
// Stat returns metadata pertaining to this stream.
|
||||
Stat() Stats
|
||||
|
||||
// Conn returns the connection this stream is part of.
|
||||
Conn() Conn
|
||||
|
||||
// Scope returns the user's view of this stream's resource scope
|
||||
Scope() StreamScope
|
||||
}
|
||||
117
vendor/github.com/libp2p/go-libp2p/core/peer/addrinfo.go
generated
vendored
Normal file
117
vendor/github.com/libp2p/go-libp2p/core/peer/addrinfo.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
// AddrInfo is a small struct used to pass around a peer with
|
||||
// a set of addresses (and later, keys?).
|
||||
type AddrInfo struct {
|
||||
ID ID
|
||||
Addrs []ma.Multiaddr
|
||||
}
|
||||
|
||||
var _ fmt.Stringer = AddrInfo{}
|
||||
|
||||
func (pi AddrInfo) String() string {
|
||||
return fmt.Sprintf("{%v: %v}", pi.ID, pi.Addrs)
|
||||
}
|
||||
|
||||
var ErrInvalidAddr = fmt.Errorf("invalid p2p multiaddr")
|
||||
|
||||
// AddrInfosFromP2pAddrs converts a set of Multiaddrs to a set of AddrInfos.
|
||||
func AddrInfosFromP2pAddrs(maddrs ...ma.Multiaddr) ([]AddrInfo, error) {
|
||||
m := make(map[ID][]ma.Multiaddr)
|
||||
for _, maddr := range maddrs {
|
||||
transport, id := SplitAddr(maddr)
|
||||
if id == "" {
|
||||
return nil, ErrInvalidAddr
|
||||
}
|
||||
if transport == nil {
|
||||
if _, ok := m[id]; !ok {
|
||||
m[id] = nil
|
||||
}
|
||||
} else {
|
||||
m[id] = append(m[id], transport)
|
||||
}
|
||||
}
|
||||
ais := make([]AddrInfo, 0, len(m))
|
||||
for id, maddrs := range m {
|
||||
ais = append(ais, AddrInfo{ID: id, Addrs: maddrs})
|
||||
}
|
||||
return ais, nil
|
||||
}
|
||||
|
||||
// SplitAddr splits a p2p Multiaddr into a transport multiaddr and a peer ID.
|
||||
//
|
||||
// * Returns a nil transport if the address only contains a /p2p part.
|
||||
// * Returns an empty peer ID if the address doesn't contain a /p2p part.
|
||||
func SplitAddr(m ma.Multiaddr) (transport ma.Multiaddr, id ID) {
|
||||
if m == nil {
|
||||
return nil, ""
|
||||
}
|
||||
|
||||
transport, p2ppart := ma.SplitLast(m)
|
||||
if p2ppart == nil || p2ppart.Protocol().Code != ma.P_P2P {
|
||||
return m, ""
|
||||
}
|
||||
id = ID(p2ppart.RawValue()) // already validated by the multiaddr library.
|
||||
return transport, id
|
||||
}
|
||||
|
||||
// AddrInfoFromString builds an AddrInfo from the string representation of a Multiaddr
|
||||
func AddrInfoFromString(s string) (*AddrInfo, error) {
|
||||
a, err := ma.NewMultiaddr(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return AddrInfoFromP2pAddr(a)
|
||||
}
|
||||
|
||||
// AddrInfoFromP2pAddr converts a Multiaddr to an AddrInfo.
|
||||
func AddrInfoFromP2pAddr(m ma.Multiaddr) (*AddrInfo, error) {
|
||||
transport, id := SplitAddr(m)
|
||||
if id == "" {
|
||||
return nil, ErrInvalidAddr
|
||||
}
|
||||
info := &AddrInfo{ID: id}
|
||||
if transport != nil {
|
||||
info.Addrs = []ma.Multiaddr{transport}
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
// AddrInfoToP2pAddrs converts an AddrInfo to a list of Multiaddrs.
|
||||
func AddrInfoToP2pAddrs(pi *AddrInfo) ([]ma.Multiaddr, error) {
|
||||
p2ppart, err := ma.NewComponent("p2p", pi.ID.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(pi.Addrs) == 0 {
|
||||
return []ma.Multiaddr{p2ppart}, nil
|
||||
}
|
||||
addrs := make([]ma.Multiaddr, 0, len(pi.Addrs))
|
||||
for _, addr := range pi.Addrs {
|
||||
addrs = append(addrs, addr.Encapsulate(p2ppart))
|
||||
}
|
||||
return addrs, nil
|
||||
}
|
||||
|
||||
func (pi *AddrInfo) Loggable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"peerID": pi.ID.String(),
|
||||
"addrs": pi.Addrs,
|
||||
}
|
||||
}
|
||||
|
||||
// AddrInfosToIDs extracts the peer IDs from the passed AddrInfos and returns them in-order.
|
||||
func AddrInfosToIDs(pis []AddrInfo) []ID {
|
||||
ps := make([]ID, len(pis))
|
||||
for i, pi := range pis {
|
||||
ps[i] = pi.ID
|
||||
}
|
||||
return ps
|
||||
}
|
||||
48
vendor/github.com/libp2p/go-libp2p/core/peer/addrinfo_serde.go
generated
vendored
Normal file
48
vendor/github.com/libp2p/go-libp2p/core/peer/addrinfo_serde.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/internal/catch"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
// Helper struct for decoding as we can't unmarshal into an interface (Multiaddr).
|
||||
type addrInfoJson struct {
|
||||
ID ID
|
||||
Addrs []string
|
||||
}
|
||||
|
||||
func (pi AddrInfo) MarshalJSON() (res []byte, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "libp2p addr info marshal") }()
|
||||
|
||||
addrs := make([]string, len(pi.Addrs))
|
||||
for i, addr := range pi.Addrs {
|
||||
addrs[i] = addr.String()
|
||||
}
|
||||
return json.Marshal(&addrInfoJson{
|
||||
ID: pi.ID,
|
||||
Addrs: addrs,
|
||||
})
|
||||
}
|
||||
|
||||
func (pi *AddrInfo) UnmarshalJSON(b []byte) (err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "libp2p addr info unmarshal") }()
|
||||
var data addrInfoJson
|
||||
if err := json.Unmarshal(b, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
addrs := make([]ma.Multiaddr, len(data.Addrs))
|
||||
for i, addr := range data.Addrs {
|
||||
maddr, err := ma.NewMultiaddr(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addrs[i] = maddr
|
||||
}
|
||||
|
||||
pi.ID = data.ID
|
||||
pi.Addrs = addrs
|
||||
return nil
|
||||
}
|
||||
239
vendor/github.com/libp2p/go-libp2p/core/peer/pb/peer_record.pb.go
generated
vendored
Normal file
239
vendor/github.com/libp2p/go-libp2p/core/peer/pb/peer_record.pb.go
generated
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v3.21.12
|
||||
// source: pb/peer_record.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// PeerRecord messages contain information that is useful to share with other peers.
|
||||
// Currently, a PeerRecord contains the public listen addresses for a peer, but this
|
||||
// is expected to expand to include other information in the future.
|
||||
//
|
||||
// PeerRecords are designed to be serialized to bytes and placed inside of
|
||||
// SignedEnvelopes before sharing with other peers.
|
||||
// See https://github.com/libp2p/go-libp2p/core/record/pb/envelope.proto for
|
||||
// the SignedEnvelope definition.
|
||||
type PeerRecord struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// peer_id contains a libp2p peer id in its binary representation.
|
||||
PeerId []byte `protobuf:"bytes,1,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"`
|
||||
// seq contains a monotonically-increasing sequence counter to order PeerRecords in time.
|
||||
Seq uint64 `protobuf:"varint,2,opt,name=seq,proto3" json:"seq,omitempty"`
|
||||
// addresses is a list of public listen addresses for the peer.
|
||||
Addresses []*PeerRecord_AddressInfo `protobuf:"bytes,3,rep,name=addresses,proto3" json:"addresses,omitempty"`
|
||||
}
|
||||
|
||||
func (x *PeerRecord) Reset() {
|
||||
*x = PeerRecord{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_pb_peer_record_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PeerRecord) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PeerRecord) ProtoMessage() {}
|
||||
|
||||
func (x *PeerRecord) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_pb_peer_record_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PeerRecord.ProtoReflect.Descriptor instead.
|
||||
func (*PeerRecord) Descriptor() ([]byte, []int) {
|
||||
return file_pb_peer_record_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *PeerRecord) GetPeerId() []byte {
|
||||
if x != nil {
|
||||
return x.PeerId
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *PeerRecord) GetSeq() uint64 {
|
||||
if x != nil {
|
||||
return x.Seq
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PeerRecord) GetAddresses() []*PeerRecord_AddressInfo {
|
||||
if x != nil {
|
||||
return x.Addresses
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddressInfo is a wrapper around a binary multiaddr. It is defined as a
|
||||
// separate message to allow us to add per-address metadata in the future.
|
||||
type PeerRecord_AddressInfo struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Multiaddr []byte `protobuf:"bytes,1,opt,name=multiaddr,proto3" json:"multiaddr,omitempty"`
|
||||
}
|
||||
|
||||
func (x *PeerRecord_AddressInfo) Reset() {
|
||||
*x = PeerRecord_AddressInfo{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_pb_peer_record_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *PeerRecord_AddressInfo) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PeerRecord_AddressInfo) ProtoMessage() {}
|
||||
|
||||
func (x *PeerRecord_AddressInfo) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_pb_peer_record_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PeerRecord_AddressInfo.ProtoReflect.Descriptor instead.
|
||||
func (*PeerRecord_AddressInfo) Descriptor() ([]byte, []int) {
|
||||
return file_pb_peer_record_proto_rawDescGZIP(), []int{0, 0}
|
||||
}
|
||||
|
||||
func (x *PeerRecord_AddressInfo) GetMultiaddr() []byte {
|
||||
if x != nil {
|
||||
return x.Multiaddr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_pb_peer_record_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_pb_peer_record_proto_rawDesc = []byte{
|
||||
0x0a, 0x14, 0x70, 0x62, 0x2f, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x70, 0x65, 0x65, 0x72, 0x2e, 0x70, 0x62, 0x22,
|
||||
0xa3, 0x01, 0x0a, 0x0a, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x17,
|
||||
0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||
0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x65, 0x71, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x73, 0x65, 0x71, 0x12, 0x3d, 0x0a, 0x09, 0x61, 0x64, 0x64,
|
||||
0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70,
|
||||
0x65, 0x65, 0x72, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x63, 0x6f, 0x72,
|
||||
0x64, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x61,
|
||||
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x1a, 0x2b, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x72,
|
||||
0x65, 0x73, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x6d, 0x75, 0x6c, 0x74, 0x69,
|
||||
0x61, 0x64, 0x64, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x6d, 0x75, 0x6c, 0x74,
|
||||
0x69, 0x61, 0x64, 0x64, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_pb_peer_record_proto_rawDescOnce sync.Once
|
||||
file_pb_peer_record_proto_rawDescData = file_pb_peer_record_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_pb_peer_record_proto_rawDescGZIP() []byte {
|
||||
file_pb_peer_record_proto_rawDescOnce.Do(func() {
|
||||
file_pb_peer_record_proto_rawDescData = protoimpl.X.CompressGZIP(file_pb_peer_record_proto_rawDescData)
|
||||
})
|
||||
return file_pb_peer_record_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_pb_peer_record_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_pb_peer_record_proto_goTypes = []interface{}{
|
||||
(*PeerRecord)(nil), // 0: peer.pb.PeerRecord
|
||||
(*PeerRecord_AddressInfo)(nil), // 1: peer.pb.PeerRecord.AddressInfo
|
||||
}
|
||||
var file_pb_peer_record_proto_depIdxs = []int32{
|
||||
1, // 0: peer.pb.PeerRecord.addresses:type_name -> peer.pb.PeerRecord.AddressInfo
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_pb_peer_record_proto_init() }
|
||||
func file_pb_peer_record_proto_init() {
|
||||
if File_pb_peer_record_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_pb_peer_record_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*PeerRecord); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_pb_peer_record_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*PeerRecord_AddressInfo); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_pb_peer_record_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_pb_peer_record_proto_goTypes,
|
||||
DependencyIndexes: file_pb_peer_record_proto_depIdxs,
|
||||
MessageInfos: file_pb_peer_record_proto_msgTypes,
|
||||
}.Build()
|
||||
File_pb_peer_record_proto = out.File
|
||||
file_pb_peer_record_proto_rawDesc = nil
|
||||
file_pb_peer_record_proto_goTypes = nil
|
||||
file_pb_peer_record_proto_depIdxs = nil
|
||||
}
|
||||
29
vendor/github.com/libp2p/go-libp2p/core/peer/pb/peer_record.proto
generated
vendored
Normal file
29
vendor/github.com/libp2p/go-libp2p/core/peer/pb/peer_record.proto
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package peer.pb;
|
||||
|
||||
// PeerRecord messages contain information that is useful to share with other peers.
|
||||
// Currently, a PeerRecord contains the public listen addresses for a peer, but this
|
||||
// is expected to expand to include other information in the future.
|
||||
//
|
||||
// PeerRecords are designed to be serialized to bytes and placed inside of
|
||||
// SignedEnvelopes before sharing with other peers.
|
||||
// See https://github.com/libp2p/go-libp2p/core/record/pb/envelope.proto for
|
||||
// the SignedEnvelope definition.
|
||||
message PeerRecord {
|
||||
|
||||
// AddressInfo is a wrapper around a binary multiaddr. It is defined as a
|
||||
// separate message to allow us to add per-address metadata in the future.
|
||||
message AddressInfo {
|
||||
bytes multiaddr = 1;
|
||||
}
|
||||
|
||||
// peer_id contains a libp2p peer id in its binary representation.
|
||||
bytes peer_id = 1;
|
||||
|
||||
// seq contains a monotonically-increasing sequence counter to order PeerRecords in time.
|
||||
uint64 seq = 2;
|
||||
|
||||
// addresses is a list of public listen addresses for the peer.
|
||||
repeated AddressInfo addresses = 3;
|
||||
}
|
||||
194
vendor/github.com/libp2p/go-libp2p/core/peer/peer.go
generated
vendored
Normal file
194
vendor/github.com/libp2p/go-libp2p/core/peer/peer.go
generated
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
// Package peer implements an object used to represent peers in the libp2p network.
|
||||
package peer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
ic "github.com/libp2p/go-libp2p/core/crypto"
|
||||
b58 "github.com/mr-tron/base58/base58"
|
||||
mc "github.com/multiformats/go-multicodec"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrEmptyPeerID is an error for empty peer ID.
|
||||
ErrEmptyPeerID = errors.New("empty peer ID")
|
||||
// ErrNoPublicKey is an error for peer IDs that don't embed public keys
|
||||
ErrNoPublicKey = errors.New("public key is not embedded in peer ID")
|
||||
)
|
||||
|
||||
// AdvancedEnableInlining enables automatically inlining keys shorter than
|
||||
// 42 bytes into the peer ID (using the "identity" multihash function).
|
||||
//
|
||||
// WARNING: This flag will likely be set to false in the future and eventually
|
||||
// be removed in favor of using a hash function specified by the key itself.
|
||||
// See: https://github.com/libp2p/specs/issues/138
|
||||
//
|
||||
// DO NOT change this flag unless you know what you're doing.
|
||||
//
|
||||
// This currently defaults to true for backwards compatibility but will likely
|
||||
// be set to false by default when an upgrade path is determined.
|
||||
var AdvancedEnableInlining = true
|
||||
|
||||
const maxInlineKeyLength = 42
|
||||
|
||||
// ID is a libp2p peer identity.
|
||||
//
|
||||
// Peer IDs are derived by hashing a peer's public key and encoding the
|
||||
// hash output as a multihash. See IDFromPublicKey for details.
|
||||
type ID string
|
||||
|
||||
// Loggable returns a pretty peer ID string in loggable JSON format.
|
||||
func (id ID) Loggable() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"peerID": id.String(),
|
||||
}
|
||||
}
|
||||
|
||||
func (id ID) String() string {
|
||||
return b58.Encode([]byte(id))
|
||||
}
|
||||
|
||||
// ShortString prints out the peer ID.
|
||||
//
|
||||
// TODO(brian): ensure correctness at ID generation and
|
||||
// enforce this by only exposing functions that generate
|
||||
// IDs safely. Then any peer.ID type found in the
|
||||
// codebase is known to be correct.
|
||||
func (id ID) ShortString() string {
|
||||
pid := id.String()
|
||||
if len(pid) <= 10 {
|
||||
return fmt.Sprintf("<peer.ID %s>", pid)
|
||||
}
|
||||
return fmt.Sprintf("<peer.ID %s*%s>", pid[:2], pid[len(pid)-6:])
|
||||
}
|
||||
|
||||
// MatchesPrivateKey tests whether this ID was derived from the secret key sk.
|
||||
func (id ID) MatchesPrivateKey(sk ic.PrivKey) bool {
|
||||
return id.MatchesPublicKey(sk.GetPublic())
|
||||
}
|
||||
|
||||
// MatchesPublicKey tests whether this ID was derived from the public key pk.
|
||||
func (id ID) MatchesPublicKey(pk ic.PubKey) bool {
|
||||
oid, err := IDFromPublicKey(pk)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return oid == id
|
||||
}
|
||||
|
||||
// ExtractPublicKey attempts to extract the public key from an ID.
|
||||
//
|
||||
// This method returns ErrNoPublicKey if the peer ID looks valid, but it can't extract
|
||||
// the public key.
|
||||
func (id ID) ExtractPublicKey() (ic.PubKey, error) {
|
||||
decoded, err := mh.Decode([]byte(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if decoded.Code != mh.IDENTITY {
|
||||
return nil, ErrNoPublicKey
|
||||
}
|
||||
pk, err := ic.UnmarshalPublicKey(decoded.Digest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
// Validate checks if ID is empty or not.
|
||||
func (id ID) Validate() error {
|
||||
if id == ID("") {
|
||||
return ErrEmptyPeerID
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IDFromBytes casts a byte slice to the ID type, and validates
|
||||
// the value to make sure it is a multihash.
|
||||
func IDFromBytes(b []byte) (ID, error) {
|
||||
if _, err := mh.Cast(b); err != nil {
|
||||
return ID(""), err
|
||||
}
|
||||
return ID(b), nil
|
||||
}
|
||||
|
||||
// Decode accepts an encoded peer ID and returns the decoded ID if the input is
|
||||
// valid.
|
||||
//
|
||||
// The encoded peer ID can either be a CID of a key or a raw multihash (identity
|
||||
// or sha256-256).
|
||||
func Decode(s string) (ID, error) {
|
||||
if strings.HasPrefix(s, "Qm") || strings.HasPrefix(s, "1") {
|
||||
// base58 encoded sha256 or identity multihash
|
||||
m, err := mh.FromB58String(s)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse peer ID: %s", err)
|
||||
}
|
||||
return ID(m), nil
|
||||
}
|
||||
|
||||
c, err := cid.Decode(s)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to parse peer ID: %s", err)
|
||||
}
|
||||
return FromCid(c)
|
||||
}
|
||||
|
||||
// FromCid converts a CID to a peer ID, if possible.
|
||||
func FromCid(c cid.Cid) (ID, error) {
|
||||
code := mc.Code(c.Type())
|
||||
if code != mc.Libp2pKey {
|
||||
return "", fmt.Errorf("can't convert CID of type %q to a peer ID", code)
|
||||
}
|
||||
return ID(c.Hash()), nil
|
||||
}
|
||||
|
||||
// ToCid encodes a peer ID as a CID of the public key.
|
||||
//
|
||||
// If the peer ID is invalid (e.g., empty), this will return the empty CID.
|
||||
func ToCid(id ID) cid.Cid {
|
||||
m, err := mh.Cast([]byte(id))
|
||||
if err != nil {
|
||||
return cid.Cid{}
|
||||
}
|
||||
return cid.NewCidV1(cid.Libp2pKey, m)
|
||||
}
|
||||
|
||||
// IDFromPublicKey returns the Peer ID corresponding to the public key pk.
|
||||
func IDFromPublicKey(pk ic.PubKey) (ID, error) {
|
||||
b, err := ic.MarshalPublicKey(pk)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var alg uint64 = mh.SHA2_256
|
||||
if AdvancedEnableInlining && len(b) <= maxInlineKeyLength {
|
||||
alg = mh.IDENTITY
|
||||
}
|
||||
hash, _ := mh.Sum(b, alg, -1)
|
||||
return ID(hash), nil
|
||||
}
|
||||
|
||||
// IDFromPrivateKey returns the Peer ID corresponding to the secret key sk.
|
||||
func IDFromPrivateKey(sk ic.PrivKey) (ID, error) {
|
||||
return IDFromPublicKey(sk.GetPublic())
|
||||
}
|
||||
|
||||
// IDSlice for sorting peers.
|
||||
type IDSlice []ID
|
||||
|
||||
func (es IDSlice) Len() int { return len(es) }
|
||||
func (es IDSlice) Swap(i, j int) { es[i], es[j] = es[j], es[i] }
|
||||
func (es IDSlice) Less(i, j int) bool { return string(es[i]) < string(es[j]) }
|
||||
|
||||
func (es IDSlice) String() string {
|
||||
peersStrings := make([]string, len(es))
|
||||
for i, id := range es {
|
||||
peersStrings[i] = id.String()
|
||||
}
|
||||
return strings.Join(peersStrings, ", ")
|
||||
}
|
||||
73
vendor/github.com/libp2p/go-libp2p/core/peer/peer_serde.go
generated
vendored
Normal file
73
vendor/github.com/libp2p/go-libp2p/core/peer/peer_serde.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
// Package peer contains Protobuf and JSON serialization/deserialization methods for peer IDs.
|
||||
package peer
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Interface assertions commented out to avoid introducing hard dependencies to protobuf.
|
||||
// var _ proto.Marshaler = (*ID)(nil)
|
||||
// var _ proto.Unmarshaler = (*ID)(nil)
|
||||
var _ json.Marshaler = (*ID)(nil)
|
||||
var _ json.Unmarshaler = (*ID)(nil)
|
||||
|
||||
var _ encoding.BinaryMarshaler = (*ID)(nil)
|
||||
var _ encoding.BinaryUnmarshaler = (*ID)(nil)
|
||||
var _ encoding.TextMarshaler = (*ID)(nil)
|
||||
var _ encoding.TextUnmarshaler = (*ID)(nil)
|
||||
|
||||
func (id ID) Marshal() ([]byte, error) {
|
||||
return []byte(id), nil
|
||||
}
|
||||
|
||||
// MarshalBinary returns the byte representation of the peer ID.
|
||||
func (id ID) MarshalBinary() ([]byte, error) {
|
||||
return id.Marshal()
|
||||
}
|
||||
|
||||
func (id ID) MarshalTo(data []byte) (n int, err error) {
|
||||
return copy(data, []byte(id)), nil
|
||||
}
|
||||
|
||||
func (id *ID) Unmarshal(data []byte) (err error) {
|
||||
*id, err = IDFromBytes(data)
|
||||
return err
|
||||
}
|
||||
|
||||
// UnmarshalBinary sets the ID from its binary representation.
|
||||
func (id *ID) UnmarshalBinary(data []byte) error {
|
||||
return id.Unmarshal(data)
|
||||
}
|
||||
|
||||
func (id ID) Size() int {
|
||||
return len([]byte(id))
|
||||
}
|
||||
|
||||
func (id ID) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(id.String())
|
||||
}
|
||||
|
||||
func (id *ID) UnmarshalJSON(data []byte) (err error) {
|
||||
var v string
|
||||
if err = json.Unmarshal(data, &v); err != nil {
|
||||
return err
|
||||
}
|
||||
*id, err = Decode(v)
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalText returns the text encoding of the ID.
|
||||
func (id ID) MarshalText() ([]byte, error) {
|
||||
return []byte(id.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText restores the ID from its text encoding.
|
||||
func (id *ID) UnmarshalText(data []byte) error {
|
||||
pid, err := Decode(string(data))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*id = pid
|
||||
return nil
|
||||
}
|
||||
253
vendor/github.com/libp2p/go-libp2p/core/peer/record.go
generated
vendored
Normal file
253
vendor/github.com/libp2p/go-libp2p/core/peer/record.go
generated
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
package peer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/internal/catch"
|
||||
"github.com/libp2p/go-libp2p/core/peer/pb"
|
||||
"github.com/libp2p/go-libp2p/core/record"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
//go:generate protoc --proto_path=$PWD:$PWD/../.. --go_out=. --go_opt=Mpb/peer_record.proto=./pb pb/peer_record.proto
|
||||
|
||||
var _ record.Record = (*PeerRecord)(nil)
|
||||
|
||||
func init() {
|
||||
record.RegisterType(&PeerRecord{})
|
||||
}
|
||||
|
||||
// PeerRecordEnvelopeDomain is the domain string used for peer records contained in an Envelope.
|
||||
const PeerRecordEnvelopeDomain = "libp2p-peer-record"
|
||||
|
||||
// PeerRecordEnvelopePayloadType is the type hint used to identify peer records in an Envelope.
|
||||
// Defined in https://github.com/multiformats/multicodec/blob/master/table.csv
|
||||
// with name "libp2p-peer-record".
|
||||
var PeerRecordEnvelopePayloadType = []byte{0x03, 0x01}
|
||||
|
||||
// PeerRecord contains information that is broadly useful to share with other peers,
|
||||
// either through a direct exchange (as in the libp2p identify protocol), or through
|
||||
// a Peer Routing provider, such as a DHT.
|
||||
//
|
||||
// Currently, a PeerRecord contains the public listen addresses for a peer, but this
|
||||
// is expected to expand to include other information in the future.
|
||||
//
|
||||
// PeerRecords are ordered in time by their Seq field. Newer PeerRecords must have
|
||||
// greater Seq values than older records. The NewPeerRecord function will create
|
||||
// a PeerRecord with a timestamp-based Seq value. The other PeerRecord fields should
|
||||
// be set by the caller:
|
||||
//
|
||||
// rec := peer.NewPeerRecord()
|
||||
// rec.PeerID = aPeerID
|
||||
// rec.Addrs = someAddrs
|
||||
//
|
||||
// Alternatively, you can construct a PeerRecord struct directly and use the TimestampSeq
|
||||
// helper to set the Seq field:
|
||||
//
|
||||
// rec := peer.PeerRecord{PeerID: aPeerID, Addrs: someAddrs, Seq: peer.TimestampSeq()}
|
||||
//
|
||||
// Failing to set the Seq field will not result in an error, however, a PeerRecord with a
|
||||
// Seq value of zero may be ignored or rejected by other peers.
|
||||
//
|
||||
// PeerRecords are intended to be shared with other peers inside a signed
|
||||
// routing.Envelope, and PeerRecord implements the routing.Record interface
|
||||
// to facilitate this.
|
||||
//
|
||||
// To share a PeerRecord, first call Sign to wrap the record in an Envelope
|
||||
// and sign it with the local peer's private key:
|
||||
//
|
||||
// rec := &PeerRecord{PeerID: myPeerId, Addrs: myAddrs}
|
||||
// envelope, err := rec.Sign(myPrivateKey)
|
||||
//
|
||||
// The resulting record.Envelope can be marshalled to a []byte and shared
|
||||
// publicly. As a convenience, the MarshalSigned method will produce the
|
||||
// Envelope and marshal it to a []byte in one go:
|
||||
//
|
||||
// rec := &PeerRecord{PeerID: myPeerId, Addrs: myAddrs}
|
||||
// recordBytes, err := rec.MarshalSigned(myPrivateKey)
|
||||
//
|
||||
// To validate and unmarshal a signed PeerRecord from a remote peer,
|
||||
// "consume" the containing envelope, which will return both the
|
||||
// routing.Envelope and the inner Record. The Record must be cast to
|
||||
// a PeerRecord pointer before use:
|
||||
//
|
||||
// envelope, untypedRecord, err := ConsumeEnvelope(envelopeBytes, PeerRecordEnvelopeDomain)
|
||||
// if err != nil {
|
||||
// handleError(err)
|
||||
// return
|
||||
// }
|
||||
// peerRec := untypedRecord.(*PeerRecord)
|
||||
type PeerRecord struct {
|
||||
// PeerID is the ID of the peer this record pertains to.
|
||||
PeerID ID
|
||||
|
||||
// Addrs contains the public addresses of the peer this record pertains to.
|
||||
Addrs []ma.Multiaddr
|
||||
|
||||
// Seq is a monotonically-increasing sequence counter that's used to order
|
||||
// PeerRecords in time. The interval between Seq values is unspecified,
|
||||
// but newer PeerRecords MUST have a greater Seq value than older records
|
||||
// for the same peer.
|
||||
Seq uint64
|
||||
}
|
||||
|
||||
// NewPeerRecord returns a PeerRecord with a timestamp-based sequence number.
|
||||
// The returned record is otherwise empty and should be populated by the caller.
|
||||
func NewPeerRecord() *PeerRecord {
|
||||
return &PeerRecord{Seq: TimestampSeq()}
|
||||
}
|
||||
|
||||
// PeerRecordFromAddrInfo creates a PeerRecord from an AddrInfo struct.
|
||||
// The returned record will have a timestamp-based sequence number.
|
||||
func PeerRecordFromAddrInfo(info AddrInfo) *PeerRecord {
|
||||
rec := NewPeerRecord()
|
||||
rec.PeerID = info.ID
|
||||
rec.Addrs = info.Addrs
|
||||
return rec
|
||||
}
|
||||
|
||||
// PeerRecordFromProtobuf creates a PeerRecord from a protobuf PeerRecord
|
||||
// struct.
|
||||
func PeerRecordFromProtobuf(msg *pb.PeerRecord) (*PeerRecord, error) {
|
||||
record := &PeerRecord{}
|
||||
|
||||
var id ID
|
||||
if err := id.UnmarshalBinary(msg.PeerId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
record.PeerID = id
|
||||
record.Addrs = addrsFromProtobuf(msg.Addresses)
|
||||
record.Seq = msg.Seq
|
||||
|
||||
return record, nil
|
||||
}
|
||||
|
||||
var (
|
||||
lastTimestampMu sync.Mutex
|
||||
lastTimestamp uint64
|
||||
)
|
||||
|
||||
// TimestampSeq is a helper to generate a timestamp-based sequence number for a PeerRecord.
|
||||
func TimestampSeq() uint64 {
|
||||
now := uint64(time.Now().UnixNano())
|
||||
lastTimestampMu.Lock()
|
||||
defer lastTimestampMu.Unlock()
|
||||
// Not all clocks are strictly increasing, but we need these sequence numbers to be strictly
|
||||
// increasing.
|
||||
if now <= lastTimestamp {
|
||||
now = lastTimestamp + 1
|
||||
}
|
||||
lastTimestamp = now
|
||||
return now
|
||||
}
|
||||
|
||||
// Domain is used when signing and validating PeerRecords contained in Envelopes.
|
||||
// It is constant for all PeerRecord instances.
|
||||
func (r *PeerRecord) Domain() string {
|
||||
return PeerRecordEnvelopeDomain
|
||||
}
|
||||
|
||||
// Codec is a binary identifier for the PeerRecord type. It is constant for all PeerRecord instances.
|
||||
func (r *PeerRecord) Codec() []byte {
|
||||
return PeerRecordEnvelopePayloadType
|
||||
}
|
||||
|
||||
// UnmarshalRecord parses a PeerRecord from a byte slice.
|
||||
// This method is called automatically when consuming a record.Envelope
|
||||
// whose PayloadType indicates that it contains a PeerRecord.
|
||||
// It is generally not necessary or recommended to call this method directly.
|
||||
func (r *PeerRecord) UnmarshalRecord(bytes []byte) (err error) {
|
||||
if r == nil {
|
||||
return fmt.Errorf("cannot unmarshal PeerRecord to nil receiver")
|
||||
}
|
||||
|
||||
defer func() { catch.HandlePanic(recover(), &err, "libp2p peer record unmarshal") }()
|
||||
|
||||
var msg pb.PeerRecord
|
||||
err = proto.Unmarshal(bytes, &msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rPtr, err := PeerRecordFromProtobuf(&msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*r = *rPtr
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalRecord serializes a PeerRecord to a byte slice.
|
||||
// This method is called automatically when constructing a routing.Envelope
|
||||
// using Seal or PeerRecord.Sign.
|
||||
func (r *PeerRecord) MarshalRecord() (res []byte, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "libp2p peer record marshal") }()
|
||||
|
||||
msg, err := r.ToProtobuf()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.Marshal(msg)
|
||||
}
|
||||
|
||||
// Equal returns true if the other PeerRecord is identical to this one.
|
||||
func (r *PeerRecord) Equal(other *PeerRecord) bool {
|
||||
if other == nil {
|
||||
return r == nil
|
||||
}
|
||||
if r.PeerID != other.PeerID {
|
||||
return false
|
||||
}
|
||||
if r.Seq != other.Seq {
|
||||
return false
|
||||
}
|
||||
if len(r.Addrs) != len(other.Addrs) {
|
||||
return false
|
||||
}
|
||||
for i := range r.Addrs {
|
||||
if !r.Addrs[i].Equal(other.Addrs[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ToProtobuf returns the equivalent Protocol Buffer struct object of a PeerRecord.
|
||||
func (r *PeerRecord) ToProtobuf() (*pb.PeerRecord, error) {
|
||||
idBytes, err := r.PeerID.MarshalBinary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.PeerRecord{
|
||||
PeerId: idBytes,
|
||||
Addresses: addrsToProtobuf(r.Addrs),
|
||||
Seq: r.Seq,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func addrsFromProtobuf(addrs []*pb.PeerRecord_AddressInfo) []ma.Multiaddr {
|
||||
out := make([]ma.Multiaddr, 0, len(addrs))
|
||||
for _, addr := range addrs {
|
||||
a, err := ma.NewMultiaddrBytes(addr.Multiaddr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
out = append(out, a)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func addrsToProtobuf(addrs []ma.Multiaddr) []*pb.PeerRecord_AddressInfo {
|
||||
out := make([]*pb.PeerRecord_AddressInfo, 0, len(addrs))
|
||||
for _, addr := range addrs {
|
||||
out = append(out, &pb.PeerRecord_AddressInfo{Multiaddr: addr.Bytes()})
|
||||
}
|
||||
return out
|
||||
}
|
||||
14
vendor/github.com/libp2p/go-libp2p/core/peerstore/helpers.go
generated
vendored
Normal file
14
vendor/github.com/libp2p/go-libp2p/core/peerstore/helpers.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
package peerstore
|
||||
|
||||
import (
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
|
||||
// AddrInfos returns an AddrInfo for each specified peer ID, in-order.
|
||||
func AddrInfos(ps Peerstore, peers []peer.ID) []peer.AddrInfo {
|
||||
pi := make([]peer.AddrInfo, len(peers))
|
||||
for i, p := range peers {
|
||||
pi[i] = ps.PeerInfo(p)
|
||||
}
|
||||
return pi
|
||||
}
|
||||
250
vendor/github.com/libp2p/go-libp2p/core/peerstore/peerstore.go
generated
vendored
Normal file
250
vendor/github.com/libp2p/go-libp2p/core/peerstore/peerstore.go
generated
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
// Package peerstore provides types and interfaces for local storage of address information,
|
||||
// metadata, and public key material about libp2p peers.
|
||||
package peerstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
ic "github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
"github.com/libp2p/go-libp2p/core/record"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
var ErrNotFound = errors.New("item not found")
|
||||
|
||||
var (
|
||||
// AddressTTL is the expiration time of addresses.
|
||||
AddressTTL = time.Hour
|
||||
|
||||
// TempAddrTTL is the ttl used for a short-lived address.
|
||||
TempAddrTTL = time.Minute * 2
|
||||
|
||||
// RecentlyConnectedAddrTTL is used when we recently connected to a peer.
|
||||
// It means that we are reasonably certain of the peer's address.
|
||||
RecentlyConnectedAddrTTL = time.Minute * 30
|
||||
|
||||
// OwnObservedAddrTTL is used for our own external addresses observed by peers.
|
||||
OwnObservedAddrTTL = time.Minute * 30
|
||||
)
|
||||
|
||||
// Permanent TTLs (distinct so we can distinguish between them, constant as they
|
||||
// are, in fact, permanent)
|
||||
const (
|
||||
// PermanentAddrTTL is the ttl for a "permanent address" (e.g. bootstrap nodes).
|
||||
PermanentAddrTTL = math.MaxInt64 - iota
|
||||
|
||||
// ConnectedAddrTTL is the ttl used for the addresses of a peer to whom
|
||||
// we're connected directly. This is basically permanent, as we will
|
||||
// clear them + re-add under a TempAddrTTL after disconnecting.
|
||||
ConnectedAddrTTL
|
||||
)
|
||||
|
||||
// Peerstore provides a thread-safe store of Peer related
|
||||
// information.
|
||||
type Peerstore interface {
|
||||
io.Closer
|
||||
|
||||
AddrBook
|
||||
KeyBook
|
||||
PeerMetadata
|
||||
Metrics
|
||||
ProtoBook
|
||||
|
||||
// PeerInfo returns a peer.PeerInfo struct for given peer.ID.
|
||||
// This is a small slice of the information Peerstore has on
|
||||
// that peer, useful to other services.
|
||||
PeerInfo(peer.ID) peer.AddrInfo
|
||||
|
||||
// Peers returns all the peer IDs stored across all inner stores.
|
||||
Peers() peer.IDSlice
|
||||
}
|
||||
|
||||
// PeerMetadata can handle values of any type. Serializing values is
|
||||
// up to the implementation. Dynamic type introspection may not be
|
||||
// supported, in which case explicitly enlisting types in the
|
||||
// serializer may be required.
|
||||
//
|
||||
// Refer to the docs of the underlying implementation for more
|
||||
// information.
|
||||
type PeerMetadata interface {
|
||||
// Get / Put is a simple registry for other peer-related key/value pairs.
|
||||
// If we find something we use often, it should become its own set of
|
||||
// methods. This is a last resort.
|
||||
Get(p peer.ID, key string) (interface{}, error)
|
||||
Put(p peer.ID, key string, val interface{}) error
|
||||
|
||||
// RemovePeer removes all values stored for a peer.
|
||||
RemovePeer(peer.ID)
|
||||
}
|
||||
|
||||
// AddrBook holds the multiaddrs of peers.
|
||||
type AddrBook interface {
|
||||
// AddAddr calls AddAddrs(p, []ma.Multiaddr{addr}, ttl)
|
||||
AddAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration)
|
||||
|
||||
// AddAddrs gives this AddrBook addresses to use, with a given ttl
|
||||
// (time-to-live), after which the address is no longer valid.
|
||||
// If the manager has a longer TTL, the operation is a no-op for that address
|
||||
AddAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration)
|
||||
|
||||
// SetAddr calls mgr.SetAddrs(p, addr, ttl)
|
||||
SetAddr(p peer.ID, addr ma.Multiaddr, ttl time.Duration)
|
||||
|
||||
// SetAddrs sets the ttl on addresses. This clears any TTL there previously.
|
||||
// This is used when we receive the best estimate of the validity of an address.
|
||||
SetAddrs(p peer.ID, addrs []ma.Multiaddr, ttl time.Duration)
|
||||
|
||||
// UpdateAddrs updates the addresses associated with the given peer that have
|
||||
// the given oldTTL to have the given newTTL.
|
||||
UpdateAddrs(p peer.ID, oldTTL time.Duration, newTTL time.Duration)
|
||||
|
||||
// Addrs returns all known (and valid) addresses for a given peer.
|
||||
Addrs(p peer.ID) []ma.Multiaddr
|
||||
|
||||
// AddrStream returns a channel that gets all addresses for a given
|
||||
// peer sent on it. If new addresses are added after the call is made
|
||||
// they will be sent along through the channel as well.
|
||||
AddrStream(context.Context, peer.ID) <-chan ma.Multiaddr
|
||||
|
||||
// ClearAddresses removes all previously stored addresses.
|
||||
ClearAddrs(p peer.ID)
|
||||
|
||||
// PeersWithAddrs returns all the peer IDs stored in the AddrBook.
|
||||
PeersWithAddrs() peer.IDSlice
|
||||
}
|
||||
|
||||
// CertifiedAddrBook manages "self-certified" addresses for remote peers.
|
||||
// Self-certified addresses are contained in peer.PeerRecords
|
||||
// which are wrapped in a record.Envelope and signed by the peer
|
||||
// to whom they belong.
|
||||
//
|
||||
// Certified addresses (CA) are generally more secure than uncertified
|
||||
// addresses (UA). Consequently, CAs beat and displace UAs. When the
|
||||
// peerstore learns CAs for a peer, it will reject UAs for the same peer
|
||||
// (as long as the former haven't expired).
|
||||
// Furthermore, peer records act like sequenced snapshots of CAs. Therefore,
|
||||
// processing a peer record that's newer than the last one seen overwrites
|
||||
// all addresses with the incoming ones.
|
||||
//
|
||||
// This interface is most useful when combined with AddrBook.
|
||||
// To test whether a given AddrBook / Peerstore implementation supports
|
||||
// certified addresses, callers should use the GetCertifiedAddrBook helper or
|
||||
// type-assert on the CertifiedAddrBook interface:
|
||||
//
|
||||
// if cab, ok := aPeerstore.(CertifiedAddrBook); ok {
|
||||
// cab.ConsumePeerRecord(signedPeerRecord, aTTL)
|
||||
// }
|
||||
type CertifiedAddrBook interface {
|
||||
// ConsumePeerRecord adds addresses from a signed peer.PeerRecord (contained in
|
||||
// a record.Envelope), which will expire after the given TTL.
|
||||
//
|
||||
// The 'accepted' return value indicates that the record was successfully processed
|
||||
// and integrated into the CertifiedAddrBook state. If 'accepted' is false but no
|
||||
// error is returned, it means that the record was ignored, most likely because
|
||||
// a newer record exists for the same peer.
|
||||
//
|
||||
// Signed records added via this method will be stored without
|
||||
// alteration as long as the address TTLs remain valid. The Envelopes
|
||||
// containing the PeerRecords can be retrieved by calling GetPeerRecord(peerID).
|
||||
//
|
||||
// If the signed PeerRecord belongs to a peer that already has certified
|
||||
// addresses in the CertifiedAddrBook, the new addresses will replace the
|
||||
// older ones, if the new record has a higher sequence number than the
|
||||
// existing record. Attempting to add a peer record with a
|
||||
// sequence number that's <= an existing record for the same peer will not
|
||||
// result in an error, but the record will be ignored, and the 'accepted'
|
||||
// bool return value will be false.
|
||||
//
|
||||
// If the CertifiedAddrBook is also an AddrBook (which is most likely the case),
|
||||
// adding certified addresses for a peer will *replace* any
|
||||
// existing non-certified addresses for that peer, and only the certified
|
||||
// addresses will be returned from AddrBook.Addrs thereafter.
|
||||
//
|
||||
// Likewise, once certified addresses have been added for a given peer,
|
||||
// any non-certified addresses added via AddrBook.AddAddrs or
|
||||
// AddrBook.SetAddrs will be ignored. AddrBook.SetAddrs may still be used
|
||||
// to update the TTL of certified addresses that have previously been
|
||||
// added via ConsumePeerRecord.
|
||||
ConsumePeerRecord(s *record.Envelope, ttl time.Duration) (accepted bool, err error)
|
||||
|
||||
// GetPeerRecord returns an Envelope containing a PeerRecord for the
|
||||
// given peer id, if one exists.
|
||||
// Returns nil if no signed PeerRecord exists for the peer.
|
||||
GetPeerRecord(p peer.ID) *record.Envelope
|
||||
}
|
||||
|
||||
// GetCertifiedAddrBook is a helper to "upcast" an AddrBook to a
|
||||
// CertifiedAddrBook by using type assertion. If the given AddrBook
|
||||
// is also a CertifiedAddrBook, it will be returned, and the ok return
|
||||
// value will be true. Returns (nil, false) if the AddrBook is not a
|
||||
// CertifiedAddrBook.
|
||||
//
|
||||
// Note that since Peerstore embeds the AddrBook interface, you can also
|
||||
// call GetCertifiedAddrBook(myPeerstore).
|
||||
func GetCertifiedAddrBook(ab AddrBook) (cab CertifiedAddrBook, ok bool) {
|
||||
cab, ok = ab.(CertifiedAddrBook)
|
||||
return cab, ok
|
||||
}
|
||||
|
||||
// KeyBook tracks the keys of Peers.
|
||||
type KeyBook interface {
|
||||
// PubKey stores the public key of a peer.
|
||||
PubKey(peer.ID) ic.PubKey
|
||||
|
||||
// AddPubKey stores the public key of a peer.
|
||||
AddPubKey(peer.ID, ic.PubKey) error
|
||||
|
||||
// PrivKey returns the private key of a peer, if known. Generally this might only be our own
|
||||
// private key, see
|
||||
// https://discuss.libp2p.io/t/what-is-the-purpose-of-having-map-peer-id-privatekey-in-peerstore/74.
|
||||
PrivKey(peer.ID) ic.PrivKey
|
||||
|
||||
// AddPrivKey stores the private key of a peer.
|
||||
AddPrivKey(peer.ID, ic.PrivKey) error
|
||||
|
||||
// PeersWithKeys returns all the peer IDs stored in the KeyBook.
|
||||
PeersWithKeys() peer.IDSlice
|
||||
|
||||
// RemovePeer removes all keys associated with a peer.
|
||||
RemovePeer(peer.ID)
|
||||
}
|
||||
|
||||
// Metrics tracks metrics across a set of peers.
|
||||
type Metrics interface {
|
||||
// RecordLatency records a new latency measurement
|
||||
RecordLatency(peer.ID, time.Duration)
|
||||
|
||||
// LatencyEWMA returns an exponentially-weighted moving avg.
|
||||
// of all measurements of a peer's latency.
|
||||
LatencyEWMA(peer.ID) time.Duration
|
||||
|
||||
// RemovePeer removes all metrics stored for a peer.
|
||||
RemovePeer(peer.ID)
|
||||
}
|
||||
|
||||
// ProtoBook tracks the protocols supported by peers.
|
||||
type ProtoBook interface {
|
||||
GetProtocols(peer.ID) ([]protocol.ID, error)
|
||||
AddProtocols(peer.ID, ...protocol.ID) error
|
||||
SetProtocols(peer.ID, ...protocol.ID) error
|
||||
RemoveProtocols(peer.ID, ...protocol.ID) error
|
||||
|
||||
// SupportsProtocols returns the set of protocols the peer supports from among the given protocols.
|
||||
// If the returned error is not nil, the result is indeterminate.
|
||||
SupportsProtocols(peer.ID, ...protocol.ID) ([]protocol.ID, error)
|
||||
|
||||
// FirstSupportedProtocol returns the first protocol that the peer supports among the given protocols.
|
||||
// If the peer does not support any of the given protocols, this function will return an empty protocol.ID and a nil error.
|
||||
// If the returned error is not nil, the result is indeterminate.
|
||||
FirstSupportedProtocol(peer.ID, ...protocol.ID) (protocol.ID, error)
|
||||
|
||||
// RemovePeer removes all protocols associated with a peer.
|
||||
RemovePeer(peer.ID)
|
||||
}
|
||||
66
vendor/github.com/libp2p/go-libp2p/core/pnet/codec.go
generated
vendored
Normal file
66
vendor/github.com/libp2p/go-libp2p/core/pnet/codec.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package pnet
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
var (
|
||||
pathPSKv1 = []byte("/key/swarm/psk/1.0.0/")
|
||||
pathBin = "/bin/"
|
||||
pathBase16 = "/base16/"
|
||||
pathBase64 = "/base64/"
|
||||
)
|
||||
|
||||
func readHeader(r *bufio.Reader) ([]byte, error) {
|
||||
header, err := r.ReadBytes('\n')
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bytes.TrimRight(header, "\r\n"), nil
|
||||
}
|
||||
|
||||
func expectHeader(r *bufio.Reader, expected []byte) error {
|
||||
header, err := readHeader(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !bytes.Equal(header, expected) {
|
||||
return fmt.Errorf("expected file header %s, got: %s", expected, header)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeV1PSK reads a Multicodec encoded V1 PSK.
|
||||
func DecodeV1PSK(in io.Reader) (PSK, error) {
|
||||
reader := bufio.NewReader(in)
|
||||
if err := expectHeader(reader, pathPSKv1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
header, err := readHeader(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var decoder io.Reader
|
||||
switch string(header) {
|
||||
case pathBase16:
|
||||
decoder = hex.NewDecoder(reader)
|
||||
case pathBase64:
|
||||
decoder = base64.NewDecoder(base64.StdEncoding, reader)
|
||||
case pathBin:
|
||||
decoder = reader
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown encoding: %s", header)
|
||||
}
|
||||
out := make([]byte, 32)
|
||||
if _, err = io.ReadFull(decoder, out[:]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
19
vendor/github.com/libp2p/go-libp2p/core/pnet/env.go
generated
vendored
Normal file
19
vendor/github.com/libp2p/go-libp2p/core/pnet/env.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package pnet
|
||||
|
||||
import "os"
|
||||
|
||||
// EnvKey defines environment variable name for forcing usage of PNet in libp2p
|
||||
// When environment variable of this name is set to "1" the ForcePrivateNetwork
|
||||
// variable will be set to true.
|
||||
const EnvKey = "LIBP2P_FORCE_PNET"
|
||||
|
||||
// ForcePrivateNetwork is boolean variable that forces usage of PNet in libp2p
|
||||
// Setting this variable to true or setting LIBP2P_FORCE_PNET environment variable
|
||||
// to true will make libp2p to require private network protector.
|
||||
// If no network protector is provided and this variable is set to true libp2p will
|
||||
// refuse to connect.
|
||||
var ForcePrivateNetwork = false
|
||||
|
||||
func init() {
|
||||
ForcePrivateNetwork = os.Getenv(EnvKey) == "1"
|
||||
}
|
||||
34
vendor/github.com/libp2p/go-libp2p/core/pnet/error.go
generated
vendored
Normal file
34
vendor/github.com/libp2p/go-libp2p/core/pnet/error.go
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package pnet
|
||||
|
||||
// ErrNotInPrivateNetwork is an error that should be returned by libp2p when it
|
||||
// tries to dial with ForcePrivateNetwork set and no PNet Protector
|
||||
var ErrNotInPrivateNetwork = NewError("private network was not configured but" +
|
||||
" is enforced by the environment")
|
||||
|
||||
// Error is error type for ease of detecting PNet errors
|
||||
type Error interface {
|
||||
IsPNetError() bool
|
||||
}
|
||||
|
||||
// NewError creates new Error
|
||||
func NewError(err string) error {
|
||||
return pnetErr("privnet: " + err)
|
||||
}
|
||||
|
||||
// IsPNetError checks if given error is PNet Error
|
||||
func IsPNetError(err error) bool {
|
||||
v, ok := err.(Error)
|
||||
return ok && v.IsPNetError()
|
||||
}
|
||||
|
||||
type pnetErr string
|
||||
|
||||
var _ Error = (*pnetErr)(nil)
|
||||
|
||||
func (p pnetErr) Error() string {
|
||||
return string(p)
|
||||
}
|
||||
|
||||
func (pnetErr) IsPNetError() bool {
|
||||
return true
|
||||
}
|
||||
7
vendor/github.com/libp2p/go-libp2p/core/pnet/protector.go
generated
vendored
Normal file
7
vendor/github.com/libp2p/go-libp2p/core/pnet/protector.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// Package pnet provides interfaces for private networking in libp2p.
|
||||
package pnet
|
||||
|
||||
// A PSK enables private network implementation to be transparent in libp2p.
|
||||
// It is used to ensure that peers can only establish connections to other peers
|
||||
// that are using the same PSK.
|
||||
type PSK []byte
|
||||
29
vendor/github.com/libp2p/go-libp2p/core/protocol/id.go
generated
vendored
Normal file
29
vendor/github.com/libp2p/go-libp2p/core/protocol/id.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package protocol
|
||||
|
||||
// ID is an identifier used to write protocol headers in streams.
|
||||
type ID string
|
||||
|
||||
// These are reserved protocol.IDs.
|
||||
const (
|
||||
TestingID ID = "/p2p/_testing"
|
||||
)
|
||||
|
||||
// ConvertFromStrings is a convenience function that takes a slice of strings and
|
||||
// converts it to a slice of protocol.ID.
|
||||
func ConvertFromStrings(ids []string) (res []ID) {
|
||||
res = make([]ID, 0, len(ids))
|
||||
for _, id := range ids {
|
||||
res = append(res, ID(id))
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// ConvertToStrings is a convenience function that takes a slice of protocol.ID and
|
||||
// converts it to a slice of strings.
|
||||
func ConvertToStrings(ids []ID) (res []string) {
|
||||
res = make([]string, 0, len(ids))
|
||||
for _, id := range ids {
|
||||
res = append(res, string(id))
|
||||
}
|
||||
return res
|
||||
}
|
||||
73
vendor/github.com/libp2p/go-libp2p/core/protocol/switch.go
generated
vendored
Normal file
73
vendor/github.com/libp2p/go-libp2p/core/protocol/switch.go
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
// Package protocol provides core interfaces for protocol routing and negotiation in libp2p.
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/multiformats/go-multistream"
|
||||
)
|
||||
|
||||
// HandlerFunc is a user-provided function used by the Router to
|
||||
// handle a protocol/stream.
|
||||
//
|
||||
// Will be invoked with the protocol ID string as the first argument,
|
||||
// which may differ from the ID used for registration if the handler
|
||||
// was registered using a match function.
|
||||
type HandlerFunc = multistream.HandlerFunc[ID]
|
||||
|
||||
// Router is an interface that allows users to add and remove protocol handlers,
|
||||
// which will be invoked when incoming stream requests for registered protocols
|
||||
// are accepted.
|
||||
//
|
||||
// Upon receiving an incoming stream request, the Router will check all registered
|
||||
// protocol handlers to determine which (if any) is capable of handling the stream.
|
||||
// The handlers are checked in order of registration; if multiple handlers are
|
||||
// eligible, only the first to be registered will be invoked.
|
||||
type Router interface {
|
||||
|
||||
// AddHandler registers the given handler to be invoked for
|
||||
// an exact literal match of the given protocol ID string.
|
||||
AddHandler(protocol ID, handler HandlerFunc)
|
||||
|
||||
// AddHandlerWithFunc registers the given handler to be invoked
|
||||
// when the provided match function returns true.
|
||||
//
|
||||
// The match function will be invoked with an incoming protocol
|
||||
// ID string, and should return true if the handler supports
|
||||
// the protocol. Note that the protocol ID argument is not
|
||||
// used for matching; if you want to match the protocol ID
|
||||
// string exactly, you must check for it in your match function.
|
||||
AddHandlerWithFunc(protocol ID, match func(ID) bool, handler HandlerFunc)
|
||||
|
||||
// RemoveHandler removes the registered handler (if any) for the
|
||||
// given protocol ID string.
|
||||
RemoveHandler(protocol ID)
|
||||
|
||||
// Protocols returns a list of all registered protocol ID strings.
|
||||
// Note that the Router may be able to handle protocol IDs not
|
||||
// included in this list if handlers were added with match functions
|
||||
// using AddHandlerWithFunc.
|
||||
Protocols() []ID
|
||||
}
|
||||
|
||||
// Negotiator is a component capable of reaching agreement over what protocols
|
||||
// to use for inbound streams of communication.
|
||||
type Negotiator interface {
|
||||
// Negotiate will return the registered protocol handler to use for a given
|
||||
// inbound stream, returning after the protocol has been determined and the
|
||||
// Negotiator has finished using the stream for negotiation. Returns an
|
||||
// error if negotiation fails.
|
||||
Negotiate(rwc io.ReadWriteCloser) (ID, HandlerFunc, error)
|
||||
|
||||
// Handle calls Negotiate to determine which protocol handler to use for an
|
||||
// inbound stream, then invokes the protocol handler function, passing it
|
||||
// the protocol ID and the stream. Returns an error if negotiation fails.
|
||||
Handle(rwc io.ReadWriteCloser) error
|
||||
}
|
||||
|
||||
// Switch is the component responsible for "dispatching" incoming stream requests to
|
||||
// their corresponding stream handlers. It is both a Negotiator and a Router.
|
||||
type Switch interface {
|
||||
Router
|
||||
Negotiator
|
||||
}
|
||||
296
vendor/github.com/libp2p/go-libp2p/core/record/envelope.go
generated
vendored
Normal file
296
vendor/github.com/libp2p/go-libp2p/core/record/envelope.go
generated
vendored
Normal file
@@ -0,0 +1,296 @@
|
||||
package record
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/internal/catch"
|
||||
"github.com/libp2p/go-libp2p/core/record/pb"
|
||||
|
||||
pool "github.com/libp2p/go-buffer-pool"
|
||||
|
||||
"github.com/multiformats/go-varint"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
//go:generate protoc --proto_path=$PWD:$PWD/../.. --go_out=. --go_opt=Mpb/envelope.proto=./pb pb/envelope.proto
|
||||
|
||||
// Envelope contains an arbitrary []byte payload, signed by a libp2p peer.
|
||||
//
|
||||
// Envelopes are signed in the context of a particular "domain", which is a
|
||||
// string specified when creating and verifying the envelope. You must know the
|
||||
// domain string used to produce the envelope in order to verify the signature
|
||||
// and access the payload.
|
||||
type Envelope struct {
|
||||
// The public key that can be used to verify the signature and derive the peer id of the signer.
|
||||
PublicKey crypto.PubKey
|
||||
|
||||
// A binary identifier that indicates what kind of data is contained in the payload.
|
||||
// TODO(yusef): enforce multicodec prefix
|
||||
PayloadType []byte
|
||||
|
||||
// The envelope payload.
|
||||
RawPayload []byte
|
||||
|
||||
// The signature of the domain string :: type hint :: payload.
|
||||
signature []byte
|
||||
|
||||
// the unmarshalled payload as a Record, cached on first access via the Record accessor method
|
||||
cached Record
|
||||
unmarshalError error
|
||||
unmarshalOnce sync.Once
|
||||
}
|
||||
|
||||
var ErrEmptyDomain = errors.New("envelope domain must not be empty")
|
||||
var ErrEmptyPayloadType = errors.New("payloadType must not be empty")
|
||||
var ErrInvalidSignature = errors.New("invalid signature or incorrect domain")
|
||||
|
||||
// Seal marshals the given Record, places the marshaled bytes inside an Envelope,
|
||||
// and signs with the given private key.
|
||||
func Seal(rec Record, privateKey crypto.PrivKey) (*Envelope, error) {
|
||||
payload, err := rec.MarshalRecord()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error marshaling record: %v", err)
|
||||
}
|
||||
|
||||
domain := rec.Domain()
|
||||
payloadType := rec.Codec()
|
||||
if domain == "" {
|
||||
return nil, ErrEmptyDomain
|
||||
}
|
||||
|
||||
if len(payloadType) == 0 {
|
||||
return nil, ErrEmptyPayloadType
|
||||
}
|
||||
|
||||
unsigned, err := makeUnsigned(domain, payloadType, payload)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer pool.Put(unsigned)
|
||||
|
||||
sig, err := privateKey.Sign(unsigned)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Envelope{
|
||||
PublicKey: privateKey.GetPublic(),
|
||||
PayloadType: payloadType,
|
||||
RawPayload: payload,
|
||||
signature: sig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ConsumeEnvelope unmarshals a serialized Envelope and validates its
|
||||
// signature using the provided 'domain' string. If validation fails, an error
|
||||
// is returned, along with the unmarshalled envelope, so it can be inspected.
|
||||
//
|
||||
// On success, ConsumeEnvelope returns the Envelope itself, as well as the inner payload,
|
||||
// unmarshalled into a concrete Record type. The actual type of the returned Record depends
|
||||
// on what has been registered for the Envelope's PayloadType (see RegisterType for details).
|
||||
//
|
||||
// You can type assert on the returned Record to convert it to an instance of the concrete
|
||||
// Record type:
|
||||
//
|
||||
// envelope, rec, err := ConsumeEnvelope(envelopeBytes, peer.PeerRecordEnvelopeDomain)
|
||||
// if err != nil {
|
||||
// handleError(envelope, err) // envelope may be non-nil, even if errors occur!
|
||||
// return
|
||||
// }
|
||||
// peerRec, ok := rec.(*peer.PeerRecord)
|
||||
// if ok {
|
||||
// doSomethingWithPeerRecord(peerRec)
|
||||
// }
|
||||
//
|
||||
// If the Envelope signature is valid, but no Record type is registered for the Envelope's
|
||||
// PayloadType, ErrPayloadTypeNotRegistered will be returned, along with the Envelope and
|
||||
// a nil Record.
|
||||
func ConsumeEnvelope(data []byte, domain string) (envelope *Envelope, rec Record, err error) {
|
||||
e, err := UnmarshalEnvelope(data)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed when unmarshalling the envelope: %w", err)
|
||||
}
|
||||
|
||||
err = e.validate(domain)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to validate envelope: %w", err)
|
||||
}
|
||||
|
||||
rec, err = e.Record()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to unmarshal envelope payload: %w", err)
|
||||
}
|
||||
return e, rec, nil
|
||||
}
|
||||
|
||||
// ConsumeTypedEnvelope unmarshals a serialized Envelope and validates its
|
||||
// signature. If validation fails, an error is returned, along with the unmarshalled
|
||||
// envelope, so it can be inspected.
|
||||
//
|
||||
// Unlike ConsumeEnvelope, ConsumeTypedEnvelope does not try to automatically determine
|
||||
// the type of Record to unmarshal the Envelope's payload into. Instead, the caller provides
|
||||
// a destination Record instance, which will unmarshal the Envelope payload. It is the caller's
|
||||
// responsibility to determine whether the given Record type is able to unmarshal the payload
|
||||
// correctly.
|
||||
//
|
||||
// rec := &MyRecordType{}
|
||||
// envelope, err := ConsumeTypedEnvelope(envelopeBytes, rec)
|
||||
// if err != nil {
|
||||
// handleError(envelope, err)
|
||||
// }
|
||||
// doSomethingWithRecord(rec)
|
||||
//
|
||||
// Important: you MUST check the error value before using the returned Envelope. In some error
|
||||
// cases, including when the envelope signature is invalid, both the Envelope and an error will
|
||||
// be returned. This allows you to inspect the unmarshalled but invalid Envelope. As a result,
|
||||
// you must not assume that any non-nil Envelope returned from this function is valid.
|
||||
func ConsumeTypedEnvelope(data []byte, destRecord Record) (envelope *Envelope, err error) {
|
||||
e, err := UnmarshalEnvelope(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed when unmarshalling the envelope: %w", err)
|
||||
}
|
||||
|
||||
err = e.validate(destRecord.Domain())
|
||||
if err != nil {
|
||||
return e, fmt.Errorf("failed to validate envelope: %w", err)
|
||||
}
|
||||
|
||||
err = destRecord.UnmarshalRecord(e.RawPayload)
|
||||
if err != nil {
|
||||
return e, fmt.Errorf("failed to unmarshal envelope payload: %w", err)
|
||||
}
|
||||
e.cached = destRecord
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// UnmarshalEnvelope unmarshals a serialized Envelope protobuf message,
|
||||
// without validating its contents. Most users should use ConsumeEnvelope.
|
||||
func UnmarshalEnvelope(data []byte) (*Envelope, error) {
|
||||
var e pb.Envelope
|
||||
if err := proto.Unmarshal(data, &e); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := crypto.PublicKeyFromProto(e.PublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Envelope{
|
||||
PublicKey: key,
|
||||
PayloadType: e.PayloadType,
|
||||
RawPayload: e.Payload,
|
||||
signature: e.Signature,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Marshal returns a byte slice containing a serialized protobuf representation
|
||||
// of an Envelope.
|
||||
func (e *Envelope) Marshal() (res []byte, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "libp2p envelope marshal") }()
|
||||
key, err := crypto.PublicKeyToProto(e.PublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msg := pb.Envelope{
|
||||
PublicKey: key,
|
||||
PayloadType: e.PayloadType,
|
||||
Payload: e.RawPayload,
|
||||
Signature: e.signature,
|
||||
}
|
||||
return proto.Marshal(&msg)
|
||||
}
|
||||
|
||||
// Equal returns true if the other Envelope has the same public key,
|
||||
// payload, payload type, and signature. This implies that they were also
|
||||
// created with the same domain string.
|
||||
func (e *Envelope) Equal(other *Envelope) bool {
|
||||
if other == nil {
|
||||
return e == nil
|
||||
}
|
||||
return e.PublicKey.Equals(other.PublicKey) &&
|
||||
bytes.Equal(e.PayloadType, other.PayloadType) &&
|
||||
bytes.Equal(e.signature, other.signature) &&
|
||||
bytes.Equal(e.RawPayload, other.RawPayload)
|
||||
}
|
||||
|
||||
// Record returns the Envelope's payload unmarshalled as a Record.
|
||||
// The concrete type of the returned Record depends on which Record
|
||||
// type was registered for the Envelope's PayloadType - see record.RegisterType.
|
||||
//
|
||||
// Once unmarshalled, the Record is cached for future access.
|
||||
func (e *Envelope) Record() (Record, error) {
|
||||
e.unmarshalOnce.Do(func() {
|
||||
if e.cached != nil {
|
||||
return
|
||||
}
|
||||
e.cached, e.unmarshalError = unmarshalRecordPayload(e.PayloadType, e.RawPayload)
|
||||
})
|
||||
return e.cached, e.unmarshalError
|
||||
}
|
||||
|
||||
// TypedRecord unmarshals the Envelope's payload to the given Record instance.
|
||||
// It is the caller's responsibility to ensure that the Record type is capable
|
||||
// of unmarshalling the Envelope payload. Callers can inspect the Envelope's
|
||||
// PayloadType field to determine the correct type of Record to use.
|
||||
//
|
||||
// This method will always unmarshal the Envelope payload even if a cached record
|
||||
// exists.
|
||||
func (e *Envelope) TypedRecord(dest Record) error {
|
||||
return dest.UnmarshalRecord(e.RawPayload)
|
||||
}
|
||||
|
||||
// validate returns nil if the envelope signature is valid for the given 'domain',
|
||||
// or an error if signature validation fails.
|
||||
func (e *Envelope) validate(domain string) error {
|
||||
unsigned, err := makeUnsigned(domain, e.PayloadType, e.RawPayload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer pool.Put(unsigned)
|
||||
|
||||
valid, err := e.PublicKey.Verify(unsigned, e.signature)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed while verifying signature: %w", err)
|
||||
}
|
||||
if !valid {
|
||||
return ErrInvalidSignature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// makeUnsigned is a helper function that prepares a buffer to sign or verify.
|
||||
// It returns a byte slice from a pool. The caller MUST return this slice to the
|
||||
// pool.
|
||||
func makeUnsigned(domain string, payloadType []byte, payload []byte) ([]byte, error) {
|
||||
var (
|
||||
fields = [][]byte{[]byte(domain), payloadType, payload}
|
||||
|
||||
// fields are prefixed with their length as an unsigned varint. we
|
||||
// compute the lengths before allocating the sig buffer, so we know how
|
||||
// much space to add for the lengths
|
||||
flen = make([][]byte, len(fields))
|
||||
size = 0
|
||||
)
|
||||
|
||||
for i, f := range fields {
|
||||
l := len(f)
|
||||
flen[i] = varint.ToUvarint(uint64(l))
|
||||
size += l + len(flen[i])
|
||||
}
|
||||
|
||||
b := pool.Get(size)
|
||||
|
||||
var s int
|
||||
for i, f := range fields {
|
||||
s += copy(b[s:], flen[i])
|
||||
s += copy(b[s:], f)
|
||||
}
|
||||
|
||||
return b[:s], nil
|
||||
}
|
||||
192
vendor/github.com/libp2p/go-libp2p/core/record/pb/envelope.pb.go
generated
vendored
Normal file
192
vendor/github.com/libp2p/go-libp2p/core/record/pb/envelope.pb.go
generated
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v3.21.12
|
||||
// source: pb/envelope.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
pb "github.com/libp2p/go-libp2p/core/crypto/pb"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// Envelope encloses a signed payload produced by a peer, along with the public
|
||||
// key of the keypair it was signed with so that it can be statelessly validated
|
||||
// by the receiver.
|
||||
//
|
||||
// The payload is prefixed with a byte string that determines the type, so it
|
||||
// can be deserialized deterministically. Often, this byte string is a
|
||||
// multicodec.
|
||||
type Envelope struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// public_key is the public key of the keypair the enclosed payload was
|
||||
// signed with.
|
||||
PublicKey *pb.PublicKey `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
|
||||
// payload_type encodes the type of payload, so that it can be deserialized
|
||||
// deterministically.
|
||||
PayloadType []byte `protobuf:"bytes,2,opt,name=payload_type,json=payloadType,proto3" json:"payload_type,omitempty"`
|
||||
// payload is the actual payload carried inside this envelope.
|
||||
Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||
// signature is the signature produced by the private key corresponding to
|
||||
// the enclosed public key, over the payload, prefixing a domain string for
|
||||
// additional security.
|
||||
Signature []byte `protobuf:"bytes,5,opt,name=signature,proto3" json:"signature,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Envelope) Reset() {
|
||||
*x = Envelope{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_pb_envelope_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Envelope) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Envelope) ProtoMessage() {}
|
||||
|
||||
func (x *Envelope) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_pb_envelope_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Envelope.ProtoReflect.Descriptor instead.
|
||||
func (*Envelope) Descriptor() ([]byte, []int) {
|
||||
return file_pb_envelope_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Envelope) GetPublicKey() *pb.PublicKey {
|
||||
if x != nil {
|
||||
return x.PublicKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Envelope) GetPayloadType() []byte {
|
||||
if x != nil {
|
||||
return x.PayloadType
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Envelope) GetPayload() []byte {
|
||||
if x != nil {
|
||||
return x.Payload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Envelope) GetSignature() []byte {
|
||||
if x != nil {
|
||||
return x.Signature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_pb_envelope_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_pb_envelope_proto_rawDesc = []byte{
|
||||
0x0a, 0x11, 0x70, 0x62, 0x2f, 0x65, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x12, 0x09, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x2e, 0x70, 0x62, 0x1a, 0x1b,
|
||||
0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x2f, 0x63,
|
||||
0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x9a, 0x01, 0x0a, 0x08,
|
||||
0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x33, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c,
|
||||
0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63,
|
||||
0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
|
||||
0x65, 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x21, 0x0a,
|
||||
0x0c, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x52, 0x0b, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x54, 0x79, 0x70, 0x65,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69,
|
||||
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73,
|
||||
0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_pb_envelope_proto_rawDescOnce sync.Once
|
||||
file_pb_envelope_proto_rawDescData = file_pb_envelope_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_pb_envelope_proto_rawDescGZIP() []byte {
|
||||
file_pb_envelope_proto_rawDescOnce.Do(func() {
|
||||
file_pb_envelope_proto_rawDescData = protoimpl.X.CompressGZIP(file_pb_envelope_proto_rawDescData)
|
||||
})
|
||||
return file_pb_envelope_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_pb_envelope_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_pb_envelope_proto_goTypes = []interface{}{
|
||||
(*Envelope)(nil), // 0: record.pb.Envelope
|
||||
(*pb.PublicKey)(nil), // 1: crypto.pb.PublicKey
|
||||
}
|
||||
var file_pb_envelope_proto_depIdxs = []int32{
|
||||
1, // 0: record.pb.Envelope.public_key:type_name -> crypto.pb.PublicKey
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_pb_envelope_proto_init() }
|
||||
func file_pb_envelope_proto_init() {
|
||||
if File_pb_envelope_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_pb_envelope_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Envelope); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_pb_envelope_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_pb_envelope_proto_goTypes,
|
||||
DependencyIndexes: file_pb_envelope_proto_depIdxs,
|
||||
MessageInfos: file_pb_envelope_proto_msgTypes,
|
||||
}.Build()
|
||||
File_pb_envelope_proto = out.File
|
||||
file_pb_envelope_proto_rawDesc = nil
|
||||
file_pb_envelope_proto_goTypes = nil
|
||||
file_pb_envelope_proto_depIdxs = nil
|
||||
}
|
||||
30
vendor/github.com/libp2p/go-libp2p/core/record/pb/envelope.proto
generated
vendored
Normal file
30
vendor/github.com/libp2p/go-libp2p/core/record/pb/envelope.proto
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package record.pb;
|
||||
|
||||
import "core/crypto/pb/crypto.proto";
|
||||
|
||||
// Envelope encloses a signed payload produced by a peer, along with the public
|
||||
// key of the keypair it was signed with so that it can be statelessly validated
|
||||
// by the receiver.
|
||||
//
|
||||
// The payload is prefixed with a byte string that determines the type, so it
|
||||
// can be deserialized deterministically. Often, this byte string is a
|
||||
// multicodec.
|
||||
message Envelope {
|
||||
// public_key is the public key of the keypair the enclosed payload was
|
||||
// signed with.
|
||||
crypto.pb.PublicKey public_key = 1;
|
||||
|
||||
// payload_type encodes the type of payload, so that it can be deserialized
|
||||
// deterministically.
|
||||
bytes payload_type = 2;
|
||||
|
||||
// payload is the actual payload carried inside this envelope.
|
||||
bytes payload = 3;
|
||||
|
||||
// signature is the signature produced by the private key corresponding to
|
||||
// the enclosed public key, over the payload, prefixing a domain string for
|
||||
// additional security.
|
||||
bytes signature = 5;
|
||||
}
|
||||
105
vendor/github.com/libp2p/go-libp2p/core/record/record.go
generated
vendored
Normal file
105
vendor/github.com/libp2p/go-libp2p/core/record/record.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
package record
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"reflect"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/internal/catch"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrPayloadTypeNotRegistered is returned from ConsumeEnvelope when the Envelope's
|
||||
// PayloadType does not match any registered Record types.
|
||||
ErrPayloadTypeNotRegistered = errors.New("payload type is not registered")
|
||||
|
||||
payloadTypeRegistry = make(map[string]reflect.Type)
|
||||
)
|
||||
|
||||
// Record represents a data type that can be used as the payload of an Envelope.
|
||||
// The Record interface defines the methods used to marshal and unmarshal a Record
|
||||
// type to a byte slice.
|
||||
//
|
||||
// Record types may be "registered" as the default for a given Envelope.PayloadType
|
||||
// using the RegisterType function. Once a Record type has been registered,
|
||||
// an instance of that type will be created and used to unmarshal the payload of
|
||||
// any Envelope with the registered PayloadType when the Envelope is opened using
|
||||
// the ConsumeEnvelope function.
|
||||
//
|
||||
// To use an unregistered Record type instead, use ConsumeTypedEnvelope and pass in
|
||||
// an instance of the Record type that you'd like the Envelope's payload to be
|
||||
// unmarshaled into.
|
||||
type Record interface {
|
||||
|
||||
// Domain is the "signature domain" used when signing and verifying a particular
|
||||
// Record type. The Domain string should be unique to your Record type, and all
|
||||
// instances of the Record type must have the same Domain string.
|
||||
Domain() string
|
||||
|
||||
// Codec is a binary identifier for this type of record, ideally a registered multicodec
|
||||
// (see https://github.com/multiformats/multicodec).
|
||||
// When a Record is put into an Envelope (see record.Seal), the Codec value will be used
|
||||
// as the Envelope's PayloadType. When the Envelope is later unsealed, the PayloadType
|
||||
// will be used to look up the correct Record type to unmarshal the Envelope payload into.
|
||||
Codec() []byte
|
||||
|
||||
// MarshalRecord converts a Record instance to a []byte, so that it can be used as an
|
||||
// Envelope payload.
|
||||
MarshalRecord() ([]byte, error)
|
||||
|
||||
// UnmarshalRecord unmarshals a []byte payload into an instance of a particular Record type.
|
||||
UnmarshalRecord([]byte) error
|
||||
}
|
||||
|
||||
// RegisterType associates a binary payload type identifier with a concrete
|
||||
// Record type. This is used to automatically unmarshal Record payloads from Envelopes
|
||||
// when using ConsumeEnvelope, and to automatically marshal Records and determine the
|
||||
// correct PayloadType when calling Seal.
|
||||
//
|
||||
// Callers must provide an instance of the record type to be registered, which must be
|
||||
// a pointer type. Registration should be done in the init function of the package
|
||||
// where the Record type is defined:
|
||||
//
|
||||
// package hello_record
|
||||
// import record "github.com/libp2p/go-libp2p/core/record"
|
||||
//
|
||||
// func init() {
|
||||
// record.RegisterType(&HelloRecord{})
|
||||
// }
|
||||
//
|
||||
// type HelloRecord struct { } // etc..
|
||||
func RegisterType(prototype Record) {
|
||||
payloadTypeRegistry[string(prototype.Codec())] = getValueType(prototype)
|
||||
}
|
||||
|
||||
func unmarshalRecordPayload(payloadType []byte, payloadBytes []byte) (_rec Record, err error) {
|
||||
defer func() { catch.HandlePanic(recover(), &err, "libp2p envelope record unmarshal") }()
|
||||
|
||||
rec, err := blankRecordForPayloadType(payloadType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = rec.UnmarshalRecord(payloadBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rec, nil
|
||||
}
|
||||
|
||||
func blankRecordForPayloadType(payloadType []byte) (Record, error) {
|
||||
valueType, ok := payloadTypeRegistry[string(payloadType)]
|
||||
if !ok {
|
||||
return nil, ErrPayloadTypeNotRegistered
|
||||
}
|
||||
|
||||
val := reflect.New(valueType)
|
||||
asRecord := val.Interface().(Record)
|
||||
return asRecord, nil
|
||||
}
|
||||
|
||||
func getValueType(i interface{}) reflect.Type {
|
||||
valueType := reflect.TypeOf(i)
|
||||
if valueType.Kind() == reflect.Ptr {
|
||||
valueType = valueType.Elem()
|
||||
}
|
||||
return valueType
|
||||
}
|
||||
50
vendor/github.com/libp2p/go-libp2p/core/routing/options.go
generated
vendored
Normal file
50
vendor/github.com/libp2p/go-libp2p/core/routing/options.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
package routing
|
||||
|
||||
// Option is a single routing option.
|
||||
type Option func(opts *Options) error
|
||||
|
||||
// Options is a set of routing options
|
||||
type Options struct {
|
||||
// Allow expired values.
|
||||
Expired bool
|
||||
Offline bool
|
||||
// Other (ValueStore implementation specific) options.
|
||||
Other map[interface{}]interface{}
|
||||
}
|
||||
|
||||
// Apply applies the given options to this Options
|
||||
func (opts *Options) Apply(options ...Option) error {
|
||||
for _, o := range options {
|
||||
if err := o(opts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToOption converts this Options to a single Option.
|
||||
func (opts *Options) ToOption() Option {
|
||||
return func(nopts *Options) error {
|
||||
*nopts = *opts
|
||||
if opts.Other != nil {
|
||||
nopts.Other = make(map[interface{}]interface{}, len(opts.Other))
|
||||
for k, v := range opts.Other {
|
||||
nopts.Other[k] = v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Expired is an option that tells the routing system to return expired records
|
||||
// when no newer records are known.
|
||||
var Expired Option = func(opts *Options) error {
|
||||
opts.Expired = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Offline is an option that tells the routing system to operate offline (i.e., rely on cached/local data only).
|
||||
var Offline Option = func(opts *Options) error {
|
||||
opts.Offline = true
|
||||
return nil
|
||||
}
|
||||
111
vendor/github.com/libp2p/go-libp2p/core/routing/query.go
generated
vendored
Normal file
111
vendor/github.com/libp2p/go-libp2p/core/routing/query.go
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
package routing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
|
||||
// QueryEventType indicates the query event's type.
|
||||
type QueryEventType int
|
||||
|
||||
// Number of events to buffer.
|
||||
var QueryEventBufferSize = 16
|
||||
|
||||
const (
|
||||
// Sending a query to a peer.
|
||||
SendingQuery QueryEventType = iota
|
||||
// Got a response from a peer.
|
||||
PeerResponse
|
||||
// Found a "closest" peer (not currently used).
|
||||
FinalPeer
|
||||
// Got an error when querying.
|
||||
QueryError
|
||||
// Found a provider.
|
||||
Provider
|
||||
// Found a value.
|
||||
Value
|
||||
// Adding a peer to the query.
|
||||
AddingPeer
|
||||
// Dialing a peer.
|
||||
DialingPeer
|
||||
)
|
||||
|
||||
// QueryEvent is emitted for every notable event that happens during a DHT query.
|
||||
type QueryEvent struct {
|
||||
ID peer.ID
|
||||
Type QueryEventType
|
||||
Responses []*peer.AddrInfo
|
||||
Extra string
|
||||
}
|
||||
|
||||
type routingQueryKey struct{}
|
||||
type eventChannel struct {
|
||||
mu sync.Mutex
|
||||
ctx context.Context
|
||||
ch chan<- *QueryEvent
|
||||
}
|
||||
|
||||
// waitThenClose is spawned in a goroutine when the channel is registered. This
|
||||
// safely cleans up the channel when the context has been canceled.
|
||||
func (e *eventChannel) waitThenClose() {
|
||||
<-e.ctx.Done()
|
||||
e.mu.Lock()
|
||||
close(e.ch)
|
||||
// 1. Signals that we're done.
|
||||
// 2. Frees memory (in case we end up hanging on to this for a while).
|
||||
e.ch = nil
|
||||
e.mu.Unlock()
|
||||
}
|
||||
|
||||
// send sends an event on the event channel, aborting if either the passed or
|
||||
// the internal context expire.
|
||||
func (e *eventChannel) send(ctx context.Context, ev *QueryEvent) {
|
||||
e.mu.Lock()
|
||||
// Closed.
|
||||
if e.ch == nil {
|
||||
e.mu.Unlock()
|
||||
return
|
||||
}
|
||||
// in case the passed context is unrelated, wait on both.
|
||||
select {
|
||||
case e.ch <- ev:
|
||||
case <-e.ctx.Done():
|
||||
case <-ctx.Done():
|
||||
}
|
||||
e.mu.Unlock()
|
||||
}
|
||||
|
||||
// RegisterForQueryEvents registers a query event channel with the given
|
||||
// context. The returned context can be passed to DHT queries to receive query
|
||||
// events on the returned channels.
|
||||
//
|
||||
// The passed context MUST be canceled when the caller is no longer interested
|
||||
// in query events.
|
||||
func RegisterForQueryEvents(ctx context.Context) (context.Context, <-chan *QueryEvent) {
|
||||
ch := make(chan *QueryEvent, QueryEventBufferSize)
|
||||
ech := &eventChannel{ch: ch, ctx: ctx}
|
||||
go ech.waitThenClose()
|
||||
return context.WithValue(ctx, routingQueryKey{}, ech), ch
|
||||
}
|
||||
|
||||
// PublishQueryEvent publishes a query event to the query event channel
|
||||
// associated with the given context, if any.
|
||||
func PublishQueryEvent(ctx context.Context, ev *QueryEvent) {
|
||||
ich := ctx.Value(routingQueryKey{})
|
||||
if ich == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// We *want* to panic here.
|
||||
ech := ich.(*eventChannel)
|
||||
ech.send(ctx, ev)
|
||||
}
|
||||
|
||||
// SubscribesToQueryEvents returns true if the context subscribes to query
|
||||
// events. If this function returns false, calling `PublishQueryEvent` on the
|
||||
// context will be a no-op.
|
||||
func SubscribesToQueryEvents(ctx context.Context) bool {
|
||||
return ctx.Value(routingQueryKey{}) != nil
|
||||
}
|
||||
40
vendor/github.com/libp2p/go-libp2p/core/routing/query_serde.go
generated
vendored
Normal file
40
vendor/github.com/libp2p/go-libp2p/core/routing/query_serde.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package routing
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
|
||||
func (qe *QueryEvent) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(map[string]interface{}{
|
||||
"ID": qe.ID.String(),
|
||||
"Type": int(qe.Type),
|
||||
"Responses": qe.Responses,
|
||||
"Extra": qe.Extra,
|
||||
})
|
||||
}
|
||||
|
||||
func (qe *QueryEvent) UnmarshalJSON(b []byte) error {
|
||||
temp := struct {
|
||||
ID string
|
||||
Type int
|
||||
Responses []*peer.AddrInfo
|
||||
Extra string
|
||||
}{}
|
||||
err := json.Unmarshal(b, &temp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(temp.ID) > 0 {
|
||||
pid, err := peer.Decode(temp.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
qe.ID = pid
|
||||
}
|
||||
qe.Type = QueryEventType(temp.Type)
|
||||
qe.Responses = temp.Responses
|
||||
qe.Extra = temp.Extra
|
||||
return nil
|
||||
}
|
||||
127
vendor/github.com/libp2p/go-libp2p/core/routing/routing.go
generated
vendored
Normal file
127
vendor/github.com/libp2p/go-libp2p/core/routing/routing.go
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
// Package routing provides interfaces for peer routing and content routing in libp2p.
|
||||
package routing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
ci "github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
// ErrNotFound is returned when the router fails to find the requested record.
|
||||
var ErrNotFound = errors.New("routing: not found")
|
||||
|
||||
// ErrNotSupported is returned when the router doesn't support the given record
|
||||
// type/operation.
|
||||
var ErrNotSupported = errors.New("routing: operation or key not supported")
|
||||
|
||||
// ContentRouting is a value provider layer of indirection. It is used to find
|
||||
// information about who has what content.
|
||||
//
|
||||
// Content is identified by CID (content identifier), which encodes a hash
|
||||
// of the identified content in a future-proof manner.
|
||||
type ContentRouting interface {
|
||||
// Provide adds the given cid to the content routing system. If 'true' is
|
||||
// passed, it also announces it, otherwise it is just kept in the local
|
||||
// accounting of which objects are being provided.
|
||||
Provide(context.Context, cid.Cid, bool) error
|
||||
|
||||
// Search for peers who are able to provide a given key
|
||||
//
|
||||
// When count is 0, this method will return an unbounded number of
|
||||
// results.
|
||||
FindProvidersAsync(context.Context, cid.Cid, int) <-chan peer.AddrInfo
|
||||
}
|
||||
|
||||
// PeerRouting is a way to find address information about certain peers.
|
||||
// This can be implemented by a simple lookup table, a tracking server,
|
||||
// or even a DHT.
|
||||
type PeerRouting interface {
|
||||
// FindPeer searches for a peer with given ID, returns a peer.AddrInfo
|
||||
// with relevant addresses.
|
||||
FindPeer(context.Context, peer.ID) (peer.AddrInfo, error)
|
||||
}
|
||||
|
||||
// ValueStore is a basic Put/Get interface.
|
||||
type ValueStore interface {
|
||||
|
||||
// PutValue adds value corresponding to given Key.
|
||||
PutValue(context.Context, string, []byte, ...Option) error
|
||||
|
||||
// GetValue searches for the value corresponding to given Key.
|
||||
GetValue(context.Context, string, ...Option) ([]byte, error)
|
||||
|
||||
// SearchValue searches for better and better values from this value
|
||||
// store corresponding to the given Key. By default, implementations must
|
||||
// stop the search after a good value is found. A 'good' value is a value
|
||||
// that would be returned from GetValue.
|
||||
//
|
||||
// Useful when you want a result *now* but still want to hear about
|
||||
// better/newer results.
|
||||
//
|
||||
// Implementations of this methods won't return ErrNotFound. When a value
|
||||
// couldn't be found, the channel will get closed without passing any results
|
||||
SearchValue(context.Context, string, ...Option) (<-chan []byte, error)
|
||||
}
|
||||
|
||||
// Routing is the combination of different routing types supported by libp2p.
|
||||
// It can be satisfied by a single item (such as a DHT) or multiple different
|
||||
// pieces that are more optimized to each task.
|
||||
type Routing interface {
|
||||
ContentRouting
|
||||
PeerRouting
|
||||
ValueStore
|
||||
|
||||
// Bootstrap allows callers to hint to the routing system to get into a
|
||||
// Boostrapped state and remain there. It is not a synchronous call.
|
||||
Bootstrap(context.Context) error
|
||||
|
||||
// TODO expose io.Closer or plain-old Close error
|
||||
}
|
||||
|
||||
// PubKeyFetcher is an interfaces that should be implemented by value stores
|
||||
// that can optimize retrieval of public keys.
|
||||
//
|
||||
// TODO(steb): Consider removing, see https://github.com/libp2p/go-libp2p-routing/issues/22.
|
||||
type PubKeyFetcher interface {
|
||||
// GetPublicKey returns the public key for the given peer.
|
||||
GetPublicKey(context.Context, peer.ID) (ci.PubKey, error)
|
||||
}
|
||||
|
||||
// KeyForPublicKey returns the key used to retrieve public keys
|
||||
// from a value store.
|
||||
func KeyForPublicKey(id peer.ID) string {
|
||||
return "/pk/" + string(id)
|
||||
}
|
||||
|
||||
// GetPublicKey retrieves the public key associated with the given peer ID from
|
||||
// the value store.
|
||||
//
|
||||
// If the ValueStore is also a PubKeyFetcher, this method will call GetPublicKey
|
||||
// (which may be better optimized) instead of GetValue.
|
||||
func GetPublicKey(r ValueStore, ctx context.Context, p peer.ID) (ci.PubKey, error) {
|
||||
switch k, err := p.ExtractPublicKey(); err {
|
||||
case peer.ErrNoPublicKey:
|
||||
// check the datastore
|
||||
case nil:
|
||||
return k, nil
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if dht, ok := r.(PubKeyFetcher); ok {
|
||||
// If we have a DHT as our routing system, use optimized fetcher
|
||||
return dht.GetPublicKey(ctx, p)
|
||||
}
|
||||
key := KeyForPublicKey(p)
|
||||
pkval, err := r.GetValue(ctx, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// get PublicKey from node.Data
|
||||
return ci.UnmarshalPublicKey(pkval)
|
||||
}
|
||||
233
vendor/github.com/libp2p/go-libp2p/core/sec/insecure/insecure.go
generated
vendored
Normal file
233
vendor/github.com/libp2p/go-libp2p/core/sec/insecure/insecure.go
generated
vendored
Normal file
@@ -0,0 +1,233 @@
|
||||
// Package insecure provides an insecure, unencrypted implementation of the SecureConn and SecureTransport interfaces.
|
||||
//
|
||||
// Recommended only for testing and other non-production usage.
|
||||
package insecure
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
ci "github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
"github.com/libp2p/go-libp2p/core/sec"
|
||||
"github.com/libp2p/go-libp2p/core/sec/insecure/pb"
|
||||
|
||||
"github.com/libp2p/go-msgio"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
//go:generate protoc --proto_path=$PWD:$PWD/../../.. --go_out=. --go_opt=Mpb/plaintext.proto=./pb pb/plaintext.proto
|
||||
|
||||
// ID is the multistream-select protocol ID that should be used when identifying
|
||||
// this security transport.
|
||||
const ID = "/plaintext/2.0.0"
|
||||
|
||||
// Transport is a no-op stream security transport. It provides no
|
||||
// security and simply mocks the security methods. Identity methods
|
||||
// return the local peer's ID and private key, and whatever the remote
|
||||
// peer presents as their ID and public key.
|
||||
// No authentication of the remote identity is performed.
|
||||
type Transport struct {
|
||||
id peer.ID
|
||||
key ci.PrivKey
|
||||
protocolID protocol.ID
|
||||
}
|
||||
|
||||
var _ sec.SecureTransport = &Transport{}
|
||||
|
||||
// NewWithIdentity constructs a new insecure transport. The public key is sent to
|
||||
// remote peers. No security is provided.
|
||||
func NewWithIdentity(protocolID protocol.ID, id peer.ID, key ci.PrivKey) *Transport {
|
||||
return &Transport{
|
||||
protocolID: protocolID,
|
||||
id: id,
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
|
||||
// LocalPeer returns the transport's local peer ID.
|
||||
func (t *Transport) LocalPeer() peer.ID {
|
||||
return t.id
|
||||
}
|
||||
|
||||
// SecureInbound *pretends to secure* an inbound connection to the given peer.
|
||||
// It sends the local peer's ID and public key, and receives the same from the remote peer.
|
||||
// No validation is performed as to the authenticity or ownership of the provided public key,
|
||||
// and the key exchange provides no security.
|
||||
//
|
||||
// SecureInbound may fail if the remote peer sends an ID and public key that are inconsistent
|
||||
// with each other, or if a network error occurs during the ID exchange.
|
||||
func (t *Transport) SecureInbound(_ context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
|
||||
conn := &Conn{
|
||||
Conn: insecure,
|
||||
local: t.id,
|
||||
localPubKey: t.key.GetPublic(),
|
||||
}
|
||||
|
||||
if err := conn.runHandshakeSync(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if p != "" && p != conn.remote {
|
||||
return nil, fmt.Errorf("remote peer sent unexpected peer ID. expected=%s received=%s", p, conn.remote)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// SecureOutbound *pretends to secure* an outbound connection to the given peer.
|
||||
// It sends the local peer's ID and public key, and receives the same from the remote peer.
|
||||
// No validation is performed as to the authenticity or ownership of the provided public key,
|
||||
// and the key exchange provides no security.
|
||||
//
|
||||
// SecureOutbound may fail if the remote peer sends an ID and public key that are inconsistent
|
||||
// with each other, or if the ID sent by the remote peer does not match the one dialed. It may
|
||||
// also fail if a network error occurs during the ID exchange.
|
||||
func (t *Transport) SecureOutbound(_ context.Context, insecure net.Conn, p peer.ID) (sec.SecureConn, error) {
|
||||
conn := &Conn{
|
||||
Conn: insecure,
|
||||
local: t.id,
|
||||
localPubKey: t.key.GetPublic(),
|
||||
}
|
||||
|
||||
if err := conn.runHandshakeSync(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if p != conn.remote {
|
||||
return nil, fmt.Errorf("remote peer sent unexpected peer ID. expected=%s received=%s",
|
||||
p, conn.remote)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (t *Transport) ID() protocol.ID { return t.protocolID }
|
||||
|
||||
// Conn is the connection type returned by the insecure transport.
|
||||
type Conn struct {
|
||||
net.Conn
|
||||
|
||||
local, remote peer.ID
|
||||
localPubKey, remotePubKey ci.PubKey
|
||||
}
|
||||
|
||||
func makeExchangeMessage(pubkey ci.PubKey) (*pb.Exchange, error) {
|
||||
keyMsg, err := ci.PublicKeyToProto(pubkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, err := peer.IDFromPublicKey(pubkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &pb.Exchange{
|
||||
Id: []byte(id),
|
||||
Pubkey: keyMsg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ic *Conn) runHandshakeSync() error {
|
||||
// If we were initialized without keys, behave as in plaintext/1.0.0 (do nothing)
|
||||
if ic.localPubKey == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generate an Exchange message
|
||||
msg, err := makeExchangeMessage(ic.localPubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Send our Exchange and read theirs
|
||||
remoteMsg, err := readWriteMsg(ic.Conn, msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Pull remote ID and public key from message
|
||||
remotePubkey, err := ci.PublicKeyFromProto(remoteMsg.Pubkey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
remoteID, err := peer.IDFromBytes(remoteMsg.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate that ID matches public key
|
||||
if !remoteID.MatchesPublicKey(remotePubkey) {
|
||||
calculatedID, _ := peer.IDFromPublicKey(remotePubkey)
|
||||
return fmt.Errorf("remote peer id does not match public key. id=%s calculated_id=%s",
|
||||
remoteID, calculatedID)
|
||||
}
|
||||
|
||||
// Add remote ID and key to conn state
|
||||
ic.remotePubKey = remotePubkey
|
||||
ic.remote = remoteID
|
||||
return nil
|
||||
}
|
||||
|
||||
// read and write a message at the same time.
|
||||
func readWriteMsg(rw io.ReadWriter, out *pb.Exchange) (*pb.Exchange, error) {
|
||||
const maxMessageSize = 1 << 16
|
||||
|
||||
outBytes, err := proto.Marshal(out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wresult := make(chan error)
|
||||
go func() {
|
||||
w := msgio.NewVarintWriter(rw)
|
||||
wresult <- w.WriteMsg(outBytes)
|
||||
}()
|
||||
|
||||
r := msgio.NewVarintReaderSize(rw, maxMessageSize)
|
||||
b, err1 := r.ReadMsg()
|
||||
|
||||
// Always wait for the read to finish.
|
||||
err2 := <-wresult
|
||||
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
if err2 != nil {
|
||||
r.ReleaseMsg(b)
|
||||
return nil, err2
|
||||
}
|
||||
inMsg := new(pb.Exchange)
|
||||
err = proto.Unmarshal(b, inMsg)
|
||||
return inMsg, err
|
||||
}
|
||||
|
||||
// LocalPeer returns the local peer ID.
|
||||
func (ic *Conn) LocalPeer() peer.ID {
|
||||
return ic.local
|
||||
}
|
||||
|
||||
// RemotePeer returns the remote peer ID if we initiated the dial. Otherwise, it
|
||||
// returns "" (because this connection isn't actually secure).
|
||||
func (ic *Conn) RemotePeer() peer.ID {
|
||||
return ic.remote
|
||||
}
|
||||
|
||||
// RemotePublicKey returns whatever public key was given by the remote peer.
|
||||
// Note that no verification of ownership is done, as this connection is not secure.
|
||||
func (ic *Conn) RemotePublicKey() ci.PubKey {
|
||||
return ic.remotePubKey
|
||||
}
|
||||
|
||||
// ConnState returns the security connection's state information.
|
||||
func (ic *Conn) ConnState() network.ConnectionState {
|
||||
return network.ConnectionState{}
|
||||
}
|
||||
|
||||
var _ sec.SecureTransport = (*Transport)(nil)
|
||||
var _ sec.SecureConn = (*Conn)(nil)
|
||||
156
vendor/github.com/libp2p/go-libp2p/core/sec/insecure/pb/plaintext.pb.go
generated
vendored
Normal file
156
vendor/github.com/libp2p/go-libp2p/core/sec/insecure/pb/plaintext.pb.go
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v3.21.12
|
||||
// source: pb/plaintext.proto
|
||||
|
||||
package pb
|
||||
|
||||
import (
|
||||
pb "github.com/libp2p/go-libp2p/core/crypto/pb"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Exchange struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id []byte `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
|
||||
Pubkey *pb.PublicKey `protobuf:"bytes,2,opt,name=pubkey" json:"pubkey,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Exchange) Reset() {
|
||||
*x = Exchange{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_pb_plaintext_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Exchange) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Exchange) ProtoMessage() {}
|
||||
|
||||
func (x *Exchange) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_pb_plaintext_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Exchange.ProtoReflect.Descriptor instead.
|
||||
func (*Exchange) Descriptor() ([]byte, []int) {
|
||||
return file_pb_plaintext_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Exchange) GetId() []byte {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Exchange) GetPubkey() *pb.PublicKey {
|
||||
if x != nil {
|
||||
return x.Pubkey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_pb_plaintext_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_pb_plaintext_proto_rawDesc = []byte{
|
||||
0x0a, 0x12, 0x70, 0x62, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e,
|
||||
0x70, 0x62, 0x1a, 0x1b, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2f,
|
||||
0x70, 0x62, 0x2f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22,
|
||||
0x48, 0x0a, 0x08, 0x45, 0x78, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x02, 0x69, 0x64, 0x12, 0x2c, 0x0a, 0x06, 0x70,
|
||||
0x75, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x72,
|
||||
0x79, 0x70, 0x74, 0x6f, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65,
|
||||
0x79, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79,
|
||||
}
|
||||
|
||||
var (
|
||||
file_pb_plaintext_proto_rawDescOnce sync.Once
|
||||
file_pb_plaintext_proto_rawDescData = file_pb_plaintext_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_pb_plaintext_proto_rawDescGZIP() []byte {
|
||||
file_pb_plaintext_proto_rawDescOnce.Do(func() {
|
||||
file_pb_plaintext_proto_rawDescData = protoimpl.X.CompressGZIP(file_pb_plaintext_proto_rawDescData)
|
||||
})
|
||||
return file_pb_plaintext_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_pb_plaintext_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_pb_plaintext_proto_goTypes = []interface{}{
|
||||
(*Exchange)(nil), // 0: plaintext.pb.Exchange
|
||||
(*pb.PublicKey)(nil), // 1: crypto.pb.PublicKey
|
||||
}
|
||||
var file_pb_plaintext_proto_depIdxs = []int32{
|
||||
1, // 0: plaintext.pb.Exchange.pubkey:type_name -> crypto.pb.PublicKey
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_pb_plaintext_proto_init() }
|
||||
func file_pb_plaintext_proto_init() {
|
||||
if File_pb_plaintext_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_pb_plaintext_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Exchange); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_pb_plaintext_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_pb_plaintext_proto_goTypes,
|
||||
DependencyIndexes: file_pb_plaintext_proto_depIdxs,
|
||||
MessageInfos: file_pb_plaintext_proto_msgTypes,
|
||||
}.Build()
|
||||
File_pb_plaintext_proto = out.File
|
||||
file_pb_plaintext_proto_rawDesc = nil
|
||||
file_pb_plaintext_proto_goTypes = nil
|
||||
file_pb_plaintext_proto_depIdxs = nil
|
||||
}
|
||||
10
vendor/github.com/libp2p/go-libp2p/core/sec/insecure/pb/plaintext.proto
generated
vendored
Normal file
10
vendor/github.com/libp2p/go-libp2p/core/sec/insecure/pb/plaintext.proto
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
syntax = "proto2";
|
||||
|
||||
package plaintext.pb;
|
||||
|
||||
import "core/crypto/pb/crypto.proto";
|
||||
|
||||
message Exchange {
|
||||
optional bytes id = 1;
|
||||
optional crypto.pb.PublicKey pubkey = 2;
|
||||
}
|
||||
43
vendor/github.com/libp2p/go-libp2p/core/sec/security.go
generated
vendored
Normal file
43
vendor/github.com/libp2p/go-libp2p/core/sec/security.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
// Package sec provides secure connection and transport interfaces for libp2p.
|
||||
package sec
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
)
|
||||
|
||||
// SecureConn is an authenticated, encrypted connection.
|
||||
type SecureConn interface {
|
||||
net.Conn
|
||||
network.ConnSecurity
|
||||
}
|
||||
|
||||
// A SecureTransport turns inbound and outbound unauthenticated,
|
||||
// plain-text, native connections into authenticated, encrypted connections.
|
||||
type SecureTransport interface {
|
||||
// SecureInbound secures an inbound connection.
|
||||
// If p is empty, connections from any peer are accepted.
|
||||
SecureInbound(ctx context.Context, insecure net.Conn, p peer.ID) (SecureConn, error)
|
||||
|
||||
// SecureOutbound secures an outbound connection.
|
||||
SecureOutbound(ctx context.Context, insecure net.Conn, p peer.ID) (SecureConn, error)
|
||||
|
||||
// ID is the protocol ID of the security protocol.
|
||||
ID() protocol.ID
|
||||
}
|
||||
|
||||
type ErrPeerIDMismatch struct {
|
||||
Expected peer.ID
|
||||
Actual peer.ID
|
||||
}
|
||||
|
||||
func (e ErrPeerIDMismatch) Error() string {
|
||||
return fmt.Sprintf("peer id mismatch: expected %s, but remote key matches %s", e.Expected, e.Actual)
|
||||
}
|
||||
|
||||
var _ error = (*ErrPeerIDMismatch)(nil)
|
||||
42
vendor/github.com/libp2p/go-libp2p/core/test/addrs.go
generated
vendored
Normal file
42
vendor/github.com/libp2p/go-libp2p/core/test/addrs.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
func GenerateTestAddrs(n int) []ma.Multiaddr {
|
||||
out := make([]ma.Multiaddr, n)
|
||||
for i := 0; i < n; i++ {
|
||||
a, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/1.2.3.4/tcp/%d", i))
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
out[i] = a
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func AssertAddressesEqual(t *testing.T, exp, act []ma.Multiaddr) {
|
||||
t.Helper()
|
||||
if len(exp) != len(act) {
|
||||
t.Fatalf("lengths not the same. expected %d, got %d\n", len(exp), len(act))
|
||||
}
|
||||
|
||||
for _, a := range exp {
|
||||
found := false
|
||||
|
||||
for _, b := range act {
|
||||
if a.Equal(b) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Fatalf("expected address %s not found", a)
|
||||
}
|
||||
}
|
||||
}
|
||||
21
vendor/github.com/libp2p/go-libp2p/core/test/crypto.go
generated
vendored
Normal file
21
vendor/github.com/libp2p/go-libp2p/core/test/crypto.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sync/atomic"
|
||||
|
||||
ci "github.com/libp2p/go-libp2p/core/crypto"
|
||||
)
|
||||
|
||||
var globalSeed atomic.Int64
|
||||
|
||||
func RandTestKeyPair(typ, bits int) (ci.PrivKey, ci.PubKey, error) {
|
||||
// workaround for low time resolution
|
||||
seed := globalSeed.Add(1)
|
||||
return SeededTestKeyPair(typ, bits, seed)
|
||||
}
|
||||
|
||||
func SeededTestKeyPair(typ, bits int, seed int64) (ci.PrivKey, ci.PubKey, error) {
|
||||
r := rand.New(rand.NewSource(seed))
|
||||
return ci.GenerateKeyPairWithReader(typ, bits, r)
|
||||
}
|
||||
19
vendor/github.com/libp2p/go-libp2p/core/test/errors.go
generated
vendored
Normal file
19
vendor/github.com/libp2p/go-libp2p/core/test/errors.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func AssertNilError(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func ExpectError(t *testing.T, err error, msg string) {
|
||||
t.Helper()
|
||||
if err == nil {
|
||||
t.Error(msg)
|
||||
}
|
||||
}
|
||||
136
vendor/github.com/libp2p/go-libp2p/core/test/mockclock.go
generated
vendored
Normal file
136
vendor/github.com/libp2p/go-libp2p/core/test/mockclock.go
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MockClock struct {
|
||||
mu sync.Mutex
|
||||
now time.Time
|
||||
timers []*mockInstantTimer
|
||||
advanceBySem chan struct{}
|
||||
}
|
||||
|
||||
type mockInstantTimer struct {
|
||||
c *MockClock
|
||||
mu sync.Mutex
|
||||
when time.Time
|
||||
active bool
|
||||
ch chan time.Time
|
||||
}
|
||||
|
||||
func (t *mockInstantTimer) Ch() <-chan time.Time {
|
||||
return t.ch
|
||||
}
|
||||
|
||||
func (t *mockInstantTimer) Reset(d time.Time) bool {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
wasActive := t.active
|
||||
t.active = true
|
||||
t.when = d
|
||||
|
||||
// Schedule any timers that need to run. This will run this timer if t.when is before c.now
|
||||
go t.c.AdvanceBy(0)
|
||||
|
||||
return wasActive
|
||||
}
|
||||
|
||||
func (t *mockInstantTimer) Stop() bool {
|
||||
t.mu.Lock()
|
||||
defer t.mu.Unlock()
|
||||
wasActive := t.active
|
||||
t.active = false
|
||||
return wasActive
|
||||
}
|
||||
|
||||
func NewMockClock() *MockClock {
|
||||
return &MockClock{now: time.Unix(0, 0), advanceBySem: make(chan struct{}, 1)}
|
||||
}
|
||||
|
||||
// InstantTimer implements a timer that triggers at a fixed instant in time as opposed to after a
|
||||
// fixed duration from the moment of creation/reset.
|
||||
//
|
||||
// In test environments, when using a Timer which fires after a duration, there is a race between
|
||||
// the goroutine moving time forward using `clock.Advanceby` and the goroutine resetting the
|
||||
// timer by doing `timer.Reset(desiredInstant.Sub(time.Now()))`. The value of
|
||||
// `desiredInstance.sub(time.Now())` is different depending on whether `clock.AdvanceBy` finishes
|
||||
// before or after the timer reset.
|
||||
func (c *MockClock) InstantTimer(when time.Time) *mockInstantTimer {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
t := &mockInstantTimer{
|
||||
c: c,
|
||||
when: when,
|
||||
ch: make(chan time.Time, 1),
|
||||
active: true,
|
||||
}
|
||||
c.timers = append(c.timers, t)
|
||||
return t
|
||||
}
|
||||
|
||||
// Since implements autorelay.ClockWithInstantTimer
|
||||
func (c *MockClock) Since(t time.Time) time.Duration {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
return c.now.Sub(t)
|
||||
}
|
||||
|
||||
func (c *MockClock) Now() time.Time {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
return c.now
|
||||
}
|
||||
|
||||
func (c *MockClock) AdvanceBy(dur time.Duration) {
|
||||
c.advanceBySem <- struct{}{}
|
||||
defer func() { <-c.advanceBySem }()
|
||||
|
||||
c.mu.Lock()
|
||||
now := c.now
|
||||
endTime := c.now.Add(dur)
|
||||
c.mu.Unlock()
|
||||
|
||||
// sort timers by when
|
||||
if len(c.timers) > 1 {
|
||||
sort.Slice(c.timers, func(i, j int) bool {
|
||||
c.timers[i].mu.Lock()
|
||||
c.timers[j].mu.Lock()
|
||||
defer c.timers[i].mu.Unlock()
|
||||
defer c.timers[j].mu.Unlock()
|
||||
return c.timers[i].when.Before(c.timers[j].when)
|
||||
})
|
||||
}
|
||||
|
||||
for _, t := range c.timers {
|
||||
t.mu.Lock()
|
||||
if !t.active {
|
||||
t.mu.Unlock()
|
||||
continue
|
||||
}
|
||||
if !t.when.After(now) {
|
||||
t.active = false
|
||||
t.mu.Unlock()
|
||||
// This may block if the channel is full, but that's intended. This way our mock clock never gets too far ahead of consumer.
|
||||
// This also prevents us from dropping times because we're advancing too fast.
|
||||
t.ch <- now
|
||||
} else if !t.when.After(endTime) {
|
||||
now = t.when
|
||||
c.mu.Lock()
|
||||
c.now = now
|
||||
c.mu.Unlock()
|
||||
|
||||
t.active = false
|
||||
t.mu.Unlock()
|
||||
// This may block if the channel is full, but that's intended. See comment above
|
||||
t.ch <- c.now
|
||||
} else {
|
||||
t.mu.Unlock()
|
||||
}
|
||||
}
|
||||
c.mu.Lock()
|
||||
c.now = endTime
|
||||
c.mu.Unlock()
|
||||
}
|
||||
25
vendor/github.com/libp2p/go-libp2p/core/test/peer.go
generated
vendored
Normal file
25
vendor/github.com/libp2p/go-libp2p/core/test/peer.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package test
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
)
|
||||
|
||||
func RandPeerID() (peer.ID, error) {
|
||||
buf := make([]byte, 16)
|
||||
rand.Read(buf)
|
||||
h, _ := mh.Sum(buf, mh.SHA2_256, -1)
|
||||
return peer.ID(h), nil
|
||||
}
|
||||
|
||||
func RandPeerIDFatal(t testing.TB) peer.ID {
|
||||
p, err := RandPeerID()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return p
|
||||
}
|
||||
171
vendor/github.com/libp2p/go-libp2p/core/transport/transport.go
generated
vendored
Normal file
171
vendor/github.com/libp2p/go-libp2p/core/transport/transport.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
// Package transport provides the Transport interface, which represents
|
||||
// the devices and network protocols used to send and receive data.
|
||||
package transport
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
)
|
||||
|
||||
// A CapableConn represents a connection that has offers the basic
|
||||
// capabilities required by libp2p: stream multiplexing, encryption and
|
||||
// peer authentication.
|
||||
//
|
||||
// These capabilities may be natively provided by the transport, or they
|
||||
// may be shimmed via the "connection upgrade" process, which converts a
|
||||
// "raw" network connection into one that supports such capabilities by
|
||||
// layering an encryption channel and a stream multiplexer.
|
||||
//
|
||||
// CapableConn provides accessors for the local and remote multiaddrs used to
|
||||
// establish the connection and an accessor for the underlying Transport.
|
||||
type CapableConn interface {
|
||||
network.MuxedConn
|
||||
network.ConnSecurity
|
||||
network.ConnMultiaddrs
|
||||
network.ConnScoper
|
||||
|
||||
// Transport returns the transport to which this connection belongs.
|
||||
Transport() Transport
|
||||
}
|
||||
|
||||
// Transport represents any device by which you can connect to and accept
|
||||
// connections from other peers.
|
||||
//
|
||||
// The Transport interface allows you to open connections to other peers
|
||||
// by dialing them, and also lets you listen for incoming connections.
|
||||
//
|
||||
// Connections returned by Dial and passed into Listeners are of type
|
||||
// CapableConn, which means that they have been upgraded to support
|
||||
// stream multiplexing and connection security (encryption and authentication).
|
||||
//
|
||||
// If a transport implements `io.Closer` (optional), libp2p will call `Close` on
|
||||
// shutdown. NOTE: `Dial` and `Listen` may be called after or concurrently with
|
||||
// `Close`.
|
||||
//
|
||||
// For a conceptual overview, see https://docs.libp2p.io/concepts/transport/
|
||||
type Transport interface {
|
||||
// Dial dials a remote peer. It should try to reuse local listener
|
||||
// addresses if possible, but it may choose not to.
|
||||
Dial(ctx context.Context, raddr ma.Multiaddr, p peer.ID) (CapableConn, error)
|
||||
|
||||
// CanDial returns true if this transport knows how to dial the given
|
||||
// multiaddr.
|
||||
//
|
||||
// Returning true does not guarantee that dialing this multiaddr will
|
||||
// succeed. This function should *only* be used to preemptively filter
|
||||
// out addresses that we can't dial.
|
||||
CanDial(addr ma.Multiaddr) bool
|
||||
|
||||
// Listen listens on the passed multiaddr.
|
||||
Listen(laddr ma.Multiaddr) (Listener, error)
|
||||
|
||||
// Protocol returns the set of protocols handled by this transport.
|
||||
//
|
||||
// See the Network interface for an explanation of how this is used.
|
||||
Protocols() []int
|
||||
|
||||
// Proxy returns true if this is a proxy transport.
|
||||
//
|
||||
// See the Network interface for an explanation of how this is used.
|
||||
// TODO: Make this a part of the go-multiaddr protocol instead?
|
||||
Proxy() bool
|
||||
}
|
||||
|
||||
// Resolver can be optionally implemented by transports that want to resolve or transform the
|
||||
// multiaddr.
|
||||
type Resolver interface {
|
||||
Resolve(ctx context.Context, maddr ma.Multiaddr) ([]ma.Multiaddr, error)
|
||||
}
|
||||
|
||||
// Listener is an interface closely resembling the net.Listener interface. The
|
||||
// only real difference is that Accept() returns Conn's of the type in this
|
||||
// package, and also exposes a Multiaddr method as opposed to a regular Addr
|
||||
// method
|
||||
type Listener interface {
|
||||
Accept() (CapableConn, error)
|
||||
Close() error
|
||||
Addr() net.Addr
|
||||
Multiaddr() ma.Multiaddr
|
||||
}
|
||||
|
||||
// ErrListenerClosed is returned by Listener.Accept when the listener is gracefully closed.
|
||||
var ErrListenerClosed = errors.New("listener closed")
|
||||
|
||||
// TransportNetwork is an inet.Network with methods for managing transports.
|
||||
type TransportNetwork interface {
|
||||
network.Network
|
||||
|
||||
// AddTransport adds a transport to this Network.
|
||||
//
|
||||
// When dialing, this Network will iterate over the protocols in the
|
||||
// remote multiaddr and pick the first protocol registered with a proxy
|
||||
// transport, if any. Otherwise, it'll pick the transport registered to
|
||||
// handle the last protocol in the multiaddr.
|
||||
//
|
||||
// When listening, this Network will iterate over the protocols in the
|
||||
// local multiaddr and pick the *last* protocol registered with a proxy
|
||||
// transport, if any. Otherwise, it'll pick the transport registered to
|
||||
// handle the last protocol in the multiaddr.
|
||||
AddTransport(t Transport) error
|
||||
}
|
||||
|
||||
// Upgrader is a multistream upgrader that can upgrade an underlying connection
|
||||
// to a full transport connection (secure and multiplexed).
|
||||
type Upgrader interface {
|
||||
// UpgradeListener upgrades the passed multiaddr-net listener into a full libp2p-transport listener.
|
||||
UpgradeListener(Transport, manet.Listener) Listener
|
||||
// Upgrade upgrades the multiaddr/net connection into a full libp2p-transport connection.
|
||||
Upgrade(ctx context.Context, t Transport, maconn manet.Conn, dir network.Direction, p peer.ID, scope network.ConnManagementScope) (CapableConn, error)
|
||||
}
|
||||
|
||||
// DialUpdater provides updates on in progress dials.
|
||||
type DialUpdater interface {
|
||||
// DialWithUpdates dials a remote peer and provides updates on the passed channel.
|
||||
DialWithUpdates(context.Context, ma.Multiaddr, peer.ID, chan<- DialUpdate) (CapableConn, error)
|
||||
}
|
||||
|
||||
// DialUpdateKind indicates the type of DialUpdate event.
|
||||
type DialUpdateKind int
|
||||
|
||||
const (
|
||||
// UpdateKindDialFailed indicates dial failed.
|
||||
UpdateKindDialFailed DialUpdateKind = iota
|
||||
// UpdateKindDialSuccessful indicates dial succeeded.
|
||||
UpdateKindDialSuccessful
|
||||
// UpdateKindHandshakeProgressed indicates successful completion of the TCP 3-way
|
||||
// handshake
|
||||
UpdateKindHandshakeProgressed
|
||||
)
|
||||
|
||||
func (k DialUpdateKind) String() string {
|
||||
switch k {
|
||||
case UpdateKindDialFailed:
|
||||
return "DialFailed"
|
||||
case UpdateKindDialSuccessful:
|
||||
return "DialSuccessful"
|
||||
case UpdateKindHandshakeProgressed:
|
||||
return "UpdateKindHandshakeProgressed"
|
||||
default:
|
||||
return fmt.Sprintf("DialUpdateKind<Unknown-%d>", k)
|
||||
}
|
||||
}
|
||||
|
||||
// DialUpdate is used by DialUpdater to provide dial updates.
|
||||
type DialUpdate struct {
|
||||
// Kind is the kind of update event.
|
||||
Kind DialUpdateKind
|
||||
// Addr is the peer's address.
|
||||
Addr ma.Multiaddr
|
||||
// Conn is the resulting connection on success.
|
||||
Conn CapableConn
|
||||
// Err is the reason for dial failure.
|
||||
Err error
|
||||
}
|
||||
218
vendor/github.com/libp2p/go-libp2p/defaults.go
generated
vendored
Normal file
218
vendor/github.com/libp2p/go-libp2p/defaults.go
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
package libp2p
|
||||
|
||||
// This file contains all the default configuration options.
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem"
|
||||
rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
|
||||
"github.com/libp2p/go-libp2p/p2p/muxer/yamux"
|
||||
"github.com/libp2p/go-libp2p/p2p/net/connmgr"
|
||||
"github.com/libp2p/go-libp2p/p2p/security/noise"
|
||||
tls "github.com/libp2p/go-libp2p/p2p/security/tls"
|
||||
quic "github.com/libp2p/go-libp2p/p2p/transport/quic"
|
||||
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
|
||||
ws "github.com/libp2p/go-libp2p/p2p/transport/websocket"
|
||||
webtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
madns "github.com/multiformats/go-multiaddr-dns"
|
||||
)
|
||||
|
||||
// DefaultSecurity is the default security option.
|
||||
//
|
||||
// Useful when you want to extend, but not replace, the supported transport
|
||||
// security protocols.
|
||||
var DefaultSecurity = ChainOptions(
|
||||
Security(noise.ID, noise.New),
|
||||
Security(tls.ID, tls.New),
|
||||
)
|
||||
|
||||
// DefaultMuxers configures libp2p to use the stream connection multiplexers.
|
||||
//
|
||||
// Use this option when you want to *extend* the set of multiplexers used by
|
||||
// libp2p instead of replacing them.
|
||||
var DefaultMuxers = Muxer(yamux.ID, yamux.DefaultTransport)
|
||||
|
||||
// DefaultTransports are the default libp2p transports.
|
||||
//
|
||||
// Use this option when you want to *extend* the set of transports used by
|
||||
// libp2p instead of replacing them.
|
||||
var DefaultTransports = ChainOptions(
|
||||
Transport(tcp.NewTCPTransport),
|
||||
Transport(quic.NewTransport),
|
||||
Transport(ws.New),
|
||||
Transport(webtransport.New),
|
||||
)
|
||||
|
||||
// DefaultPrivateTransports are the default libp2p transports when a PSK is supplied.
|
||||
//
|
||||
// Use this option when you want to *extend* the set of transports used by
|
||||
// libp2p instead of replacing them.
|
||||
var DefaultPrivateTransports = ChainOptions(
|
||||
Transport(tcp.NewTCPTransport),
|
||||
Transport(ws.New),
|
||||
)
|
||||
|
||||
// DefaultPeerstore configures libp2p to use the default peerstore.
|
||||
var DefaultPeerstore Option = func(cfg *Config) error {
|
||||
ps, err := pstoremem.NewPeerstore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cfg.Apply(Peerstore(ps))
|
||||
}
|
||||
|
||||
// RandomIdentity generates a random identity. (default behaviour)
|
||||
var RandomIdentity = func(cfg *Config) error {
|
||||
priv, _, err := crypto.GenerateEd25519Key(rand.Reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cfg.Apply(Identity(priv))
|
||||
}
|
||||
|
||||
// DefaultListenAddrs configures libp2p to use default listen address.
|
||||
var DefaultListenAddrs = func(cfg *Config) error {
|
||||
addrs := []string{
|
||||
"/ip4/0.0.0.0/tcp/0",
|
||||
"/ip4/0.0.0.0/udp/0/quic-v1",
|
||||
"/ip4/0.0.0.0/udp/0/quic-v1/webtransport",
|
||||
"/ip6/::/tcp/0",
|
||||
"/ip6/::/udp/0/quic-v1",
|
||||
"/ip6/::/udp/0/quic-v1/webtransport",
|
||||
}
|
||||
listenAddrs := make([]multiaddr.Multiaddr, 0, len(addrs))
|
||||
for _, s := range addrs {
|
||||
addr, err := multiaddr.NewMultiaddr(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
listenAddrs = append(listenAddrs, addr)
|
||||
}
|
||||
return cfg.Apply(ListenAddrs(listenAddrs...))
|
||||
}
|
||||
|
||||
// DefaultEnableRelay enables relay dialing and listening by default.
|
||||
var DefaultEnableRelay = func(cfg *Config) error {
|
||||
return cfg.Apply(EnableRelay())
|
||||
}
|
||||
|
||||
var DefaultResourceManager = func(cfg *Config) error {
|
||||
// Default memory limit: 1/8th of total memory, minimum 128MB, maximum 1GB
|
||||
limits := rcmgr.DefaultLimits
|
||||
SetDefaultServiceLimits(&limits)
|
||||
mgr, err := rcmgr.NewResourceManager(rcmgr.NewFixedLimiter(limits.AutoScale()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cfg.Apply(ResourceManager(mgr))
|
||||
}
|
||||
|
||||
// DefaultConnectionManager creates a default connection manager
|
||||
var DefaultConnectionManager = func(cfg *Config) error {
|
||||
mgr, err := connmgr.NewConnManager(160, 192)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return cfg.Apply(ConnectionManager(mgr))
|
||||
}
|
||||
|
||||
// DefaultMultiaddrResolver creates a default connection manager
|
||||
var DefaultMultiaddrResolver = func(cfg *Config) error {
|
||||
return cfg.Apply(MultiaddrResolver(madns.DefaultResolver))
|
||||
}
|
||||
|
||||
// DefaultPrometheusRegisterer configures libp2p to use the default registerer
|
||||
var DefaultPrometheusRegisterer = func(cfg *Config) error {
|
||||
return cfg.Apply(PrometheusRegisterer(prometheus.DefaultRegisterer))
|
||||
}
|
||||
|
||||
// Complete list of default options and when to fallback on them.
|
||||
//
|
||||
// Please *DON'T* specify default options any other way. Putting this all here
|
||||
// makes tracking defaults *much* easier.
|
||||
var defaults = []struct {
|
||||
fallback func(cfg *Config) bool
|
||||
opt Option
|
||||
}{
|
||||
{
|
||||
fallback: func(cfg *Config) bool { return cfg.Transports == nil && cfg.ListenAddrs == nil },
|
||||
opt: DefaultListenAddrs,
|
||||
},
|
||||
{
|
||||
fallback: func(cfg *Config) bool { return cfg.Transports == nil && cfg.PSK == nil },
|
||||
opt: DefaultTransports,
|
||||
},
|
||||
{
|
||||
fallback: func(cfg *Config) bool { return cfg.Transports == nil && cfg.PSK != nil },
|
||||
opt: DefaultPrivateTransports,
|
||||
},
|
||||
{
|
||||
fallback: func(cfg *Config) bool { return cfg.Muxers == nil },
|
||||
opt: DefaultMuxers,
|
||||
},
|
||||
{
|
||||
fallback: func(cfg *Config) bool { return !cfg.Insecure && cfg.SecurityTransports == nil },
|
||||
opt: DefaultSecurity,
|
||||
},
|
||||
{
|
||||
fallback: func(cfg *Config) bool { return cfg.PeerKey == nil },
|
||||
opt: RandomIdentity,
|
||||
},
|
||||
{
|
||||
fallback: func(cfg *Config) bool { return cfg.Peerstore == nil },
|
||||
opt: DefaultPeerstore,
|
||||
},
|
||||
{
|
||||
fallback: func(cfg *Config) bool { return !cfg.RelayCustom },
|
||||
opt: DefaultEnableRelay,
|
||||
},
|
||||
{
|
||||
fallback: func(cfg *Config) bool { return cfg.ResourceManager == nil },
|
||||
opt: DefaultResourceManager,
|
||||
},
|
||||
{
|
||||
fallback: func(cfg *Config) bool { return cfg.ConnManager == nil },
|
||||
opt: DefaultConnectionManager,
|
||||
},
|
||||
{
|
||||
fallback: func(cfg *Config) bool { return cfg.MultiaddrResolver == nil },
|
||||
opt: DefaultMultiaddrResolver,
|
||||
},
|
||||
{
|
||||
fallback: func(cfg *Config) bool { return !cfg.DisableMetrics && cfg.PrometheusRegisterer == nil },
|
||||
opt: DefaultPrometheusRegisterer,
|
||||
},
|
||||
}
|
||||
|
||||
// Defaults configures libp2p to use the default options. Can be combined with
|
||||
// other options to *extend* the default options.
|
||||
var Defaults Option = func(cfg *Config) error {
|
||||
for _, def := range defaults {
|
||||
if err := cfg.Apply(def.opt); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FallbackDefaults applies default options to the libp2p node if and only if no
|
||||
// other relevant options have been applied. will be appended to the options
|
||||
// passed into New.
|
||||
var FallbackDefaults Option = func(cfg *Config) error {
|
||||
for _, def := range defaults {
|
||||
if !def.fallback(cfg) {
|
||||
continue
|
||||
}
|
||||
if err := cfg.Apply(def.opt); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
23
vendor/github.com/libp2p/go-libp2p/internal/sha256/post_go1_21.go
generated
vendored
Normal file
23
vendor/github.com/libp2p/go-libp2p/internal/sha256/post_go1_21.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
//go:build go1.21
|
||||
|
||||
// This package use build tags to select between github.com/minio/sha256-simd
|
||||
// for go1.20 and bellow and crypto/sha256 for go1.21 and above.
|
||||
// This is used because a fast SHANI implementation of sha256 is only avaiable
|
||||
// in the std for go1.21 and above. See https://go.dev/issue/50543.
|
||||
// TODO: Once go1.22 releases remove this package and replace all uses
|
||||
// with crypto/sha256 because the two supported version of go will have the fast
|
||||
// implementation.
|
||||
package sha256
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"hash"
|
||||
)
|
||||
|
||||
func Sum256(b []byte) [sha256.Size]byte {
|
||||
return sha256.Sum256(b)
|
||||
}
|
||||
|
||||
func New() hash.Hash {
|
||||
return sha256.New()
|
||||
}
|
||||
24
vendor/github.com/libp2p/go-libp2p/internal/sha256/pre_go1_21.go
generated
vendored
Normal file
24
vendor/github.com/libp2p/go-libp2p/internal/sha256/pre_go1_21.go
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
//go:build !go1.21
|
||||
|
||||
// This package use build tags to select between github.com/minio/sha256-simd
|
||||
// for go1.20 and bellow and crypto/sha256 for go1.21 and above.
|
||||
// This is used because a fast SHANI implementation of sha256 is only avaiable
|
||||
// in the std for go1.21 and above. See https://go.dev/issue/50543.
|
||||
// TODO: Once go1.22 releases remove this package and replace all uses
|
||||
// with crypto/sha256 because the two supported version of go will have the fast
|
||||
// implementation.
|
||||
package sha256
|
||||
|
||||
import (
|
||||
"hash"
|
||||
|
||||
"github.com/minio/sha256-simd"
|
||||
)
|
||||
|
||||
func Sum256(b []byte) [sha256.Size]byte {
|
||||
return sha256.Sum256(b)
|
||||
}
|
||||
|
||||
func New() hash.Hash {
|
||||
return sha256.New()
|
||||
}
|
||||
68
vendor/github.com/libp2p/go-libp2p/libp2p.go
generated
vendored
Normal file
68
vendor/github.com/libp2p/go-libp2p/libp2p.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
package libp2p
|
||||
|
||||
import (
|
||||
"github.com/libp2p/go-libp2p/config"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
)
|
||||
|
||||
// Config describes a set of settings for a libp2p node.
|
||||
type Config = config.Config
|
||||
|
||||
// Option is a libp2p config option that can be given to the libp2p constructor
|
||||
// (`libp2p.New`).
|
||||
type Option = config.Option
|
||||
|
||||
// ChainOptions chains multiple options into a single option.
|
||||
func ChainOptions(opts ...Option) Option {
|
||||
return func(cfg *Config) error {
|
||||
for _, opt := range opts {
|
||||
if opt == nil {
|
||||
continue
|
||||
}
|
||||
if err := opt(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// New constructs a new libp2p node with the given options, falling back on
|
||||
// reasonable defaults. The defaults are:
|
||||
//
|
||||
// - If no transport and listen addresses are provided, the node listens to
|
||||
// the multiaddresses "/ip4/0.0.0.0/tcp/0" and "/ip6/::/tcp/0";
|
||||
//
|
||||
// - If no transport options are provided, the node uses TCP, websocket and QUIC
|
||||
// transport protocols;
|
||||
//
|
||||
// - If no multiplexer configuration is provided, the node is configured by
|
||||
// default to use yamux;
|
||||
//
|
||||
// - If no security transport is provided, the host uses the go-libp2p's noise
|
||||
// and/or tls encrypted transport to encrypt all traffic;
|
||||
//
|
||||
// - If no peer identity is provided, it generates a random RSA 2048 key-pair
|
||||
// and derives a new identity from it;
|
||||
//
|
||||
// - If no peerstore is provided, the host is initialized with an empty
|
||||
// peerstore.
|
||||
//
|
||||
// To stop/shutdown the returned libp2p node, the user needs to cancel the passed context and call `Close` on the returned Host.
|
||||
func New(opts ...Option) (host.Host, error) {
|
||||
return NewWithoutDefaults(append(opts, FallbackDefaults)...)
|
||||
}
|
||||
|
||||
// NewWithoutDefaults constructs a new libp2p node with the given options but
|
||||
// *without* falling back on reasonable defaults.
|
||||
//
|
||||
// Warning: This function should not be considered a stable interface. We may
|
||||
// choose to add required services at any time and, by using this function, you
|
||||
// opt-out of any defaults we may provide.
|
||||
func NewWithoutDefaults(opts ...Option) (host.Host, error) {
|
||||
var cfg Config
|
||||
if err := cfg.Apply(opts...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg.NewNode()
|
||||
}
|
||||
113
vendor/github.com/libp2p/go-libp2p/limits.go
generated
vendored
Normal file
113
vendor/github.com/libp2p/go-libp2p/limits.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
package libp2p
|
||||
|
||||
import (
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/autonat"
|
||||
rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
|
||||
circuit "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/proto"
|
||||
relayv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/holepunch"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/identify"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/ping"
|
||||
)
|
||||
|
||||
// SetDefaultServiceLimits sets the default limits for bundled libp2p services
|
||||
func SetDefaultServiceLimits(config *rcmgr.ScalingLimitConfig) {
|
||||
// identify
|
||||
config.AddServiceLimit(
|
||||
identify.ServiceName,
|
||||
rcmgr.BaseLimit{StreamsInbound: 64, StreamsOutbound: 64, Streams: 128, Memory: 4 << 20},
|
||||
rcmgr.BaseLimitIncrease{StreamsInbound: 64, StreamsOutbound: 64, Streams: 128, Memory: 4 << 20},
|
||||
)
|
||||
config.AddServicePeerLimit(
|
||||
identify.ServiceName,
|
||||
rcmgr.BaseLimit{StreamsInbound: 16, StreamsOutbound: 16, Streams: 32, Memory: 1 << 20},
|
||||
rcmgr.BaseLimitIncrease{},
|
||||
)
|
||||
for _, id := range [...]protocol.ID{identify.ID, identify.IDPush} {
|
||||
config.AddProtocolLimit(
|
||||
id,
|
||||
rcmgr.BaseLimit{StreamsInbound: 64, StreamsOutbound: 64, Streams: 128, Memory: 4 << 20},
|
||||
rcmgr.BaseLimitIncrease{StreamsInbound: 64, StreamsOutbound: 64, Streams: 128, Memory: 4 << 20},
|
||||
)
|
||||
config.AddProtocolPeerLimit(
|
||||
id,
|
||||
rcmgr.BaseLimit{StreamsInbound: 16, StreamsOutbound: 16, Streams: 32, Memory: 32 * (256<<20 + 16<<10)},
|
||||
rcmgr.BaseLimitIncrease{},
|
||||
)
|
||||
}
|
||||
|
||||
// ping
|
||||
addServiceAndProtocolLimit(config,
|
||||
ping.ServiceName, ping.ID,
|
||||
rcmgr.BaseLimit{StreamsInbound: 64, StreamsOutbound: 64, Streams: 64, Memory: 4 << 20},
|
||||
rcmgr.BaseLimitIncrease{StreamsInbound: 64, StreamsOutbound: 64, Streams: 64, Memory: 4 << 20},
|
||||
)
|
||||
addServicePeerAndProtocolPeerLimit(
|
||||
config,
|
||||
ping.ServiceName, ping.ID,
|
||||
rcmgr.BaseLimit{StreamsInbound: 2, StreamsOutbound: 3, Streams: 4, Memory: 32 * (256<<20 + 16<<10)},
|
||||
rcmgr.BaseLimitIncrease{},
|
||||
)
|
||||
|
||||
// autonat
|
||||
addServiceAndProtocolLimit(config,
|
||||
autonat.ServiceName, autonat.AutoNATProto,
|
||||
rcmgr.BaseLimit{StreamsInbound: 64, StreamsOutbound: 64, Streams: 64, Memory: 4 << 20},
|
||||
rcmgr.BaseLimitIncrease{StreamsInbound: 4, StreamsOutbound: 4, Streams: 4, Memory: 2 << 20},
|
||||
)
|
||||
addServicePeerAndProtocolPeerLimit(
|
||||
config,
|
||||
autonat.ServiceName, autonat.AutoNATProto,
|
||||
rcmgr.BaseLimit{StreamsInbound: 2, StreamsOutbound: 2, Streams: 2, Memory: 1 << 20},
|
||||
rcmgr.BaseLimitIncrease{},
|
||||
)
|
||||
|
||||
// holepunch
|
||||
addServiceAndProtocolLimit(config,
|
||||
holepunch.ServiceName, holepunch.Protocol,
|
||||
rcmgr.BaseLimit{StreamsInbound: 32, StreamsOutbound: 32, Streams: 64, Memory: 4 << 20},
|
||||
rcmgr.BaseLimitIncrease{StreamsInbound: 8, StreamsOutbound: 8, Streams: 16, Memory: 4 << 20},
|
||||
)
|
||||
addServicePeerAndProtocolPeerLimit(config,
|
||||
holepunch.ServiceName, holepunch.Protocol,
|
||||
rcmgr.BaseLimit{StreamsInbound: 2, StreamsOutbound: 2, Streams: 2, Memory: 1 << 20},
|
||||
rcmgr.BaseLimitIncrease{},
|
||||
)
|
||||
|
||||
// relay/v2
|
||||
config.AddServiceLimit(
|
||||
relayv2.ServiceName,
|
||||
rcmgr.BaseLimit{StreamsInbound: 256, StreamsOutbound: 256, Streams: 256, Memory: 16 << 20},
|
||||
rcmgr.BaseLimitIncrease{StreamsInbound: 256, StreamsOutbound: 256, Streams: 256, Memory: 16 << 20},
|
||||
)
|
||||
config.AddServicePeerLimit(
|
||||
relayv2.ServiceName,
|
||||
rcmgr.BaseLimit{StreamsInbound: 64, StreamsOutbound: 64, Streams: 64, Memory: 1 << 20},
|
||||
rcmgr.BaseLimitIncrease{},
|
||||
)
|
||||
|
||||
// circuit protocols, both client and service
|
||||
for _, proto := range [...]protocol.ID{circuit.ProtoIDv2Hop, circuit.ProtoIDv2Stop} {
|
||||
config.AddProtocolLimit(
|
||||
proto,
|
||||
rcmgr.BaseLimit{StreamsInbound: 640, StreamsOutbound: 640, Streams: 640, Memory: 16 << 20},
|
||||
rcmgr.BaseLimitIncrease{StreamsInbound: 640, StreamsOutbound: 640, Streams: 640, Memory: 16 << 20},
|
||||
)
|
||||
config.AddProtocolPeerLimit(
|
||||
proto,
|
||||
rcmgr.BaseLimit{StreamsInbound: 128, StreamsOutbound: 128, Streams: 128, Memory: 32 << 20},
|
||||
rcmgr.BaseLimitIncrease{},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func addServiceAndProtocolLimit(config *rcmgr.ScalingLimitConfig, service string, proto protocol.ID, limit rcmgr.BaseLimit, increase rcmgr.BaseLimitIncrease) {
|
||||
config.AddServiceLimit(service, limit, increase)
|
||||
config.AddProtocolLimit(proto, limit, increase)
|
||||
}
|
||||
|
||||
func addServicePeerAndProtocolPeerLimit(config *rcmgr.ScalingLimitConfig, service string, proto protocol.ID, limit rcmgr.BaseLimit, increase rcmgr.BaseLimitIncrease) {
|
||||
config.AddServicePeerLimit(service, limit, increase)
|
||||
config.AddProtocolPeerLimit(proto, limit, increase)
|
||||
}
|
||||
600
vendor/github.com/libp2p/go-libp2p/options.go
generated
vendored
Normal file
600
vendor/github.com/libp2p/go-libp2p/options.go
generated
vendored
Normal file
@@ -0,0 +1,600 @@
|
||||
package libp2p
|
||||
|
||||
// This file contains all libp2p configuration options (except the defaults,
|
||||
// those are in defaults.go).
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/config"
|
||||
"github.com/libp2p/go-libp2p/core/connmgr"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/metrics"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/peerstore"
|
||||
"github.com/libp2p/go-libp2p/core/pnet"
|
||||
"github.com/libp2p/go-libp2p/core/protocol"
|
||||
"github.com/libp2p/go-libp2p/core/transport"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/autorelay"
|
||||
bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
|
||||
"github.com/libp2p/go-libp2p/p2p/net/swarm"
|
||||
tptu "github.com/libp2p/go-libp2p/p2p/net/upgrader"
|
||||
relayv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
|
||||
"github.com/libp2p/go-libp2p/p2p/protocol/holepunch"
|
||||
"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
madns "github.com/multiformats/go-multiaddr-dns"
|
||||
"go.uber.org/fx"
|
||||
)
|
||||
|
||||
// ListenAddrStrings configures libp2p to listen on the given (unparsed)
|
||||
// addresses.
|
||||
func ListenAddrStrings(s ...string) Option {
|
||||
return func(cfg *Config) error {
|
||||
for _, addrstr := range s {
|
||||
a, err := ma.NewMultiaddr(addrstr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg.ListenAddrs = append(cfg.ListenAddrs, a)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ListenAddrs configures libp2p to listen on the given addresses.
|
||||
func ListenAddrs(addrs ...ma.Multiaddr) Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.ListenAddrs = append(cfg.ListenAddrs, addrs...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Security configures libp2p to use the given security transport (or transport
|
||||
// constructor).
|
||||
//
|
||||
// Name is the protocol name.
|
||||
//
|
||||
// The transport can be a constructed security.Transport or a function taking
|
||||
// any subset of this libp2p node's:
|
||||
// * Public key
|
||||
// * Private key
|
||||
// * Peer ID
|
||||
// * Host
|
||||
// * Network
|
||||
// * Peerstore
|
||||
func Security(name string, constructor interface{}) Option {
|
||||
return func(cfg *Config) error {
|
||||
if cfg.Insecure {
|
||||
return fmt.Errorf("cannot use security transports with an insecure libp2p configuration")
|
||||
}
|
||||
cfg.SecurityTransports = append(cfg.SecurityTransports, config.Security{ID: protocol.ID(name), Constructor: constructor})
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NoSecurity is an option that completely disables all transport security.
|
||||
// It's incompatible with all other transport security protocols.
|
||||
var NoSecurity Option = func(cfg *Config) error {
|
||||
if len(cfg.SecurityTransports) > 0 {
|
||||
return fmt.Errorf("cannot use security transports with an insecure libp2p configuration")
|
||||
}
|
||||
cfg.Insecure = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// Muxer configures libp2p to use the given stream multiplexer.
|
||||
// name is the protocol name.
|
||||
func Muxer(name string, muxer network.Multiplexer) Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.Muxers = append(cfg.Muxers, tptu.StreamMuxer{Muxer: muxer, ID: protocol.ID(name)})
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func QUICReuse(constructor interface{}, opts ...quicreuse.Option) Option {
|
||||
return func(cfg *Config) error {
|
||||
tag := `group:"quicreuseopts"`
|
||||
typ := reflect.ValueOf(constructor).Type()
|
||||
numParams := typ.NumIn()
|
||||
isVariadic := typ.IsVariadic()
|
||||
|
||||
if !isVariadic && len(opts) > 0 {
|
||||
return errors.New("QUICReuse constructor doesn't take any options")
|
||||
}
|
||||
|
||||
var params []string
|
||||
if isVariadic && len(opts) > 0 {
|
||||
// If there are options, apply the tag.
|
||||
// Since options are variadic, they have to be the last argument of the constructor.
|
||||
params = make([]string, numParams)
|
||||
params[len(params)-1] = tag
|
||||
}
|
||||
|
||||
cfg.QUICReuse = append(cfg.QUICReuse, fx.Provide(fx.Annotate(constructor, fx.ParamTags(params...))))
|
||||
for _, opt := range opts {
|
||||
cfg.QUICReuse = append(cfg.QUICReuse, fx.Supply(fx.Annotate(opt, fx.ResultTags(tag))))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Transport configures libp2p to use the given transport (or transport
|
||||
// constructor).
|
||||
//
|
||||
// The transport can be a constructed transport.Transport or a function taking
|
||||
// any subset of this libp2p node's:
|
||||
// * Transport Upgrader (*tptu.Upgrader)
|
||||
// * Host
|
||||
// * Stream muxer (muxer.Transport)
|
||||
// * Security transport (security.Transport)
|
||||
// * Private network protector (pnet.Protector)
|
||||
// * Peer ID
|
||||
// * Private Key
|
||||
// * Public Key
|
||||
// * Address filter (filter.Filter)
|
||||
// * Peerstore
|
||||
func Transport(constructor interface{}, opts ...interface{}) Option {
|
||||
return func(cfg *Config) error {
|
||||
// generate a random identifier, so that fx can associate the constructor with its options
|
||||
b := make([]byte, 8)
|
||||
rand.Read(b)
|
||||
id := binary.BigEndian.Uint64(b)
|
||||
|
||||
tag := fmt.Sprintf(`group:"transportopt_%d"`, id)
|
||||
|
||||
typ := reflect.ValueOf(constructor).Type()
|
||||
numParams := typ.NumIn()
|
||||
isVariadic := typ.IsVariadic()
|
||||
|
||||
if !isVariadic && len(opts) > 0 {
|
||||
return errors.New("transport constructor doesn't take any options")
|
||||
}
|
||||
if isVariadic && numParams >= 1 {
|
||||
paramType := typ.In(numParams - 1).Elem()
|
||||
for _, opt := range opts {
|
||||
if typ := reflect.TypeOf(opt); !typ.AssignableTo(paramType) {
|
||||
return fmt.Errorf("transport option of type %s not assignable to %s", typ, paramType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var params []string
|
||||
if isVariadic && len(opts) > 0 {
|
||||
// If there are transport options, apply the tag.
|
||||
// Since options are variadic, they have to be the last argument of the constructor.
|
||||
params = make([]string, numParams)
|
||||
params[len(params)-1] = tag
|
||||
}
|
||||
|
||||
cfg.Transports = append(cfg.Transports, fx.Provide(
|
||||
fx.Annotate(
|
||||
constructor,
|
||||
fx.ParamTags(params...),
|
||||
fx.As(new(transport.Transport)),
|
||||
fx.ResultTags(`group:"transport"`),
|
||||
),
|
||||
))
|
||||
for _, opt := range opts {
|
||||
cfg.Transports = append(cfg.Transports, fx.Supply(
|
||||
fx.Annotate(
|
||||
opt,
|
||||
fx.ResultTags(tag),
|
||||
),
|
||||
))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Peerstore configures libp2p to use the given peerstore.
|
||||
func Peerstore(ps peerstore.Peerstore) Option {
|
||||
return func(cfg *Config) error {
|
||||
if cfg.Peerstore != nil {
|
||||
return fmt.Errorf("cannot specify multiple peerstore options")
|
||||
}
|
||||
|
||||
cfg.Peerstore = ps
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// PrivateNetwork configures libp2p to use the given private network protector.
|
||||
func PrivateNetwork(psk pnet.PSK) Option {
|
||||
return func(cfg *Config) error {
|
||||
if cfg.PSK != nil {
|
||||
return fmt.Errorf("cannot specify multiple private network options")
|
||||
}
|
||||
|
||||
cfg.PSK = psk
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// BandwidthReporter configures libp2p to use the given bandwidth reporter.
|
||||
func BandwidthReporter(rep metrics.Reporter) Option {
|
||||
return func(cfg *Config) error {
|
||||
if cfg.Reporter != nil {
|
||||
return fmt.Errorf("cannot specify multiple bandwidth reporter options")
|
||||
}
|
||||
|
||||
cfg.Reporter = rep
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Identity configures libp2p to use the given private key to identify itself.
|
||||
func Identity(sk crypto.PrivKey) Option {
|
||||
return func(cfg *Config) error {
|
||||
if cfg.PeerKey != nil {
|
||||
return fmt.Errorf("cannot specify multiple identities")
|
||||
}
|
||||
|
||||
cfg.PeerKey = sk
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ConnectionManager configures libp2p to use the given connection manager.
|
||||
//
|
||||
// The current "standard" connection manager lives in github.com/libp2p/go-libp2p-connmgr. See
|
||||
// https://pkg.go.dev/github.com/libp2p/go-libp2p-connmgr?utm_source=godoc#NewConnManager.
|
||||
func ConnectionManager(connman connmgr.ConnManager) Option {
|
||||
return func(cfg *Config) error {
|
||||
if cfg.ConnManager != nil {
|
||||
return fmt.Errorf("cannot specify multiple connection managers")
|
||||
}
|
||||
cfg.ConnManager = connman
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// AddrsFactory configures libp2p to use the given address factory.
|
||||
func AddrsFactory(factory config.AddrsFactory) Option {
|
||||
return func(cfg *Config) error {
|
||||
if cfg.AddrsFactory != nil {
|
||||
return fmt.Errorf("cannot specify multiple address factories")
|
||||
}
|
||||
cfg.AddrsFactory = factory
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// EnableRelay configures libp2p to enable the relay transport.
|
||||
// This option only configures libp2p to accept inbound connections from relays
|
||||
// and make outbound connections_through_ relays when requested by the remote peer.
|
||||
// This option supports both circuit v1 and v2 connections.
|
||||
// (default: enabled)
|
||||
func EnableRelay() Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.RelayCustom = true
|
||||
cfg.Relay = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DisableRelay configures libp2p to disable the relay transport.
|
||||
func DisableRelay() Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.RelayCustom = true
|
||||
cfg.Relay = false
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// EnableRelayService configures libp2p to run a circuit v2 relay,
|
||||
// if we detect that we're publicly reachable.
|
||||
func EnableRelayService(opts ...relayv2.Option) Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.EnableRelayService = true
|
||||
cfg.RelayServiceOpts = opts
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// EnableAutoRelay configures libp2p to enable the AutoRelay subsystem.
|
||||
//
|
||||
// Dependencies:
|
||||
// - Relay (enabled by default)
|
||||
// - Either:
|
||||
// 1. A list of static relays
|
||||
// 2. A PeerSource function that provides a chan of relays. See `autorelay.WithPeerSource`
|
||||
//
|
||||
// This subsystem performs automatic address rewriting to advertise relay addresses when it
|
||||
// detects that the node is publicly unreachable (e.g. behind a NAT).
|
||||
//
|
||||
// Deprecated: Use EnableAutoRelayWithStaticRelays or EnableAutoRelayWithPeerSource
|
||||
func EnableAutoRelay(opts ...autorelay.Option) Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.EnableAutoRelay = true
|
||||
cfg.AutoRelayOpts = opts
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// EnableAutoRelayWithStaticRelays configures libp2p to enable the AutoRelay subsystem using
|
||||
// the provided relays as relay candidates.
|
||||
// This subsystem performs automatic address rewriting to advertise relay addresses when it
|
||||
// detects that the node is publicly unreachable (e.g. behind a NAT).
|
||||
func EnableAutoRelayWithStaticRelays(static []peer.AddrInfo, opts ...autorelay.Option) Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.EnableAutoRelay = true
|
||||
cfg.AutoRelayOpts = append([]autorelay.Option{autorelay.WithStaticRelays(static)}, opts...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// EnableAutoRelayWithPeerSource configures libp2p to enable the AutoRelay
|
||||
// subsystem using the provided PeerSource callback to get more relay
|
||||
// candidates. This subsystem performs automatic address rewriting to advertise
|
||||
// relay addresses when it detects that the node is publicly unreachable (e.g.
|
||||
// behind a NAT).
|
||||
func EnableAutoRelayWithPeerSource(peerSource autorelay.PeerSource, opts ...autorelay.Option) Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.EnableAutoRelay = true
|
||||
cfg.AutoRelayOpts = append([]autorelay.Option{autorelay.WithPeerSource(peerSource)}, opts...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ForceReachabilityPublic overrides automatic reachability detection in the AutoNAT subsystem,
|
||||
// forcing the local node to believe it is reachable externally.
|
||||
func ForceReachabilityPublic() Option {
|
||||
return func(cfg *Config) error {
|
||||
public := network.Reachability(network.ReachabilityPublic)
|
||||
cfg.AutoNATConfig.ForceReachability = &public
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ForceReachabilityPrivate overrides automatic reachability detection in the AutoNAT subsystem,
|
||||
// forceing the local node to believe it is behind a NAT and not reachable externally.
|
||||
func ForceReachabilityPrivate() Option {
|
||||
return func(cfg *Config) error {
|
||||
private := network.Reachability(network.ReachabilityPrivate)
|
||||
cfg.AutoNATConfig.ForceReachability = &private
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// EnableNATService configures libp2p to provide a service to peers for determining
|
||||
// their reachability status. When enabled, the host will attempt to dial back
|
||||
// to peers, and then tell them if it was successful in making such connections.
|
||||
func EnableNATService() Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.AutoNATConfig.EnableService = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// AutoNATServiceRateLimit changes the default rate limiting configured in helping
|
||||
// other peers determine their reachability status. When set, the host will limit
|
||||
// the number of requests it responds to in each 60 second period to the set
|
||||
// numbers. A value of '0' disables throttling.
|
||||
func AutoNATServiceRateLimit(global, perPeer int, interval time.Duration) Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.AutoNATConfig.ThrottleGlobalLimit = global
|
||||
cfg.AutoNATConfig.ThrottlePeerLimit = perPeer
|
||||
cfg.AutoNATConfig.ThrottleInterval = interval
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ConnectionGater configures libp2p to use the given ConnectionGater
|
||||
// to actively reject inbound/outbound connections based on the lifecycle stage
|
||||
// of the connection.
|
||||
//
|
||||
// For more information, refer to go-libp2p/core.ConnectionGater.
|
||||
func ConnectionGater(cg connmgr.ConnectionGater) Option {
|
||||
return func(cfg *Config) error {
|
||||
if cfg.ConnectionGater != nil {
|
||||
return errors.New("cannot configure multiple connection gaters, or cannot configure both Filters and ConnectionGater")
|
||||
}
|
||||
cfg.ConnectionGater = cg
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ResourceManager configures libp2p to use the given ResourceManager.
|
||||
// When using the p2p/host/resource-manager implementation of the ResourceManager interface,
|
||||
// it is recommended to set limits for libp2p protocol by calling SetDefaultServiceLimits.
|
||||
func ResourceManager(rcmgr network.ResourceManager) Option {
|
||||
return func(cfg *Config) error {
|
||||
if cfg.ResourceManager != nil {
|
||||
return errors.New("cannot configure multiple resource managers")
|
||||
}
|
||||
cfg.ResourceManager = rcmgr
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NATPortMap configures libp2p to use the default NATManager. The default
|
||||
// NATManager will attempt to open a port in your network's firewall using UPnP.
|
||||
func NATPortMap() Option {
|
||||
return NATManager(bhost.NewNATManager)
|
||||
}
|
||||
|
||||
// NATManager will configure libp2p to use the requested NATManager. This
|
||||
// function should be passed a NATManager *constructor* that takes a libp2p Network.
|
||||
func NATManager(nm config.NATManagerC) Option {
|
||||
return func(cfg *Config) error {
|
||||
if cfg.NATManager != nil {
|
||||
return fmt.Errorf("cannot specify multiple NATManagers")
|
||||
}
|
||||
cfg.NATManager = nm
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Ping will configure libp2p to support the ping service; enable by default.
|
||||
func Ping(enable bool) Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.DisablePing = !enable
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Routing will configure libp2p to use routing.
|
||||
func Routing(rt config.RoutingC) Option {
|
||||
return func(cfg *Config) error {
|
||||
if cfg.Routing != nil {
|
||||
return fmt.Errorf("cannot specify multiple routing options")
|
||||
}
|
||||
cfg.Routing = rt
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NoListenAddrs will configure libp2p to not listen by default.
|
||||
//
|
||||
// This will both clear any configured listen addrs and prevent libp2p from
|
||||
// applying the default listen address option. It also disables relay, unless the
|
||||
// user explicitly specifies with an option, as the transport creates an implicit
|
||||
// listen address that would make the node dialable through any relay it was connected to.
|
||||
var NoListenAddrs = func(cfg *Config) error {
|
||||
cfg.ListenAddrs = []ma.Multiaddr{}
|
||||
if !cfg.RelayCustom {
|
||||
cfg.RelayCustom = true
|
||||
cfg.Relay = false
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NoTransports will configure libp2p to not enable any transports.
|
||||
//
|
||||
// This will both clear any configured transports (specified in prior libp2p
|
||||
// options) and prevent libp2p from applying the default transports.
|
||||
var NoTransports = func(cfg *Config) error {
|
||||
cfg.Transports = []fx.Option{}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ProtocolVersion sets the protocolVersion string required by the
|
||||
// libp2p Identify protocol.
|
||||
func ProtocolVersion(s string) Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.ProtocolVersion = s
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// UserAgent sets the libp2p user-agent sent along with the identify protocol
|
||||
func UserAgent(userAgent string) Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.UserAgent = userAgent
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MultiaddrResolver sets the libp2p dns resolver
|
||||
func MultiaddrResolver(rslv *madns.Resolver) Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.MultiaddrResolver = rslv
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Experimental
|
||||
// EnableHolePunching enables NAT traversal by enabling NATT'd peers to both initiate and respond to hole punching attempts
|
||||
// to create direct/NAT-traversed connections with other peers. (default: disabled)
|
||||
//
|
||||
// Dependencies:
|
||||
// - Relay (enabled by default)
|
||||
//
|
||||
// This subsystem performs two functions:
|
||||
//
|
||||
// 1. On receiving an inbound Relay connection, it attempts to create a direct connection with the remote peer
|
||||
// by initiating and co-ordinating a hole punch over the Relayed connection.
|
||||
// 2. If a peer sees a request to co-ordinate a hole punch on an outbound Relay connection,
|
||||
// it will participate in the hole-punch to create a direct connection with the remote peer.
|
||||
//
|
||||
// If the hole punch is successful, all new streams will thereafter be created on the hole-punched connection.
|
||||
// The Relayed connection will eventually be closed after a grace period.
|
||||
//
|
||||
// All existing indefinite long-lived streams on the Relayed connection will have to re-opened on the hole-punched connection by the user.
|
||||
// Users can make use of the `Connected`/`Disconnected` notifications emitted by the Network for this purpose.
|
||||
//
|
||||
// It is not mandatory but nice to also enable the `AutoRelay` option (See `EnableAutoRelay`)
|
||||
// so the peer can discover and connect to Relay servers if it discovers that it is NATT'd and has private reachability via AutoNAT.
|
||||
// This will then enable it to advertise Relay addresses which can be used to accept inbound Relay connections to then co-ordinate
|
||||
// a hole punch.
|
||||
//
|
||||
// If `EnableAutoRelay` is configured and the user is confident that the peer has private reachability/is NATT'd,
|
||||
// the `ForceReachabilityPrivate` option can be configured to short-circuit reachability discovery via AutoNAT
|
||||
// so the peer can immediately start connecting to Relay servers.
|
||||
//
|
||||
// If `EnableAutoRelay` is configured, the `StaticRelays` option can be used to configure a static set of Relay servers
|
||||
// for `AutoRelay` to connect to so that it does not need to discover Relay servers via Routing.
|
||||
func EnableHolePunching(opts ...holepunch.Option) Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.EnableHolePunching = true
|
||||
cfg.HolePunchingOptions = opts
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithDialTimeout(t time.Duration) Option {
|
||||
return func(cfg *Config) error {
|
||||
if t <= 0 {
|
||||
return errors.New("dial timeout needs to be non-negative")
|
||||
}
|
||||
cfg.DialTimeout = t
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DisableMetrics configures libp2p to disable prometheus metrics
|
||||
func DisableMetrics() Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.DisableMetrics = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// PrometheusRegisterer configures libp2p to use reg as the Registerer for all metrics subsystems
|
||||
func PrometheusRegisterer(reg prometheus.Registerer) Option {
|
||||
return func(cfg *Config) error {
|
||||
if cfg.DisableMetrics {
|
||||
return errors.New("cannot set registerer when metrics are disabled")
|
||||
}
|
||||
if cfg.PrometheusRegisterer != nil {
|
||||
return errors.New("registerer already set")
|
||||
}
|
||||
if reg == nil {
|
||||
return errors.New("registerer cannot be nil")
|
||||
}
|
||||
cfg.PrometheusRegisterer = reg
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DialRanker configures libp2p to use d as the dial ranker. To enable smart
|
||||
// dialing use `swarm.DefaultDialRanker`. use `swarm.NoDelayDialRanker` to
|
||||
// disable smart dialing.
|
||||
//
|
||||
// Deprecated: use SwarmOpts(swarm.WithDialRanker(d)) instead
|
||||
func DialRanker(d network.DialRanker) Option {
|
||||
return func(cfg *Config) error {
|
||||
if cfg.DialRanker != nil {
|
||||
return errors.New("dial ranker already configured")
|
||||
}
|
||||
cfg.DialRanker = d
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SwarmOpts configures libp2p to use swarm with opts
|
||||
func SwarmOpts(opts ...swarm.Option) Option {
|
||||
return func(cfg *Config) error {
|
||||
cfg.SwarmOpts = opts
|
||||
return nil
|
||||
}
|
||||
}
|
||||
36
vendor/github.com/libp2p/go-libp2p/options_filter.go
generated
vendored
Normal file
36
vendor/github.com/libp2p/go-libp2p/options_filter.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package libp2p
|
||||
|
||||
import (
|
||||
"github.com/libp2p/go-libp2p/core/connmgr"
|
||||
"github.com/libp2p/go-libp2p/core/control"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
// filtersConnectionGater is an adapter that turns multiaddr.Filter into a
|
||||
// connmgr.ConnectionGater.
|
||||
type filtersConnectionGater ma.Filters
|
||||
|
||||
var _ connmgr.ConnectionGater = (*filtersConnectionGater)(nil)
|
||||
|
||||
func (f *filtersConnectionGater) InterceptAddrDial(_ peer.ID, addr ma.Multiaddr) (allow bool) {
|
||||
return !(*ma.Filters)(f).AddrBlocked(addr)
|
||||
}
|
||||
|
||||
func (f *filtersConnectionGater) InterceptPeerDial(p peer.ID) (allow bool) {
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *filtersConnectionGater) InterceptAccept(connAddr network.ConnMultiaddrs) (allow bool) {
|
||||
return !(*ma.Filters)(f).AddrBlocked(connAddr.RemoteMultiaddr())
|
||||
}
|
||||
|
||||
func (f *filtersConnectionGater) InterceptSecured(_ network.Direction, _ peer.ID, connAddr network.ConnMultiaddrs) (allow bool) {
|
||||
return !(*ma.Filters)(f).AddrBlocked(connAddr.RemoteMultiaddr())
|
||||
}
|
||||
|
||||
func (f *filtersConnectionGater) InterceptUpgraded(_ network.Conn) (allow bool, reason control.DisconnectReason) {
|
||||
return true, 0
|
||||
}
|
||||
232
vendor/github.com/libp2p/go-libp2p/p2p/discovery/backoff/backoff.go
generated
vendored
Normal file
232
vendor/github.com/libp2p/go-libp2p/p2p/discovery/backoff/backoff.go
generated
vendored
Normal file
@@ -0,0 +1,232 @@
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
)
|
||||
|
||||
var log = logging.Logger("discovery-backoff")
|
||||
|
||||
type BackoffFactory func() BackoffStrategy
|
||||
|
||||
// BackoffStrategy describes how backoff will be implemented. BackoffStrategies are stateful.
|
||||
type BackoffStrategy interface {
|
||||
// Delay calculates how long the next backoff duration should be, given the prior calls to Delay
|
||||
Delay() time.Duration
|
||||
// Reset clears the internal state of the BackoffStrategy
|
||||
Reset()
|
||||
}
|
||||
|
||||
// Jitter implementations taken roughly from https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/
|
||||
|
||||
// Jitter must return a duration between min and max. Min must be lower than, or equal to, max.
|
||||
type Jitter func(duration, min, max time.Duration, rng *rand.Rand) time.Duration
|
||||
|
||||
// FullJitter returns a random number, uniformly chosen from the range [min, boundedDur].
|
||||
// boundedDur is the duration bounded between min and max.
|
||||
func FullJitter(duration, min, max time.Duration, rng *rand.Rand) time.Duration {
|
||||
if duration <= min {
|
||||
return min
|
||||
}
|
||||
|
||||
normalizedDur := boundedDuration(duration, min, max) - min
|
||||
|
||||
return boundedDuration(time.Duration(rng.Int63n(int64(normalizedDur)))+min, min, max)
|
||||
}
|
||||
|
||||
// NoJitter returns the duration bounded between min and max
|
||||
func NoJitter(duration, min, max time.Duration, rng *rand.Rand) time.Duration {
|
||||
return boundedDuration(duration, min, max)
|
||||
}
|
||||
|
||||
type randomizedBackoff struct {
|
||||
min time.Duration
|
||||
max time.Duration
|
||||
rng *rand.Rand
|
||||
}
|
||||
|
||||
func (b *randomizedBackoff) BoundedDelay(duration time.Duration) time.Duration {
|
||||
return boundedDuration(duration, b.min, b.max)
|
||||
}
|
||||
|
||||
func boundedDuration(d, min, max time.Duration) time.Duration {
|
||||
if d < min {
|
||||
return min
|
||||
}
|
||||
if d > max {
|
||||
return max
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
type attemptBackoff struct {
|
||||
attempt int
|
||||
jitter Jitter
|
||||
randomizedBackoff
|
||||
}
|
||||
|
||||
func (b *attemptBackoff) Reset() {
|
||||
b.attempt = 0
|
||||
}
|
||||
|
||||
// NewFixedBackoff creates a BackoffFactory with a constant backoff duration
|
||||
func NewFixedBackoff(delay time.Duration) BackoffFactory {
|
||||
return func() BackoffStrategy {
|
||||
return &fixedBackoff{delay: delay}
|
||||
}
|
||||
}
|
||||
|
||||
type fixedBackoff struct {
|
||||
delay time.Duration
|
||||
}
|
||||
|
||||
func (b *fixedBackoff) Delay() time.Duration {
|
||||
return b.delay
|
||||
}
|
||||
|
||||
func (b *fixedBackoff) Reset() {}
|
||||
|
||||
// NewPolynomialBackoff creates a BackoffFactory with backoff of the form c0*x^0, c1*x^1, ...cn*x^n where x is the attempt number
|
||||
// jitter is the function for adding randomness around the backoff
|
||||
// timeUnits are the units of time the polynomial is evaluated in
|
||||
// polyCoefs is the array of polynomial coefficients from [c0, c1, ... cn]
|
||||
func NewPolynomialBackoff(min, max time.Duration, jitter Jitter,
|
||||
timeUnits time.Duration, polyCoefs []float64, rngSrc rand.Source) BackoffFactory {
|
||||
rng := rand.New(&lockedSource{src: rngSrc})
|
||||
return func() BackoffStrategy {
|
||||
return &polynomialBackoff{
|
||||
attemptBackoff: attemptBackoff{
|
||||
randomizedBackoff: randomizedBackoff{
|
||||
min: min,
|
||||
max: max,
|
||||
rng: rng,
|
||||
},
|
||||
jitter: jitter,
|
||||
},
|
||||
timeUnits: timeUnits,
|
||||
poly: polyCoefs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type polynomialBackoff struct {
|
||||
attemptBackoff
|
||||
timeUnits time.Duration
|
||||
poly []float64
|
||||
}
|
||||
|
||||
func (b *polynomialBackoff) Delay() time.Duration {
|
||||
var polySum float64
|
||||
switch len(b.poly) {
|
||||
case 0:
|
||||
return 0
|
||||
case 1:
|
||||
polySum = b.poly[0]
|
||||
default:
|
||||
polySum = b.poly[0]
|
||||
exp := 1
|
||||
attempt := b.attempt
|
||||
b.attempt++
|
||||
|
||||
for _, c := range b.poly[1:] {
|
||||
exp *= attempt
|
||||
polySum += float64(exp) * c
|
||||
}
|
||||
}
|
||||
return b.jitter(time.Duration(float64(b.timeUnits)*polySum), b.min, b.max, b.rng)
|
||||
}
|
||||
|
||||
// NewExponentialBackoff creates a BackoffFactory with backoff of the form base^x + offset where x is the attempt number
|
||||
// jitter is the function for adding randomness around the backoff
|
||||
// timeUnits are the units of time the base^x is evaluated in
|
||||
func NewExponentialBackoff(min, max time.Duration, jitter Jitter,
|
||||
timeUnits time.Duration, base float64, offset time.Duration, rngSrc rand.Source) BackoffFactory {
|
||||
rng := rand.New(&lockedSource{src: rngSrc})
|
||||
return func() BackoffStrategy {
|
||||
return &exponentialBackoff{
|
||||
attemptBackoff: attemptBackoff{
|
||||
randomizedBackoff: randomizedBackoff{
|
||||
min: min,
|
||||
max: max,
|
||||
rng: rng,
|
||||
},
|
||||
jitter: jitter,
|
||||
},
|
||||
timeUnits: timeUnits,
|
||||
base: base,
|
||||
offset: offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type exponentialBackoff struct {
|
||||
attemptBackoff
|
||||
timeUnits time.Duration
|
||||
base float64
|
||||
offset time.Duration
|
||||
}
|
||||
|
||||
func (b *exponentialBackoff) Delay() time.Duration {
|
||||
attempt := b.attempt
|
||||
b.attempt++
|
||||
return b.jitter(
|
||||
time.Duration(math.Pow(b.base, float64(attempt))*float64(b.timeUnits))+b.offset, b.min, b.max, b.rng)
|
||||
}
|
||||
|
||||
// NewExponentialDecorrelatedJitter creates a BackoffFactory with backoff of the roughly of the form base^x where x is the attempt number.
|
||||
// Delays start at the minimum duration and after each attempt delay = rand(min, delay * base), bounded by the max
|
||||
// See https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ for more information
|
||||
func NewExponentialDecorrelatedJitter(min, max time.Duration, base float64, rngSrc rand.Source) BackoffFactory {
|
||||
rng := rand.New(&lockedSource{src: rngSrc})
|
||||
return func() BackoffStrategy {
|
||||
return &exponentialDecorrelatedJitter{
|
||||
randomizedBackoff: randomizedBackoff{
|
||||
min: min,
|
||||
max: max,
|
||||
rng: rng,
|
||||
},
|
||||
base: base,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type exponentialDecorrelatedJitter struct {
|
||||
randomizedBackoff
|
||||
base float64
|
||||
lastDelay time.Duration
|
||||
}
|
||||
|
||||
func (b *exponentialDecorrelatedJitter) Delay() time.Duration {
|
||||
if b.lastDelay < b.min {
|
||||
b.lastDelay = b.min
|
||||
return b.lastDelay
|
||||
}
|
||||
|
||||
nextMax := int64(float64(b.lastDelay) * b.base)
|
||||
b.lastDelay = boundedDuration(time.Duration(b.rng.Int63n(nextMax-int64(b.min)))+b.min, b.min, b.max)
|
||||
return b.lastDelay
|
||||
}
|
||||
|
||||
func (b *exponentialDecorrelatedJitter) Reset() { b.lastDelay = 0 }
|
||||
|
||||
type lockedSource struct {
|
||||
lk sync.Mutex
|
||||
src rand.Source
|
||||
}
|
||||
|
||||
func (r *lockedSource) Int63() (n int64) {
|
||||
r.lk.Lock()
|
||||
n = r.src.Int63()
|
||||
r.lk.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
func (r *lockedSource) Seed(seed int64) {
|
||||
r.lk.Lock()
|
||||
r.src.Seed(seed)
|
||||
r.lk.Unlock()
|
||||
}
|
||||
337
vendor/github.com/libp2p/go-libp2p/p2p/discovery/backoff/backoffcache.go
generated
vendored
Normal file
337
vendor/github.com/libp2p/go-libp2p/p2p/discovery/backoff/backoffcache.go
generated
vendored
Normal file
@@ -0,0 +1,337 @@
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/discovery"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
// BackoffDiscovery is an implementation of discovery that caches peer data and attenuates repeated queries
|
||||
type BackoffDiscovery struct {
|
||||
disc discovery.Discovery
|
||||
stratFactory BackoffFactory
|
||||
peerCache map[string]*backoffCache
|
||||
peerCacheMux sync.RWMutex
|
||||
|
||||
parallelBufSz int
|
||||
returnedBufSz int
|
||||
|
||||
clock clock
|
||||
}
|
||||
|
||||
type BackoffDiscoveryOption func(*BackoffDiscovery) error
|
||||
|
||||
func NewBackoffDiscovery(disc discovery.Discovery, stratFactory BackoffFactory, opts ...BackoffDiscoveryOption) (discovery.Discovery, error) {
|
||||
b := &BackoffDiscovery{
|
||||
disc: disc,
|
||||
stratFactory: stratFactory,
|
||||
peerCache: make(map[string]*backoffCache),
|
||||
|
||||
parallelBufSz: 32,
|
||||
returnedBufSz: 32,
|
||||
|
||||
clock: realClock{},
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
if err := opt(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// WithBackoffDiscoverySimultaneousQueryBufferSize sets the buffer size for the channels between the main FindPeers query
|
||||
// for a given namespace and all simultaneous FindPeers queries for the namespace
|
||||
func WithBackoffDiscoverySimultaneousQueryBufferSize(size int) BackoffDiscoveryOption {
|
||||
return func(b *BackoffDiscovery) error {
|
||||
if size < 0 {
|
||||
return fmt.Errorf("cannot set size to be smaller than 0")
|
||||
}
|
||||
b.parallelBufSz = size
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithBackoffDiscoveryReturnedChannelSize sets the size of the buffer to be used during a FindPeer query.
|
||||
// Note: This does not apply if the query occurs during the backoff time
|
||||
func WithBackoffDiscoveryReturnedChannelSize(size int) BackoffDiscoveryOption {
|
||||
return func(b *BackoffDiscovery) error {
|
||||
if size < 0 {
|
||||
return fmt.Errorf("cannot set size to be smaller than 0")
|
||||
}
|
||||
b.returnedBufSz = size
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type clock interface {
|
||||
Now() time.Time
|
||||
}
|
||||
|
||||
type realClock struct{}
|
||||
|
||||
func (c realClock) Now() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
// withClock lets you override the default time.Now() call. Useful for tests.
|
||||
func withClock(c clock) BackoffDiscoveryOption {
|
||||
return func(b *BackoffDiscovery) error {
|
||||
b.clock = c
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type backoffCache struct {
|
||||
// strat is assigned on creation and not written to
|
||||
strat BackoffStrategy
|
||||
|
||||
mux sync.Mutex // guards writes to all following fields
|
||||
nextDiscover time.Time
|
||||
prevPeers map[peer.ID]peer.AddrInfo
|
||||
peers map[peer.ID]peer.AddrInfo
|
||||
sendingChs map[chan peer.AddrInfo]int
|
||||
ongoing bool
|
||||
|
||||
clock clock
|
||||
}
|
||||
|
||||
func (d *BackoffDiscovery) Advertise(ctx context.Context, ns string, opts ...discovery.Option) (time.Duration, error) {
|
||||
return d.disc.Advertise(ctx, ns, opts...)
|
||||
}
|
||||
|
||||
func (d *BackoffDiscovery) FindPeers(ctx context.Context, ns string, opts ...discovery.Option) (<-chan peer.AddrInfo, error) {
|
||||
// Get options
|
||||
var options discovery.Options
|
||||
err := options.Apply(opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get cached peers
|
||||
d.peerCacheMux.RLock()
|
||||
c, ok := d.peerCache[ns]
|
||||
d.peerCacheMux.RUnlock()
|
||||
|
||||
/*
|
||||
Overall plan:
|
||||
If it's time to look for peers, look for peers, then return them
|
||||
If it's not time then return cache
|
||||
If it's time to look for peers, but we have already started looking. Get up to speed with ongoing request
|
||||
*/
|
||||
|
||||
// Setup cache if we don't have one yet
|
||||
if !ok {
|
||||
pc := &backoffCache{
|
||||
nextDiscover: time.Time{},
|
||||
prevPeers: make(map[peer.ID]peer.AddrInfo),
|
||||
peers: make(map[peer.ID]peer.AddrInfo),
|
||||
sendingChs: make(map[chan peer.AddrInfo]int),
|
||||
strat: d.stratFactory(),
|
||||
clock: d.clock,
|
||||
}
|
||||
|
||||
d.peerCacheMux.Lock()
|
||||
c, ok = d.peerCache[ns]
|
||||
|
||||
if !ok {
|
||||
d.peerCache[ns] = pc
|
||||
c = pc
|
||||
}
|
||||
|
||||
d.peerCacheMux.Unlock()
|
||||
}
|
||||
|
||||
c.mux.Lock()
|
||||
defer c.mux.Unlock()
|
||||
|
||||
timeExpired := d.clock.Now().After(c.nextDiscover)
|
||||
|
||||
// If it's not yet time to search again and no searches are in progress then return cached peers
|
||||
if !(timeExpired || c.ongoing) {
|
||||
chLen := options.Limit
|
||||
|
||||
if chLen == 0 {
|
||||
chLen = len(c.prevPeers)
|
||||
} else if chLen > len(c.prevPeers) {
|
||||
chLen = len(c.prevPeers)
|
||||
}
|
||||
pch := make(chan peer.AddrInfo, chLen)
|
||||
for _, ai := range c.prevPeers {
|
||||
select {
|
||||
case pch <- ai:
|
||||
default:
|
||||
// skip if we have asked for a lower limit than the number of peers known
|
||||
}
|
||||
}
|
||||
close(pch)
|
||||
return pch, nil
|
||||
}
|
||||
|
||||
// If a request is not already in progress setup a dispatcher channel for dispatching incoming peers
|
||||
if !c.ongoing {
|
||||
pch, err := d.disc.FindPeers(ctx, ns, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.ongoing = true
|
||||
go findPeerDispatcher(ctx, c, pch)
|
||||
}
|
||||
|
||||
// Setup receiver channel for receiving peers from ongoing requests
|
||||
evtCh := make(chan peer.AddrInfo, d.parallelBufSz)
|
||||
pch := make(chan peer.AddrInfo, d.returnedBufSz)
|
||||
rcvPeers := make([]peer.AddrInfo, 0, 32)
|
||||
for _, ai := range c.peers {
|
||||
rcvPeers = append(rcvPeers, ai)
|
||||
}
|
||||
c.sendingChs[evtCh] = options.Limit
|
||||
|
||||
go findPeerReceiver(ctx, pch, evtCh, rcvPeers)
|
||||
|
||||
return pch, nil
|
||||
}
|
||||
|
||||
func findPeerDispatcher(ctx context.Context, c *backoffCache, pch <-chan peer.AddrInfo) {
|
||||
defer func() {
|
||||
c.mux.Lock()
|
||||
|
||||
// If the peer addresses have changed reset the backoff
|
||||
if checkUpdates(c.prevPeers, c.peers) {
|
||||
c.strat.Reset()
|
||||
c.prevPeers = c.peers
|
||||
}
|
||||
c.nextDiscover = c.clock.Now().Add(c.strat.Delay())
|
||||
|
||||
c.ongoing = false
|
||||
c.peers = make(map[peer.ID]peer.AddrInfo)
|
||||
|
||||
for ch := range c.sendingChs {
|
||||
close(ch)
|
||||
}
|
||||
c.sendingChs = make(map[chan peer.AddrInfo]int)
|
||||
c.mux.Unlock()
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case ai, ok := <-pch:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
c.mux.Lock()
|
||||
|
||||
// If we receive the same peer multiple times return the address union
|
||||
var sendAi peer.AddrInfo
|
||||
if prevAi, ok := c.peers[ai.ID]; ok {
|
||||
if combinedAi := mergeAddrInfos(prevAi, ai); combinedAi != nil {
|
||||
sendAi = *combinedAi
|
||||
} else {
|
||||
c.mux.Unlock()
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
sendAi = ai
|
||||
}
|
||||
|
||||
c.peers[ai.ID] = sendAi
|
||||
|
||||
for ch, rem := range c.sendingChs {
|
||||
if rem > 0 {
|
||||
ch <- sendAi
|
||||
c.sendingChs[ch] = rem - 1
|
||||
}
|
||||
}
|
||||
|
||||
c.mux.Unlock()
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findPeerReceiver(ctx context.Context, pch, evtCh chan peer.AddrInfo, rcvPeers []peer.AddrInfo) {
|
||||
defer close(pch)
|
||||
|
||||
for {
|
||||
select {
|
||||
case ai, ok := <-evtCh:
|
||||
if ok {
|
||||
rcvPeers = append(rcvPeers, ai)
|
||||
|
||||
sentAll := true
|
||||
sendPeers:
|
||||
for i, p := range rcvPeers {
|
||||
select {
|
||||
case pch <- p:
|
||||
default:
|
||||
rcvPeers = rcvPeers[i:]
|
||||
sentAll = false
|
||||
break sendPeers
|
||||
}
|
||||
}
|
||||
if sentAll {
|
||||
rcvPeers = []peer.AddrInfo{}
|
||||
}
|
||||
} else {
|
||||
for _, p := range rcvPeers {
|
||||
select {
|
||||
case pch <- p:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mergeAddrInfos(prevAi, newAi peer.AddrInfo) *peer.AddrInfo {
|
||||
seen := make(map[string]struct{}, len(prevAi.Addrs))
|
||||
combinedAddrs := make([]ma.Multiaddr, 0, len(prevAi.Addrs))
|
||||
addAddrs := func(addrs []ma.Multiaddr) {
|
||||
for _, addr := range addrs {
|
||||
if _, ok := seen[addr.String()]; ok {
|
||||
continue
|
||||
}
|
||||
seen[addr.String()] = struct{}{}
|
||||
combinedAddrs = append(combinedAddrs, addr)
|
||||
}
|
||||
}
|
||||
addAddrs(prevAi.Addrs)
|
||||
addAddrs(newAi.Addrs)
|
||||
|
||||
if len(combinedAddrs) > len(prevAi.Addrs) {
|
||||
combinedAi := &peer.AddrInfo{ID: prevAi.ID, Addrs: combinedAddrs}
|
||||
return combinedAi
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkUpdates(orig, update map[peer.ID]peer.AddrInfo) bool {
|
||||
if len(orig) != len(update) {
|
||||
return true
|
||||
}
|
||||
for p, ai := range update {
|
||||
if prevAi, ok := orig[p]; ok {
|
||||
if combinedAi := mergeAddrInfos(prevAi, ai); combinedAi != nil {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
94
vendor/github.com/libp2p/go-libp2p/p2p/discovery/backoff/backoffconnector.go
generated
vendored
Normal file
94
vendor/github.com/libp2p/go-libp2p/p2p/discovery/backoff/backoffconnector.go
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru/v2"
|
||||
)
|
||||
|
||||
// BackoffConnector is a utility to connect to peers, but only if we have not recently tried connecting to them already
|
||||
type BackoffConnector struct {
|
||||
cache *lru.TwoQueueCache[peer.ID, *connCacheData]
|
||||
host host.Host
|
||||
connTryDur time.Duration
|
||||
backoff BackoffFactory
|
||||
mux sync.Mutex
|
||||
}
|
||||
|
||||
// NewBackoffConnector creates a utility to connect to peers, but only if we have not recently tried connecting to them already
|
||||
// cacheSize is the size of a TwoQueueCache
|
||||
// connectionTryDuration is how long we attempt to connect to a peer before giving up
|
||||
// backoff describes the strategy used to decide how long to backoff after previously attempting to connect to a peer
|
||||
func NewBackoffConnector(h host.Host, cacheSize int, connectionTryDuration time.Duration, backoff BackoffFactory) (*BackoffConnector, error) {
|
||||
cache, err := lru.New2Q[peer.ID, *connCacheData](cacheSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &BackoffConnector{
|
||||
cache: cache,
|
||||
host: h,
|
||||
connTryDur: connectionTryDuration,
|
||||
backoff: backoff,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type connCacheData struct {
|
||||
nextTry time.Time
|
||||
strat BackoffStrategy
|
||||
}
|
||||
|
||||
// Connect attempts to connect to the peers passed in by peerCh. Will not connect to peers if they are within the backoff period.
|
||||
// As Connect will attempt to dial peers as soon as it learns about them, the caller should try to keep the number,
|
||||
// and rate, of inbound peers manageable.
|
||||
func (c *BackoffConnector) Connect(ctx context.Context, peerCh <-chan peer.AddrInfo) {
|
||||
for {
|
||||
select {
|
||||
case pi, ok := <-peerCh:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if pi.ID == c.host.ID() || pi.ID == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
c.mux.Lock()
|
||||
var cachedPeer *connCacheData
|
||||
if tv, ok := c.cache.Get(pi.ID); ok {
|
||||
now := time.Now()
|
||||
if now.Before(tv.nextTry) {
|
||||
c.mux.Unlock()
|
||||
continue
|
||||
}
|
||||
|
||||
tv.nextTry = now.Add(tv.strat.Delay())
|
||||
} else {
|
||||
cachedPeer = &connCacheData{strat: c.backoff()}
|
||||
cachedPeer.nextTry = time.Now().Add(cachedPeer.strat.Delay())
|
||||
c.cache.Add(pi.ID, cachedPeer)
|
||||
}
|
||||
c.mux.Unlock()
|
||||
|
||||
go func(pi peer.AddrInfo) {
|
||||
ctx, cancel := context.WithTimeout(ctx, c.connTryDur)
|
||||
defer cancel()
|
||||
|
||||
err := c.host.Connect(ctx, pi)
|
||||
if err != nil {
|
||||
log.Debugf("Error connecting to pubsub peer %s: %s", pi.ID, err.Error())
|
||||
return
|
||||
}
|
||||
}(pi)
|
||||
|
||||
case <-ctx.Done():
|
||||
log.Infof("discovery: backoff connector context error %v", ctx.Err())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
202
vendor/github.com/libp2p/go-libp2p/p2p/discovery/mdns/mdns.go
generated
vendored
Normal file
202
vendor/github.com/libp2p/go-libp2p/p2p/discovery/mdns/mdns.go
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
package mdns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
"github.com/libp2p/zeroconf/v2"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
)
|
||||
|
||||
const (
|
||||
ServiceName = "_p2p._udp"
|
||||
mdnsDomain = "local"
|
||||
dnsaddrPrefix = "dnsaddr="
|
||||
)
|
||||
|
||||
var log = logging.Logger("mdns")
|
||||
|
||||
type Service interface {
|
||||
Start() error
|
||||
io.Closer
|
||||
}
|
||||
|
||||
type Notifee interface {
|
||||
HandlePeerFound(peer.AddrInfo)
|
||||
}
|
||||
|
||||
type mdnsService struct {
|
||||
host host.Host
|
||||
serviceName string
|
||||
peerName string
|
||||
|
||||
// The context is canceled when Close() is called.
|
||||
ctx context.Context
|
||||
ctxCancel context.CancelFunc
|
||||
|
||||
resolverWG sync.WaitGroup
|
||||
server *zeroconf.Server
|
||||
|
||||
notifee Notifee
|
||||
}
|
||||
|
||||
func NewMdnsService(host host.Host, serviceName string, notifee Notifee) *mdnsService {
|
||||
if serviceName == "" {
|
||||
serviceName = ServiceName
|
||||
}
|
||||
s := &mdnsService{
|
||||
host: host,
|
||||
serviceName: serviceName,
|
||||
peerName: randomString(32 + rand.Intn(32)), // generate a random string between 32 and 63 characters long
|
||||
notifee: notifee,
|
||||
}
|
||||
s.ctx, s.ctxCancel = context.WithCancel(context.Background())
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *mdnsService) Start() error {
|
||||
if err := s.startServer(); err != nil {
|
||||
return err
|
||||
}
|
||||
s.startResolver(s.ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *mdnsService) Close() error {
|
||||
s.ctxCancel()
|
||||
if s.server != nil {
|
||||
s.server.Shutdown()
|
||||
}
|
||||
s.resolverWG.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// We don't really care about the IP addresses, but the spec (and various routers / firewalls) require us
|
||||
// to send A and AAAA records.
|
||||
func (s *mdnsService) getIPs(addrs []ma.Multiaddr) ([]string, error) {
|
||||
var ip4, ip6 string
|
||||
for _, addr := range addrs {
|
||||
first, _ := ma.SplitFirst(addr)
|
||||
if first == nil {
|
||||
continue
|
||||
}
|
||||
if ip4 == "" && first.Protocol().Code == ma.P_IP4 {
|
||||
ip4 = first.Value()
|
||||
} else if ip6 == "" && first.Protocol().Code == ma.P_IP6 {
|
||||
ip6 = first.Value()
|
||||
}
|
||||
}
|
||||
ips := make([]string, 0, 2)
|
||||
if ip4 != "" {
|
||||
ips = append(ips, ip4)
|
||||
}
|
||||
if ip6 != "" {
|
||||
ips = append(ips, ip6)
|
||||
}
|
||||
if len(ips) == 0 {
|
||||
return nil, errors.New("didn't find any IP addresses")
|
||||
}
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
func (s *mdnsService) startServer() error {
|
||||
interfaceAddrs, err := s.host.Network().InterfaceListenAddresses()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addrs, err := peer.AddrInfoToP2pAddrs(&peer.AddrInfo{
|
||||
ID: s.host.ID(),
|
||||
Addrs: interfaceAddrs,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var txts []string
|
||||
for _, addr := range addrs {
|
||||
if manet.IsThinWaist(addr) { // don't announce circuit addresses
|
||||
txts = append(txts, dnsaddrPrefix+addr.String())
|
||||
}
|
||||
}
|
||||
|
||||
ips, err := s.getIPs(addrs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
server, err := zeroconf.RegisterProxy(
|
||||
s.peerName,
|
||||
s.serviceName,
|
||||
mdnsDomain,
|
||||
4001, // we have to pass in a port number here, but libp2p only uses the TXT records
|
||||
s.peerName,
|
||||
ips,
|
||||
txts,
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.server = server
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *mdnsService) startResolver(ctx context.Context) {
|
||||
s.resolverWG.Add(2)
|
||||
entryChan := make(chan *zeroconf.ServiceEntry, 1000)
|
||||
go func() {
|
||||
defer s.resolverWG.Done()
|
||||
for entry := range entryChan {
|
||||
// We only care about the TXT records.
|
||||
// Ignore A, AAAA and PTR.
|
||||
addrs := make([]ma.Multiaddr, 0, len(entry.Text)) // assume that all TXT records are dnsaddrs
|
||||
for _, s := range entry.Text {
|
||||
if !strings.HasPrefix(s, dnsaddrPrefix) {
|
||||
log.Debug("missing dnsaddr prefix")
|
||||
continue
|
||||
}
|
||||
addr, err := ma.NewMultiaddr(s[len(dnsaddrPrefix):])
|
||||
if err != nil {
|
||||
log.Debugf("failed to parse multiaddr: %s", err)
|
||||
continue
|
||||
}
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
infos, err := peer.AddrInfosFromP2pAddrs(addrs...)
|
||||
if err != nil {
|
||||
log.Debugf("failed to get peer info: %s", err)
|
||||
continue
|
||||
}
|
||||
for _, info := range infos {
|
||||
if info.ID == s.host.ID() {
|
||||
continue
|
||||
}
|
||||
go s.notifee.HandlePeerFound(info)
|
||||
}
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
defer s.resolverWG.Done()
|
||||
if err := zeroconf.Browse(ctx, s.serviceName, mdnsDomain, entryChan); err != nil {
|
||||
log.Debugf("zeroconf browsing failed: %s", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func randomString(l int) string {
|
||||
const alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
s := make([]byte, 0, l)
|
||||
for i := 0; i < l; i++ {
|
||||
s = append(s, alphabet[rand.Intn(len(alphabet))])
|
||||
}
|
||||
return string(s)
|
||||
}
|
||||
450
vendor/github.com/libp2p/go-libp2p/p2p/host/autonat/autonat.go
generated
vendored
Normal file
450
vendor/github.com/libp2p/go-libp2p/p2p/host/autonat/autonat.go
generated
vendored
Normal file
@@ -0,0 +1,450 @@
|
||||
package autonat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/rand"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/event"
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
|
||||
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
)
|
||||
|
||||
var log = logging.Logger("autonat")
|
||||
|
||||
const maxConfidence = 3
|
||||
|
||||
// AmbientAutoNAT is the implementation of ambient NAT autodiscovery
|
||||
type AmbientAutoNAT struct {
|
||||
host host.Host
|
||||
|
||||
*config
|
||||
|
||||
ctx context.Context
|
||||
ctxCancel context.CancelFunc // is closed when Close is called
|
||||
backgroundRunning chan struct{} // is closed when the background go routine exits
|
||||
|
||||
inboundConn chan network.Conn
|
||||
dialResponses chan error
|
||||
// status is an autoNATResult reflecting current status.
|
||||
status atomic.Pointer[network.Reachability]
|
||||
// Reflects the confidence on of the NATStatus being private, as a single
|
||||
// dialback may fail for reasons unrelated to NAT.
|
||||
// If it is <3, then multiple autoNAT peers may be contacted for dialback
|
||||
// If only a single autoNAT peer is known, then the confidence increases
|
||||
// for each failure until it reaches 3.
|
||||
confidence int
|
||||
lastInbound time.Time
|
||||
lastProbeTry time.Time
|
||||
lastProbe time.Time
|
||||
recentProbes map[peer.ID]time.Time
|
||||
|
||||
service *autoNATService
|
||||
|
||||
emitReachabilityChanged event.Emitter
|
||||
subscriber event.Subscription
|
||||
}
|
||||
|
||||
// StaticAutoNAT is a simple AutoNAT implementation when a single NAT status is desired.
|
||||
type StaticAutoNAT struct {
|
||||
host host.Host
|
||||
reachability network.Reachability
|
||||
service *autoNATService
|
||||
}
|
||||
|
||||
// New creates a new NAT autodiscovery system attached to a host
|
||||
func New(h host.Host, options ...Option) (AutoNAT, error) {
|
||||
var err error
|
||||
conf := new(config)
|
||||
conf.host = h
|
||||
conf.dialPolicy.host = h
|
||||
|
||||
if err = defaults(conf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if conf.addressFunc == nil {
|
||||
conf.addressFunc = h.Addrs
|
||||
}
|
||||
|
||||
for _, o := range options {
|
||||
if err = o(conf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
emitReachabilityChanged, _ := h.EventBus().Emitter(new(event.EvtLocalReachabilityChanged), eventbus.Stateful)
|
||||
|
||||
var service *autoNATService
|
||||
if (!conf.forceReachability || conf.reachability == network.ReachabilityPublic) && conf.dialer != nil {
|
||||
service, err = newAutoNATService(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
service.Enable()
|
||||
}
|
||||
|
||||
if conf.forceReachability {
|
||||
emitReachabilityChanged.Emit(event.EvtLocalReachabilityChanged{Reachability: conf.reachability})
|
||||
|
||||
return &StaticAutoNAT{
|
||||
host: h,
|
||||
reachability: conf.reachability,
|
||||
service: service,
|
||||
}, nil
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
as := &AmbientAutoNAT{
|
||||
ctx: ctx,
|
||||
ctxCancel: cancel,
|
||||
backgroundRunning: make(chan struct{}),
|
||||
host: h,
|
||||
config: conf,
|
||||
inboundConn: make(chan network.Conn, 5),
|
||||
dialResponses: make(chan error, 1),
|
||||
|
||||
emitReachabilityChanged: emitReachabilityChanged,
|
||||
service: service,
|
||||
recentProbes: make(map[peer.ID]time.Time),
|
||||
}
|
||||
reachability := network.ReachabilityUnknown
|
||||
as.status.Store(&reachability)
|
||||
|
||||
subscriber, err := as.host.EventBus().Subscribe(
|
||||
[]any{new(event.EvtLocalAddressesUpdated), new(event.EvtPeerIdentificationCompleted)},
|
||||
eventbus.Name("autonat"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
as.subscriber = subscriber
|
||||
|
||||
h.Network().Notify(as)
|
||||
go as.background()
|
||||
|
||||
return as, nil
|
||||
}
|
||||
|
||||
// Status returns the AutoNAT observed reachability status.
|
||||
func (as *AmbientAutoNAT) Status() network.Reachability {
|
||||
s := as.status.Load()
|
||||
return *s
|
||||
}
|
||||
|
||||
func (as *AmbientAutoNAT) emitStatus() {
|
||||
status := *as.status.Load()
|
||||
as.emitReachabilityChanged.Emit(event.EvtLocalReachabilityChanged{Reachability: status})
|
||||
if as.metricsTracer != nil {
|
||||
as.metricsTracer.ReachabilityStatus(status)
|
||||
}
|
||||
}
|
||||
|
||||
func ipInList(candidate ma.Multiaddr, list []ma.Multiaddr) bool {
|
||||
candidateIP, _ := manet.ToIP(candidate)
|
||||
for _, i := range list {
|
||||
if ip, err := manet.ToIP(i); err == nil && ip.Equal(candidateIP) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (as *AmbientAutoNAT) background() {
|
||||
defer close(as.backgroundRunning)
|
||||
// wait a bit for the node to come online and establish some connections
|
||||
// before starting autodetection
|
||||
delay := as.config.bootDelay
|
||||
|
||||
subChan := as.subscriber.Out()
|
||||
defer as.subscriber.Close()
|
||||
defer as.emitReachabilityChanged.Close()
|
||||
|
||||
timer := time.NewTimer(delay)
|
||||
defer timer.Stop()
|
||||
timerRunning := true
|
||||
retryProbe := false
|
||||
for {
|
||||
select {
|
||||
// new inbound connection.
|
||||
case conn := <-as.inboundConn:
|
||||
localAddrs := as.host.Addrs()
|
||||
if manet.IsPublicAddr(conn.RemoteMultiaddr()) &&
|
||||
!ipInList(conn.RemoteMultiaddr(), localAddrs) {
|
||||
as.lastInbound = time.Now()
|
||||
}
|
||||
|
||||
case e := <-subChan:
|
||||
switch e := e.(type) {
|
||||
case event.EvtLocalAddressesUpdated:
|
||||
// On local address update, reduce confidence from maximum so that we schedule
|
||||
// the next probe sooner
|
||||
if as.confidence == maxConfidence {
|
||||
as.confidence--
|
||||
}
|
||||
case event.EvtPeerIdentificationCompleted:
|
||||
if s, err := as.host.Peerstore().SupportsProtocols(e.Peer, AutoNATProto); err == nil && len(s) > 0 {
|
||||
currentStatus := *as.status.Load()
|
||||
if currentStatus == network.ReachabilityUnknown {
|
||||
as.tryProbe(e.Peer)
|
||||
}
|
||||
}
|
||||
default:
|
||||
log.Errorf("unknown event type: %T", e)
|
||||
}
|
||||
|
||||
// probe finished.
|
||||
case err, ok := <-as.dialResponses:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if IsDialRefused(err) {
|
||||
retryProbe = true
|
||||
} else {
|
||||
as.handleDialResponse(err)
|
||||
}
|
||||
case <-timer.C:
|
||||
peer := as.getPeerToProbe()
|
||||
as.tryProbe(peer)
|
||||
timerRunning = false
|
||||
retryProbe = false
|
||||
case <-as.ctx.Done():
|
||||
return
|
||||
}
|
||||
|
||||
// Drain the timer channel if it hasn't fired in preparation for Resetting it.
|
||||
if timerRunning && !timer.Stop() {
|
||||
<-timer.C
|
||||
}
|
||||
timer.Reset(as.scheduleProbe(retryProbe))
|
||||
timerRunning = true
|
||||
}
|
||||
}
|
||||
|
||||
func (as *AmbientAutoNAT) cleanupRecentProbes() {
|
||||
fixedNow := time.Now()
|
||||
for k, v := range as.recentProbes {
|
||||
if fixedNow.Sub(v) > as.throttlePeerPeriod {
|
||||
delete(as.recentProbes, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// scheduleProbe calculates when the next probe should be scheduled for.
|
||||
func (as *AmbientAutoNAT) scheduleProbe(retryProbe bool) time.Duration {
|
||||
// Our baseline is a probe every 'AutoNATRefreshInterval'
|
||||
// This is modulated by:
|
||||
// * if we are in an unknown state, have low confidence, or we want to retry because a probe was refused that
|
||||
// should drop to 'AutoNATRetryInterval'
|
||||
// * recent inbound connections (implying continued connectivity) should decrease the retry when public
|
||||
// * recent inbound connections when not public mean we should try more actively to see if we're public.
|
||||
fixedNow := time.Now()
|
||||
currentStatus := *as.status.Load()
|
||||
|
||||
nextProbe := fixedNow
|
||||
// Don't look for peers in the peer store more than once per second.
|
||||
if !as.lastProbeTry.IsZero() {
|
||||
backoff := as.lastProbeTry.Add(time.Second)
|
||||
if backoff.After(nextProbe) {
|
||||
nextProbe = backoff
|
||||
}
|
||||
}
|
||||
if !as.lastProbe.IsZero() {
|
||||
untilNext := as.config.refreshInterval
|
||||
if retryProbe {
|
||||
untilNext = as.config.retryInterval
|
||||
} else if currentStatus == network.ReachabilityUnknown {
|
||||
untilNext = as.config.retryInterval
|
||||
} else if as.confidence < maxConfidence {
|
||||
untilNext = as.config.retryInterval
|
||||
} else if currentStatus == network.ReachabilityPublic && as.lastInbound.After(as.lastProbe) {
|
||||
untilNext *= 2
|
||||
} else if currentStatus != network.ReachabilityPublic && as.lastInbound.After(as.lastProbe) {
|
||||
untilNext /= 5
|
||||
}
|
||||
|
||||
if as.lastProbe.Add(untilNext).After(nextProbe) {
|
||||
nextProbe = as.lastProbe.Add(untilNext)
|
||||
}
|
||||
}
|
||||
if as.metricsTracer != nil {
|
||||
as.metricsTracer.NextProbeTime(nextProbe)
|
||||
}
|
||||
return nextProbe.Sub(fixedNow)
|
||||
}
|
||||
|
||||
// handleDialResponse updates the current status based on dial response.
|
||||
func (as *AmbientAutoNAT) handleDialResponse(dialErr error) {
|
||||
var observation network.Reachability
|
||||
switch {
|
||||
case dialErr == nil:
|
||||
observation = network.ReachabilityPublic
|
||||
case IsDialError(dialErr):
|
||||
observation = network.ReachabilityPrivate
|
||||
default:
|
||||
observation = network.ReachabilityUnknown
|
||||
}
|
||||
|
||||
as.recordObservation(observation)
|
||||
}
|
||||
|
||||
// recordObservation updates NAT status and confidence
|
||||
func (as *AmbientAutoNAT) recordObservation(observation network.Reachability) {
|
||||
|
||||
currentStatus := *as.status.Load()
|
||||
|
||||
if observation == network.ReachabilityPublic {
|
||||
changed := false
|
||||
if currentStatus != network.ReachabilityPublic {
|
||||
// Aggressively switch to public from other states ignoring confidence
|
||||
log.Debugf("NAT status is public")
|
||||
|
||||
// we are flipping our NATStatus, so confidence drops to 0
|
||||
as.confidence = 0
|
||||
if as.service != nil {
|
||||
as.service.Enable()
|
||||
}
|
||||
changed = true
|
||||
} else if as.confidence < maxConfidence {
|
||||
as.confidence++
|
||||
}
|
||||
as.status.Store(&observation)
|
||||
if changed {
|
||||
as.emitStatus()
|
||||
}
|
||||
} else if observation == network.ReachabilityPrivate {
|
||||
if currentStatus != network.ReachabilityPrivate {
|
||||
if as.confidence > 0 {
|
||||
as.confidence--
|
||||
} else {
|
||||
log.Debugf("NAT status is private")
|
||||
|
||||
// we are flipping our NATStatus, so confidence drops to 0
|
||||
as.confidence = 0
|
||||
as.status.Store(&observation)
|
||||
if as.service != nil {
|
||||
as.service.Disable()
|
||||
}
|
||||
as.emitStatus()
|
||||
}
|
||||
} else if as.confidence < maxConfidence {
|
||||
as.confidence++
|
||||
as.status.Store(&observation)
|
||||
}
|
||||
} else if as.confidence > 0 {
|
||||
// don't just flip to unknown, reduce confidence first
|
||||
as.confidence--
|
||||
} else {
|
||||
log.Debugf("NAT status is unknown")
|
||||
as.status.Store(&observation)
|
||||
if currentStatus != network.ReachabilityUnknown {
|
||||
if as.service != nil {
|
||||
as.service.Enable()
|
||||
}
|
||||
as.emitStatus()
|
||||
}
|
||||
}
|
||||
if as.metricsTracer != nil {
|
||||
as.metricsTracer.ReachabilityStatusConfidence(as.confidence)
|
||||
}
|
||||
}
|
||||
|
||||
func (as *AmbientAutoNAT) tryProbe(p peer.ID) bool {
|
||||
as.lastProbeTry = time.Now()
|
||||
if p.Validate() != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if lastTime, ok := as.recentProbes[p]; ok {
|
||||
if time.Since(lastTime) < as.throttlePeerPeriod {
|
||||
return false
|
||||
}
|
||||
}
|
||||
as.cleanupRecentProbes()
|
||||
|
||||
info := as.host.Peerstore().PeerInfo(p)
|
||||
|
||||
if !as.config.dialPolicy.skipPeer(info.Addrs) {
|
||||
as.recentProbes[p] = time.Now()
|
||||
as.lastProbe = time.Now()
|
||||
go as.probe(&info)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (as *AmbientAutoNAT) probe(pi *peer.AddrInfo) {
|
||||
cli := NewAutoNATClient(as.host, as.config.addressFunc, as.metricsTracer)
|
||||
ctx, cancel := context.WithTimeout(as.ctx, as.config.requestTimeout)
|
||||
defer cancel()
|
||||
|
||||
err := cli.DialBack(ctx, pi.ID)
|
||||
log.Debugf("Dialback through peer %s completed: err: %s", pi.ID, err)
|
||||
|
||||
select {
|
||||
case as.dialResponses <- err:
|
||||
case <-as.ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (as *AmbientAutoNAT) getPeerToProbe() peer.ID {
|
||||
peers := as.host.Network().Peers()
|
||||
if len(peers) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
candidates := make([]peer.ID, 0, len(peers))
|
||||
|
||||
for _, p := range peers {
|
||||
info := as.host.Peerstore().PeerInfo(p)
|
||||
// Exclude peers which don't support the autonat protocol.
|
||||
if proto, err := as.host.Peerstore().SupportsProtocols(p, AutoNATProto); len(proto) == 0 || err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Exclude peers in backoff.
|
||||
if lastTime, ok := as.recentProbes[p]; ok {
|
||||
if time.Since(lastTime) < as.throttlePeerPeriod {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if as.config.dialPolicy.skipPeer(info.Addrs) {
|
||||
continue
|
||||
}
|
||||
candidates = append(candidates, p)
|
||||
}
|
||||
|
||||
if len(candidates) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return candidates[rand.Intn(len(candidates))]
|
||||
}
|
||||
|
||||
func (as *AmbientAutoNAT) Close() error {
|
||||
as.ctxCancel()
|
||||
if as.service != nil {
|
||||
as.service.Disable()
|
||||
}
|
||||
<-as.backgroundRunning
|
||||
return nil
|
||||
}
|
||||
|
||||
// Status returns the AutoNAT observed reachability status.
|
||||
func (s *StaticAutoNAT) Status() network.Reachability {
|
||||
return s.reachability
|
||||
}
|
||||
|
||||
func (s *StaticAutoNAT) Close() error {
|
||||
if s.service != nil {
|
||||
s.service.Disable()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
122
vendor/github.com/libp2p/go-libp2p/p2p/host/autonat/client.go
generated
vendored
Normal file
122
vendor/github.com/libp2p/go-libp2p/p2p/host/autonat/client.go
generated
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
package autonat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/autonat/pb"
|
||||
|
||||
"github.com/libp2p/go-msgio/pbio"
|
||||
)
|
||||
|
||||
// NewAutoNATClient creates a fresh instance of an AutoNATClient
|
||||
// If addrFunc is nil, h.Addrs will be used
|
||||
func NewAutoNATClient(h host.Host, addrFunc AddrFunc, mt MetricsTracer) Client {
|
||||
if addrFunc == nil {
|
||||
addrFunc = h.Addrs
|
||||
}
|
||||
return &client{h: h, addrFunc: addrFunc, mt: mt}
|
||||
}
|
||||
|
||||
type client struct {
|
||||
h host.Host
|
||||
addrFunc AddrFunc
|
||||
mt MetricsTracer
|
||||
}
|
||||
|
||||
// DialBack asks peer p to dial us back on all addresses returned by the addrFunc.
|
||||
// It blocks until we've received a response from the peer.
|
||||
//
|
||||
// Note: A returned error Message_E_DIAL_ERROR does not imply that the server
|
||||
// actually performed a dial attempt. Servers that run a version < v0.20.0 also
|
||||
// return Message_E_DIAL_ERROR if the dial was skipped due to the dialPolicy.
|
||||
func (c *client) DialBack(ctx context.Context, p peer.ID) error {
|
||||
s, err := c.h.NewStream(ctx, p, AutoNATProto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.Scope().SetService(ServiceName); err != nil {
|
||||
log.Debugf("error attaching stream to autonat service: %s", err)
|
||||
s.Reset()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.Scope().ReserveMemory(maxMsgSize, network.ReservationPriorityAlways); err != nil {
|
||||
log.Debugf("error reserving memory for autonat stream: %s", err)
|
||||
s.Reset()
|
||||
return err
|
||||
}
|
||||
defer s.Scope().ReleaseMemory(maxMsgSize)
|
||||
|
||||
s.SetDeadline(time.Now().Add(streamTimeout))
|
||||
// Might as well just reset the stream. Once we get to this point, we
|
||||
// don't care about being nice.
|
||||
defer s.Close()
|
||||
|
||||
r := pbio.NewDelimitedReader(s, maxMsgSize)
|
||||
w := pbio.NewDelimitedWriter(s)
|
||||
|
||||
req := newDialMessage(peer.AddrInfo{ID: c.h.ID(), Addrs: c.addrFunc()})
|
||||
if err := w.WriteMsg(req); err != nil {
|
||||
s.Reset()
|
||||
return err
|
||||
}
|
||||
|
||||
var res pb.Message
|
||||
if err := r.ReadMsg(&res); err != nil {
|
||||
s.Reset()
|
||||
return err
|
||||
}
|
||||
if res.GetType() != pb.Message_DIAL_RESPONSE {
|
||||
s.Reset()
|
||||
return fmt.Errorf("unexpected response: %s", res.GetType().String())
|
||||
}
|
||||
|
||||
status := res.GetDialResponse().GetStatus()
|
||||
if c.mt != nil {
|
||||
c.mt.ReceivedDialResponse(status)
|
||||
}
|
||||
switch status {
|
||||
case pb.Message_OK:
|
||||
return nil
|
||||
default:
|
||||
return Error{Status: status, Text: res.GetDialResponse().GetStatusText()}
|
||||
}
|
||||
}
|
||||
|
||||
// Error wraps errors signalled by AutoNAT services
|
||||
type Error struct {
|
||||
Status pb.Message_ResponseStatus
|
||||
Text string
|
||||
}
|
||||
|
||||
func (e Error) Error() string {
|
||||
return fmt.Sprintf("AutoNAT error: %s (%s)", e.Text, e.Status.String())
|
||||
}
|
||||
|
||||
// IsDialError returns true if the error was due to a dial back failure
|
||||
func (e Error) IsDialError() bool {
|
||||
return e.Status == pb.Message_E_DIAL_ERROR
|
||||
}
|
||||
|
||||
// IsDialRefused returns true if the error was due to a refusal to dial back
|
||||
func (e Error) IsDialRefused() bool {
|
||||
return e.Status == pb.Message_E_DIAL_REFUSED
|
||||
}
|
||||
|
||||
// IsDialError returns true if the AutoNAT peer signalled an error dialing back
|
||||
func IsDialError(e error) bool {
|
||||
ae, ok := e.(Error)
|
||||
return ok && ae.IsDialError()
|
||||
}
|
||||
|
||||
// IsDialRefused returns true if the AutoNAT peer signalled refusal to dial back
|
||||
func IsDialRefused(e error) bool {
|
||||
ae, ok := e.(Error)
|
||||
return ok && ae.IsDialRefused()
|
||||
}
|
||||
95
vendor/github.com/libp2p/go-libp2p/p2p/host/autonat/dialpolicy.go
generated
vendored
Normal file
95
vendor/github.com/libp2p/go-libp2p/p2p/host/autonat/dialpolicy.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
package autonat
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/host"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
manet "github.com/multiformats/go-multiaddr/net"
|
||||
)
|
||||
|
||||
type dialPolicy struct {
|
||||
allowSelfDials bool
|
||||
host host.Host
|
||||
}
|
||||
|
||||
// skipDial indicates that a multiaddress isn't worth attempted dialing.
|
||||
// The same logic is used when the autonat client is considering if
|
||||
// a remote peer is worth using as a server, and when the server is
|
||||
// considering if a requested client is worth dialing back.
|
||||
func (d *dialPolicy) skipDial(addr ma.Multiaddr) bool {
|
||||
// skip relay addresses
|
||||
_, err := addr.ValueForProtocol(ma.P_CIRCUIT)
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if d.allowSelfDials {
|
||||
return false
|
||||
}
|
||||
|
||||
// skip private network (unroutable) addresses
|
||||
if !manet.IsPublicAddr(addr) {
|
||||
return true
|
||||
}
|
||||
candidateIP, err := manet.ToIP(addr)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
// Skip dialing addresses we believe are the local node's
|
||||
for _, localAddr := range d.host.Addrs() {
|
||||
localIP, err := manet.ToIP(localAddr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if localIP.Equal(candidateIP) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// skipPeer indicates that the collection of multiaddresses representing a peer
|
||||
// isn't worth attempted dialing. If one of the addresses matches an address
|
||||
// we believe is ours, we exclude the peer, even if there are other valid
|
||||
// public addresses in the list.
|
||||
func (d *dialPolicy) skipPeer(addrs []ma.Multiaddr) bool {
|
||||
localAddrs := d.host.Addrs()
|
||||
localHosts := make([]net.IP, 0)
|
||||
for _, lAddr := range localAddrs {
|
||||
if _, err := lAddr.ValueForProtocol(ma.P_CIRCUIT); err != nil && manet.IsPublicAddr(lAddr) {
|
||||
lIP, err := manet.ToIP(lAddr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
localHosts = append(localHosts, lIP)
|
||||
}
|
||||
}
|
||||
|
||||
// if a public IP of the peer is one of ours: skip the peer.
|
||||
goodPublic := false
|
||||
for _, addr := range addrs {
|
||||
if _, err := addr.ValueForProtocol(ma.P_CIRCUIT); err != nil && manet.IsPublicAddr(addr) {
|
||||
aIP, err := manet.ToIP(addr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, lIP := range localHosts {
|
||||
if lIP.Equal(aIP) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
goodPublic = true
|
||||
}
|
||||
}
|
||||
|
||||
if d.allowSelfDials {
|
||||
return false
|
||||
}
|
||||
|
||||
return !goodPublic
|
||||
}
|
||||
31
vendor/github.com/libp2p/go-libp2p/p2p/host/autonat/interface.go
generated
vendored
Normal file
31
vendor/github.com/libp2p/go-libp2p/p2p/host/autonat/interface.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package autonat
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
// AutoNAT is the interface for NAT autodiscovery
|
||||
type AutoNAT interface {
|
||||
// Status returns the current NAT status
|
||||
Status() network.Reachability
|
||||
io.Closer
|
||||
}
|
||||
|
||||
// Client is a stateless client interface to AutoNAT peers
|
||||
type Client interface {
|
||||
// DialBack requests from a peer providing AutoNAT services to test dial back
|
||||
// and report the address on a successful connection.
|
||||
DialBack(ctx context.Context, p peer.ID) error
|
||||
}
|
||||
|
||||
// AddrFunc is a function returning the candidate addresses for the local host.
|
||||
type AddrFunc func() []ma.Multiaddr
|
||||
|
||||
// Option is an Autonat option for configuration
|
||||
type Option func(*config) error
|
||||
162
vendor/github.com/libp2p/go-libp2p/p2p/host/autonat/metrics.go
generated
vendored
Normal file
162
vendor/github.com/libp2p/go-libp2p/p2p/host/autonat/metrics.go
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
package autonat
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/p2p/host/autonat/pb"
|
||||
"github.com/libp2p/go-libp2p/p2p/metricshelper"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const metricNamespace = "libp2p_autonat"
|
||||
|
||||
var (
|
||||
reachabilityStatus = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "reachability_status",
|
||||
Help: "Current node reachability",
|
||||
},
|
||||
)
|
||||
reachabilityStatusConfidence = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "reachability_status_confidence",
|
||||
Help: "Node reachability status confidence",
|
||||
},
|
||||
)
|
||||
receivedDialResponseTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "received_dial_response_total",
|
||||
Help: "Count of dial responses for client",
|
||||
},
|
||||
[]string{"response_status"},
|
||||
)
|
||||
outgoingDialResponseTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "outgoing_dial_response_total",
|
||||
Help: "Count of dial responses for server",
|
||||
},
|
||||
[]string{"response_status"},
|
||||
)
|
||||
outgoingDialRefusedTotal = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "outgoing_dial_refused_total",
|
||||
Help: "Count of dial requests refused by server",
|
||||
},
|
||||
[]string{"refusal_reason"},
|
||||
)
|
||||
nextProbeTimestamp = prometheus.NewGauge(
|
||||
prometheus.GaugeOpts{
|
||||
Namespace: metricNamespace,
|
||||
Name: "next_probe_timestamp",
|
||||
Help: "Time of next probe",
|
||||
},
|
||||
)
|
||||
collectors = []prometheus.Collector{
|
||||
reachabilityStatus,
|
||||
reachabilityStatusConfidence,
|
||||
receivedDialResponseTotal,
|
||||
outgoingDialResponseTotal,
|
||||
outgoingDialRefusedTotal,
|
||||
nextProbeTimestamp,
|
||||
}
|
||||
)
|
||||
|
||||
type MetricsTracer interface {
|
||||
ReachabilityStatus(status network.Reachability)
|
||||
ReachabilityStatusConfidence(confidence int)
|
||||
ReceivedDialResponse(status pb.Message_ResponseStatus)
|
||||
OutgoingDialResponse(status pb.Message_ResponseStatus)
|
||||
OutgoingDialRefused(reason string)
|
||||
NextProbeTime(t time.Time)
|
||||
}
|
||||
|
||||
func getResponseStatus(status pb.Message_ResponseStatus) string {
|
||||
var s string
|
||||
switch status {
|
||||
case pb.Message_OK:
|
||||
s = "ok"
|
||||
case pb.Message_E_DIAL_ERROR:
|
||||
s = "dial error"
|
||||
case pb.Message_E_DIAL_REFUSED:
|
||||
s = "dial refused"
|
||||
case pb.Message_E_BAD_REQUEST:
|
||||
s = "bad request"
|
||||
case pb.Message_E_INTERNAL_ERROR:
|
||||
s = "internal error"
|
||||
default:
|
||||
s = "unknown"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
const (
|
||||
rate_limited = "rate limited"
|
||||
dial_blocked = "dial blocked"
|
||||
no_valid_address = "no valid address"
|
||||
)
|
||||
|
||||
type metricsTracer struct{}
|
||||
|
||||
var _ MetricsTracer = &metricsTracer{}
|
||||
|
||||
type metricsTracerSetting struct {
|
||||
reg prometheus.Registerer
|
||||
}
|
||||
|
||||
type MetricsTracerOption func(*metricsTracerSetting)
|
||||
|
||||
func WithRegisterer(reg prometheus.Registerer) MetricsTracerOption {
|
||||
return func(s *metricsTracerSetting) {
|
||||
if reg != nil {
|
||||
s.reg = reg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewMetricsTracer(opts ...MetricsTracerOption) MetricsTracer {
|
||||
setting := &metricsTracerSetting{reg: prometheus.DefaultRegisterer}
|
||||
for _, opt := range opts {
|
||||
opt(setting)
|
||||
}
|
||||
metricshelper.RegisterCollectors(setting.reg, collectors...)
|
||||
return &metricsTracer{}
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) ReachabilityStatus(status network.Reachability) {
|
||||
reachabilityStatus.Set(float64(status))
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) ReachabilityStatusConfidence(confidence int) {
|
||||
reachabilityStatusConfidence.Set(float64(confidence))
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) ReceivedDialResponse(status pb.Message_ResponseStatus) {
|
||||
tags := metricshelper.GetStringSlice()
|
||||
defer metricshelper.PutStringSlice(tags)
|
||||
*tags = append(*tags, getResponseStatus(status))
|
||||
receivedDialResponseTotal.WithLabelValues(*tags...).Inc()
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) OutgoingDialResponse(status pb.Message_ResponseStatus) {
|
||||
tags := metricshelper.GetStringSlice()
|
||||
defer metricshelper.PutStringSlice(tags)
|
||||
*tags = append(*tags, getResponseStatus(status))
|
||||
outgoingDialResponseTotal.WithLabelValues(*tags...).Inc()
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) OutgoingDialRefused(reason string) {
|
||||
tags := metricshelper.GetStringSlice()
|
||||
defer metricshelper.PutStringSlice(tags)
|
||||
*tags = append(*tags, reason)
|
||||
outgoingDialRefusedTotal.WithLabelValues(*tags...).Inc()
|
||||
}
|
||||
|
||||
func (mt *metricsTracer) NextProbeTime(t time.Time) {
|
||||
nextProbeTimestamp.Set(float64(t.Unix()))
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user