mirror of
https://github.com/vacp2p/specs.git
synced 2026-01-08 23:08:09 -05:00
rename archive dir to _archive
This commit is contained in:
33
_archive/1-introduction.md
Normal file
33
_archive/1-introduction.md
Normal file
@@ -0,0 +1,33 @@
|
||||
1 Introduction
|
||||
==============
|
||||
|
||||
While developing [IPFS, the InterPlanetary FileSystem](https://ipfs.io/), we came to learn about several challenges imposed by having to run a distributed file system on top of heterogeneous devices, with different network setups and capabilities. During this process, we had to revisit the whole network stack and elaborate solutions to overcome the obstacles imposed by design decisions of the several layers and protocols, without breaking compatibility or recreating technologies.
|
||||
|
||||
In order to build this library, we focused on tackling problems independently, creating less complex solutions with powerful abstractions that, when composed, can offer an environment for a peer-to-peer application to work successfully.
|
||||
|
||||
| ⚠️ Warning: parts of this document are incomplete and out of date. Please see [this issue](https://github.com/libp2p/specs/issues/156), and look for deprecation notices throughout. ⚠️ |
|
||||
| --- |
|
||||
|
||||
## 1.1 Motivation
|
||||
|
||||
`libp2p` is the result of our collective experience of building a distributed system, in that it puts responsibility on developers to decide how they want an app to interoperate with others in the network, and favors configuration and extensibility instead of making assumptions about the network setup.
|
||||
|
||||
In essence, a peer using `libp2p` should be able to communicate with another peer using a variety of different transports, including connection relay, and talk over different protocols, negotiated on demand.
|
||||
|
||||
## 1.2 Goals
|
||||
|
||||
Our goals for the `libp2p` specification and its implementations are:
|
||||
|
||||
- Enable the use of various:
|
||||
- transports: TCP, UDP, SCTP, UDT, uTP, QUIC, SSH, etc.
|
||||
- authenticated transports: TLS, DTLS, CurveCP, SSH
|
||||
- Make efficient use of sockets (connection reuse)
|
||||
- Enable communications between peers to be multiplexed over one socket (avoiding handshake overhead)
|
||||
- Enable multiprotocols and respective versions to be used between peers, using a negotiation process
|
||||
- Be backwards compatible
|
||||
- Work in current systems
|
||||
- Use the full capabilities of current network technologies
|
||||
- Have NAT traversal
|
||||
- Enable connections to be relayed
|
||||
- Enable encrypted channels
|
||||
- Make efficient use of underlying transports (e.g. native stream muxing, native auth, etc.)
|
||||
79
_archive/2-state-of-the-art.md
Normal file
79
_archive/2-state-of-the-art.md
Normal file
@@ -0,0 +1,79 @@
|
||||
2 An analysis of the state of the art in network stacks
|
||||
====================================================
|
||||
|
||||
This section presents to the reader an analysis of the available protocols and architectures for network stacks. The goal is to provide the foundations from which to infer the conclusions and understand why `libp2p` has the requirements and architecture that it has.
|
||||
|
||||
## 2.1 The client-server model
|
||||
|
||||
The client-server model indicates that both parties at the ends of the channel have different roles, that they support different services and/or have different capabilities, or in other words, that they speak different protocols.
|
||||
|
||||
Building client-server applications has been the natural tendency for a number of reasons:
|
||||
|
||||
- The bandwidth inside a data center is considerably higher than that available for clients to connect to each other.
|
||||
- Data center resources are considerably cheaper, due to efficient usage and bulk stocking.
|
||||
- It makes it easier for the developer and system admin to have fine grained control over the application.
|
||||
- It reduces the number of heterogeneous systems to be handled (although the number is still considerable).
|
||||
- Systems like NAT make it really hard for client machines to find and talk with each other, forcing a developer to perform very clever hacks to traverse these obstacles.
|
||||
- Protocols started to be designed with the assumption that a developer will create a client-server application from the start.
|
||||
|
||||
We even learned how to hide all the complexity of a distributed system behind gateways on the Internet, using protocols that were designed to perform a point-to-point operation, such as HTTP, making it opaque for the application to see and understand the cascade of service calls made for each request.
|
||||
|
||||
`libp2p` offers a move towards dialer-listener interactions, from the client-server listener, where it is not implicit which of the entities, dialer or listener, has which capabilities or is enabled to perform which actions. Setting up a connection between two applications today is a multilayered problem to solve, and these connections should not have a purpose bias, and should instead support several other protocols to work on top of the established connection. In a client-server model, a server sending data without a prior request from the client is known as a push model, which typically adds more complexity; in a dialer-listener model in comparison, both entities can perform requests independently.
|
||||
|
||||
## 2.2 Categorizing the network stack protocols by solutions
|
||||
|
||||
Before diving into the `libp2p` protocols, it is important to understand the large diversity of protocols already in wide use and deployment that help maintain today's simple abstractions. For example, when one thinks about an HTTP connection, one might naively just think that HTTP/TCP/IP are the main protocols involved, but in reality many more protocols participate, depending on the usage, the networks involved, and so on. Protocols like DNS, DHCP(v6), ARP, NDISC, OSPF, Ethernet, 802.11 (Wi-Fi) and many others get involved. Looking inside ISPs' own networks would reveal dozens more.
|
||||
|
||||
Additionally, it's worth noting that the traditional 7-layer OSI model characterization does not fit `libp2p`. Instead, we categorize protocols based on their role, i.e. the problem they solve. The upper layers of the OSI model are geared towards point-to-point links between applications, whereas the `libp2p` protocols speak more towards various sizes of networks, with various properties, under various different security models. Different `libp2p` protocols can have the same role (in the OSI model, this would be "address the same layer"), meaning that multiple protocols can run simultaneously, all addressing one role (instead of one-protocol-per-layer in traditional OSI stacking). For example, bootstrap lists, mDNS, DHT discovery, and PEX are all forms of the role "Peer Discovery"; they can coexist and even synergize.
|
||||
|
||||
### 2.2.1 Establishing the physical link
|
||||
|
||||
- Ethernet
|
||||
- Wi-Fi
|
||||
- Bluetooth
|
||||
- USB
|
||||
|
||||
### 2.2.2 Addressing a machine or process
|
||||
|
||||
- IPv4
|
||||
- IPv6
|
||||
- Hidden addressing, like SDP
|
||||
|
||||
### 2.2.3 Discovering other peers or services
|
||||
|
||||
- ARP
|
||||
- NDISC
|
||||
- DHCP(v6)
|
||||
- DNS
|
||||
- Onion
|
||||
|
||||
### 2.2.4 Routing messages through the network
|
||||
|
||||
- RIP(1, 2)
|
||||
- OSPF
|
||||
- BGP
|
||||
- PPP
|
||||
- Tor
|
||||
- I2P
|
||||
- cjdns
|
||||
|
||||
### 2.2.5 Transport
|
||||
|
||||
- TCP
|
||||
- UDP
|
||||
- UDT
|
||||
- QUIC
|
||||
- WebRTC data channel
|
||||
|
||||
### 2.2.6 Agreed semantics for applications to talk to each other
|
||||
|
||||
- RMI
|
||||
- Remoting
|
||||
- RPC
|
||||
- HTTP
|
||||
|
||||
## 2.3 Current shortcomings
|
||||
|
||||
Although we currently have a panoply of protocols available for our services to communicate, the abundance and variety of solutions creates its own problems. It is currently difficult for an application to be able to support and be available through several transports (e.g. the lack of TCP/UDP stack in browser applications).
|
||||
|
||||
There is also no 'presence linking', meaning that there isn't a notion for a peer to announce itself in several transports, so that other peers can guarantee that it is always the same peer.
|
||||
116
_archive/3-requirements.md
Normal file
116
_archive/3-requirements.md
Normal file
@@ -0,0 +1,116 @@
|
||||
3 Requirements and considerations
|
||||
=================================
|
||||
|
||||
## 3.1 Transport agnostic
|
||||
|
||||
`libp2p` is transport agnostic, so it can run over any transport protocol. It does not even depend on IP; it may run on top of NDN, XIA, and other new Internet architectures.
|
||||
|
||||
In order to reason about possible transports, `libp2p` uses [multiaddr](https://github.com/multiformats/multiaddr), a self-describing addressing format. This makes it possible for `libp2p` to treat addresses opaquely everywhere in the system, and have support for various transport protocols in the network layer. The actual format of addresses in `libp2p` is `ipfs-addr`, a multiaddr that ends with an IPFS node id. For example, these are all valid `ipfs-addrs`:
|
||||
|
||||
```
|
||||
# IPFS over TCP over IPv6 (typical TCP)
|
||||
/ip6/fe80::8823:6dff:fee7:f172/tcp/4001/ipfs/QmYJyUMAcXEw1b5bFfbBbzYu5wyyjLMRHXGUkCXpag74Fu
|
||||
|
||||
# IPFS over uTP over UDP over IPv4 (UDP-shimmed transport)
|
||||
/ip4/162.246.145.218/udp/4001/utp/ipfs/QmYJyUMAcXEw1b5bFfbBbzYu5wyyjLMRHXGUkCXpag74Fu
|
||||
|
||||
# IPFS over IPv6 (unreliable)
|
||||
/ip6/fe80::8823:6dff:fee7:f172/ipfs/QmYJyUMAcXEw1b5bFfbBbzYu5wyyjLMRHXGUkCXpag74Fu
|
||||
|
||||
# IPFS over TCP over IPv4 over TCP over IPv4 (proxy)
|
||||
/ip4/162.246.145.218/tcp/7650/ip4/192.168.0.1/tcp/4001/ipfs/QmYJyUMAcXEw1b5bFfbBbzYu5wyyjLMRHXGUkCXpag74Fu
|
||||
|
||||
# IPFS over Ethernet (no IP)
|
||||
/ether/ac:fd:ec:0b:7c:fe/ipfs/QmYJyUMAcXEw1b5bFfbBbzYu5wyyjLMRHXGUkCXpag74Fu
|
||||
```
|
||||
|
||||
**Note:** At this time, no unreliable implementations exist. The protocol's interface for defining and using unreliable transport has not been defined. For more information on unreliable vs reliable transport, see [here](http://www.inetdaemon.com/tutorials/basic_concepts/communication/reliable_vs_unreliable.shtml). In the context of WebRTC, CTRL+F "reliable" [here](https://www.html5rocks.com/en/tutorials/webrtc/basics/#signaling).
|
||||
|
||||
## 3.2 Multi-multiplexing
|
||||
|
||||
The `libp2p` protocol is a collection of multiple protocols. In order to conserve resources, and to make connectivity easier, `libp2p` can perform all its operations through a single port, such as a TCP or UDP port, depending on the transports used. `libp2p` can multiplex its many protocols through point-to-point connections. This multiplexing is for both reliable streams and unreliable datagrams.
|
||||
|
||||
`libp2p` is pragmatic. It seeks to be usable in as many settings as possible, to be modular and flexible to fit various use cases, and to force as few choices as possible. Thus the `libp2p` network layer provides what we're loosely referring to as "multi-multiplexing":
|
||||
|
||||
- can multiplex multiple listen network interfaces
|
||||
- can multiplex multiple transport protocols
|
||||
- can multiplex multiple connections per peer
|
||||
- can multiplex multiple client protocols
|
||||
- can multiplex multiple streams per protocol, per connection (SPDY, HTTP2, QUIC, SSH)
|
||||
- has flow control (backpressure, fairness)
|
||||
- encrypts each connection with a different ephemeral key
|
||||
|
||||
To give an example, imagine a single IPFS node that:
|
||||
|
||||
- listens on a particular TCP/IP address
|
||||
- listens on a different TCP/IP address
|
||||
- listens on a SCTP/UDP/IP address
|
||||
- listens on a UDT/UDP/IP address
|
||||
- has multiple connections to another node X
|
||||
- has multiple connections to another node Y
|
||||
- has multiple streams open per connection
|
||||
- multiplexes streams over HTTP2 to node X
|
||||
- multiplexes streams over SSH to node Y
|
||||
- one protocol mounted on top of `libp2p` uses one stream per peer
|
||||
- one protocol mounted on top of `libp2p` uses multiple streams per peer
|
||||
|
||||
Not providing this level of flexbility makes it impossible to use `libp2p` in various platforms, use cases, or network setups. It is not important that all implementations support all choices; what is critical is that the spec is flexible enough to allow implementations to use precisely what they need. This ensures that complex user or application constraints do not rule out `libp2p` as an option.
|
||||
|
||||
## 3.3 Encryption
|
||||
|
||||
Communications on `libp2p` may be:
|
||||
|
||||
- **encrypted**
|
||||
- **signed** (not encrypted)
|
||||
- **clear** (not encrypted, not signed)
|
||||
|
||||
We take both security and performance seriously. We recognize that encryption is not viable for some in-datacenter high performance use cases.
|
||||
|
||||
We recommend that:
|
||||
|
||||
- implementations encrypt all communications by default
|
||||
- implementations are audited
|
||||
- unless absolutely necessary, users normally operate with encrypted communications only.
|
||||
|
||||
`libp2p` uses cyphersuites like TLS.
|
||||
|
||||
**Note:** We do not use TLS directly, because we do not want the CA system baggage. Most TLS implementations are very big. Since the `libp2p` model begins with keys, `libp2p` only needs to apply ciphers. This is a minimal portion of the whole TLS standard.
|
||||
|
||||
## 3.4 NAT traversal
|
||||
|
||||
Network Address Translation is ubiquitous in the Internet. Not only are most consumer devices behind many layers of NAT, but most data center nodes are often behind NAT for security or virtualization reasons. As we move into containerized deployments, this is getting worse. IPFS implementations SHOULD provide a way to traverse NATs, otherwise it is likely that operation will be affected. Even nodes meant to run with real IP addresses must implement NAT traversal techniques, as they may need to establish connections to peers behind NAT.
|
||||
|
||||
`libp2p` accomplishes full NAT traversal using an ICE-like protocol. It is not exactly ICE, as IPFS networks provide the possibility of relaying communications over the IPFS protocol itself, for coordinating hole-punching or even relaying communication.
|
||||
|
||||
It is recommended that implementations use one of the many NAT traversal libraries available, such as `libnice`, `libwebrtc`, or `natty`. However, NAT traversal must be interoperable.
|
||||
|
||||
## 3.5 Relay
|
||||
|
||||
Unfortunately, due to symmetric NATs, container and VM NATs, and other impossible-to-bypass NATs, `libp2p` MUST fallback to relaying communication to establish a full connectivity graph. To be complete, implementations MUST support relay, though it SHOULD be optional and able to be turned off by end users.
|
||||
|
||||
Connection relaying SHOULD be implemented as a transport, in order to be transparent to upper layers.
|
||||
|
||||
For an instantiation of relaying, see the [p2p-circuit transport](relay).
|
||||
|
||||
|
||||
## 3.6 Enable several network topologies
|
||||
|
||||
Different systems have different requirements and with that comes different topologies. In the P2P literature we can find these topologies being enumerated as: unstructured, structured, hybrid and centralized.
|
||||
|
||||
Centralized topologies are the most common to find in Web Applications infrastructures, it requires for a given service or services to be present at all times in a known static location, so that other services can access them. Unstructured networks represent a type of P2P networks where the network topology is completely random, or at least non deterministic, while structured networks have a implicit way of organizing themselves. Hybrid networks are a mix of the last two.
|
||||
|
||||
With this in consideration, `libp2p` must be ready to perform different routing mechanisms and peer discovery, in order to build the routing tables that will enable services to propagate messages or to find each other.
|
||||
|
||||
## 3.7 Resource discovery
|
||||
|
||||
`libp2p` also solves the problem with discoverability of resources inside of a network through *records*. A record is a unit of data that can be digitally signed, timestamped and/or used with other methods to give it an ephemeral validity. These records hold pieces of information such as location or availability of resources present in the network. These resources can be data, storage, CPU cycles and other types of services.
|
||||
|
||||
`libp2p` must not put a constraint on the location of resources, but instead offer ways to find them easily in the network or use a side channel.
|
||||
|
||||
## 3.8 Messaging
|
||||
|
||||
Efficient messaging protocols offer ways to deliver content with minimum latency and/or support large and complex topologies for distribution. `libp2p` seeks to incorporate the developments made in Multicast and PubSub to fulfil these needs.
|
||||
|
||||
## 3.9 Naming
|
||||
|
||||
Networks change and applications need to have a way to use the network in such a way that it is agnostic to its topology, naming appears to solve this issues.
|
||||
134
_archive/4-architecture.md
Normal file
134
_archive/4-architecture.md
Normal file
@@ -0,0 +1,134 @@
|
||||
4 Architecture
|
||||
==============
|
||||
|
||||
| ⚠️ Warning: this section is incomplete, and parts of it are out of date. Please see [this issue](https://github.com/libp2p/specs/issues/156) to track progress on improving it. ⚠️ |
|
||||
| --- |
|
||||
|
||||
`libp2p` was designed around the Unix Philosophy of creating small components that are easy to understand and test. These components should also be able to be swapped in order to accommodate different technologies or scenarios and also make it feasible to upgrade them over time.
|
||||
|
||||
Although different peers can support different protocols depending on their capabilities, any peer can act as a dialer and/or a listener for connections from other peers, connections that once established can be reused from both ends, removing the distinction between clients and servers.
|
||||
|
||||
The `libp2p` interface acts as a thin veneer over a multitude of subsystems that are required in order for peers to be able to communicate. These subsystems are allowed to be built on top of other subsystems as long as they respect the standardized interface. The main areas where these subsystems fit are:
|
||||
|
||||
- Peer Routing - Mechanism to decide which peers to use for routing particular messages. This routing can be done recursively, iteratively or even in a broadcast/multicast mode.
|
||||
- Swarm - Handles everything that touches the 'opening a stream' part of `libp2p`, from protocol muxing, stream muxing, NAT traversal and connection relaying, while being multi-transport.
|
||||
- Distributed Record Store - A system to store and distribute records. Records are small entries used by other systems for signaling, establishing links, announcing peers or content, and so on. They have a similar role to DNS in the broader Internet.
|
||||
- Discovery - Finding or identifying other peers in the network.
|
||||
|
||||
Each of these subsystems exposes a well known interface (see [chapter 6](6-interfaces.md) for Interfaces) and may use each other in order to fulfill their goal. A global overview of the system is:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ libp2p │
|
||||
└─────────────────────────────────────────────────────────────────────────────────┘
|
||||
┌─────────────────┐┌─────────────────┐┌──────────────────────────┐┌───────────────┐
|
||||
│ Peer Routing ││ Swarm ││ Distributed Record Store ││ Discovery │
|
||||
└─────────────────┘└─────────────────┘└──────────────────────────┘└───────────────┘
|
||||
```
|
||||
|
||||
## 4.1 Peer Routing
|
||||
|
||||
A Peer Routing subsystem exposes an interface to identify which peers a message should be routed to in the DHT. It receives a key and must return one or more `PeerInfo` objects.
|
||||
|
||||
We present two examples of possible Peer Routing subsystems, the first based on a the Kademlia DHT and the second based on mDNS. Nevertheless, other Peer Routing mechanisms can be implemented, as long as they fulfil the same expectation and interface.
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Peer Routing │
|
||||
│ │
|
||||
│┌──────────────┐┌────────────────┐┌──────────────────────────┐│
|
||||
││ kad-routing ││ mDNS-routing ││ other-routing-mechanisms ││
|
||||
││ ││ ││ ││
|
||||
││ ││ ││ ││
|
||||
│└──────────────┘└────────────────┘└──────────────────────────┘│
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 4.1.1 kad-routing
|
||||
|
||||
kad-routing implements the Kademlia Routing table, where each peer holds a set of k-buckets, each of them containing several `PeerInfo` objects from other peers in the network.
|
||||
|
||||
### 4.1.2 mDNS-routing
|
||||
|
||||
mDNS-routing uses mDNS probes to identify if local area network peers have a given key or they are simply present.
|
||||
|
||||
## 4.2 Swarm
|
||||
|
||||
### 4.2.1 Stream Muxer
|
||||
|
||||
The stream muxer must implement the interface offered by [interface-stream-muxer](https://github.com/diasdavid/interface-stream-muxer).
|
||||
|
||||
### 4.2.2 Protocol Muxer
|
||||
|
||||
Protocol muxing is handled on the application level instead of the conventional way at the port level (where different services/protocols listen at different ports). This enables us to support several protocols to be muxed in the same socket, saving the cost of doing NAT traversal for more than one port.
|
||||
|
||||
Protocol multiplexing is done through [`multistream`](https://github.com/jbenet/multistream), a protocol to negotiate different types of streams (protocols) using [`multicodec`](https://github.com/jbenet/multicodec).
|
||||
|
||||
### 4.2.3 Transport
|
||||
|
||||
### 4.2.4 Crypto
|
||||
|
||||
### 4.2.5 Identify
|
||||
|
||||
**Identify** is one of the protocols mounted on top of Swarm, our Connection handler. However, it follows and respects the same pattern as any other protocol when it comes to mounting it on top of Swarm. Identify enables us to trade `listenAddrs` and `observedAddrs` between peers, which is crucial for the working of IPFS. Since every socket open implements `REUSEPORT`, an `observedAddr` by another peer can enable a third peer to connect to us, since the port will be already open and redirect to us on a NAT.
|
||||
|
||||
### 4.2.6 Relay
|
||||
|
||||
See [Circuit Relay](/relay).
|
||||
|
||||
## 4.3 Distributed Record Store
|
||||
|
||||
### 4.3.1 Record
|
||||
|
||||
Follows [IPRS spec](/IPRS.md).
|
||||
|
||||
### 4.3.2 abstract-record-store
|
||||
|
||||
### 4.3.3 kad-record-store
|
||||
|
||||
### 4.3.4 mDNS-record-store
|
||||
|
||||
### 4.3.5 s3-record-store
|
||||
|
||||
## 4.4 Discovery
|
||||
|
||||
### 4.4.1 mDNS-discovery
|
||||
|
||||
mDNS-discovery is a Discovery Protocol that uses [mDNS](https://en.wikipedia.org/wiki/Multicast_DNS) over local area networks with zero configuration. Local area network peers are very useful to peer-to-peer protocols, because of their low latency links.
|
||||
|
||||
The [mDNS-discovery](discovery/mdns.md) specification describes how to use mDNS to discover other peers.
|
||||
|
||||
mDNS-discovery is a standalone protocol and does not depend on any other `libp2p` protocol. mDNS-discovery can yield peers available in the local area network, without relying on other infrastructure. This is particularly useful in intranets, networks disconnected from the Internet backbone, and networks which temporarily lose links.
|
||||
|
||||
mDNS-discovery can be configured per-service (i.e. discover only peers participating in a specific protocol, like IPFS), and with private networks (discover peers belonging to a private network).
|
||||
|
||||
We are exploring ways to make mDNS-discovery beacons encrypted (so that other nodes in the local network cannot discern what service is being used), though the nature of mDNS will always reveal local IP addresses.
|
||||
|
||||
**Privacy note:** mDNS advertises in local area networks, which reveals IP addresses to listeners in the same local network. It is not recommended to use this with privacy-sensitive applications or oblivious routing protocols.
|
||||
|
||||
#### 4.4.2 random-walk
|
||||
|
||||
Random-Walk is a Discovery Protocol for DHTs (and other protocols with routing tables). It makes random DHT queries in order to learn about a large number of peers quickly. This causes the DHT (or other protocols) to converge much faster, at the expense of a small load at the very beginning.
|
||||
|
||||
#### 4.4.3 bootstrap-list
|
||||
|
||||
Bootstrap-List is a Discovery Protocol that uses local storage to cache the addresses of highly stable (and somewhat trusted) peers available in the network. This allows protocols to "find the rest of the network". This is essentially the same way that DNS bootstraps itself (though note that changing the DNS bootstrap list -- the "dot domain" addresses -- is not easy to do, by design).
|
||||
|
||||
- The list should be stored in long-term local storage, whatever that means to the local node (e.g. to disk).
|
||||
- Protocols can ship a default list hardcoded or along with the standard code distribution (like DNS).
|
||||
- In most cases (and certainly in the case of IPFS) the bootstrap list should be user configurable, as users may wish to establish separate networks, or place their reliance and trust in specific nodes.
|
||||
|
||||
## 4.5 Messaging
|
||||
|
||||
#### 4.5.1 PubSub
|
||||
|
||||
See [`pubsub/`](pubsub/) and [`pubsub/gossipsub/`](pubsub/gossipsub/).
|
||||
|
||||
|
||||
## 4.6 Naming
|
||||
|
||||
#### 4.6.1 IPRS
|
||||
|
||||
[IPRS spec](/IPRS.md)
|
||||
|
||||
#### 4.6.2 IPNS
|
||||
17
_archive/5-datastructures.md
Normal file
17
_archive/5-datastructures.md
Normal file
@@ -0,0 +1,17 @@
|
||||
5 Data structures
|
||||
=================
|
||||
|
||||
The network protocol deals with these data structures:
|
||||
|
||||
- a `PrivateKey`, the private key of a node.
|
||||
- a `PublicKey`, the public key of a node.
|
||||
- a `PeerId`, a hash of a node's public key.
|
||||
- a `PeerInfo`, an object containing a node's `PeerId` and its known multiaddrs.
|
||||
- a `Transport`, a transport used to establish connections to other peers. See <https://github.com/libp2p/interface-transport>.
|
||||
- a `Connection`, a point-to-point link between two nodes. Must implement <https://github.com/libp2p/interface-connection>.
|
||||
- a `Muxed-Stream`, a duplex message channel.
|
||||
- a `Stream-Muxer`, a stream multiplexer. Must implement <https://github.com/libp2p/interface-stream-muxer>.
|
||||
- a `Record`, IPLD (IPFS Linked Data) described object that implements [IPRS](https://github.com/libp2p/specs/blob/master/IPRS.md).
|
||||
- a `multiaddr`, a self describable network address. See <https://github.com/multiformats/multiaddr>.
|
||||
- a `multicodec`, a self describable encoding type. See <https://github.com/multiformats/multicodec>.
|
||||
- a `multihash`, a self describable hash. See <https://github.com/multiformats/multihash>.
|
||||
101
_archive/6-interfaces.md
Normal file
101
_archive/6-interfaces.md
Normal file
@@ -0,0 +1,101 @@
|
||||
6 Interfaces
|
||||
============
|
||||
|
||||
| ⚠️ Warning: this section is incomplete, and parts of it are out of date. Please see [this issue](https://github.com/libp2p/specs/issues/156) to track progress on improving it. ⚠️ |
|
||||
| --- |
|
||||
|
||||
`libp2p` is a collection of several protocols working together to offer a common solid interface that can talk with any other network addressable process. This is made possible by shimming currently existing protocols and implementations into a set of explicit interfaces: Peer Routing, Discovery, Stream Muxing, Transports, Connections and so on.
|
||||
|
||||
## 6.1 libp2p
|
||||
|
||||
`libp2p`, the top module that provides an interface to all the other modules that make a `libp2p` instance, must offer an interface for dialing to a peer and plugging in all of the modules (e.g. which transports) we want to support. We present the `libp2p` interface and UX in [section 6.6](#66-libp2p-interface-and-ux), after presenting every other module interface.
|
||||
|
||||
## 6.2 Peer Routing
|
||||
|
||||

|
||||
|
||||
A Peer Routing module offers a way for a `libp2p` `Node` to find the `PeerInfo` of another `Node`, so that it can dial that node. In its most pure form, a Peer Routing module should have an interface that takes a 'key', and returns a set of `PeerInfo`s.
|
||||
See https://github.com/libp2p/interface-peer-routing for the interface and tests.
|
||||
|
||||
## 6.3 Swarm
|
||||
|
||||
Current interface available and updated at:
|
||||
|
||||
https://github.com/libp2p/js-libp2p-swarm#usage
|
||||
|
||||
### 6.3.1 Transport
|
||||
|
||||

|
||||
|
||||
https://github.com/libp2p/interface-transport
|
||||
|
||||
### 6.3.2 Connection
|
||||
|
||||

|
||||
|
||||
https://github.com/libp2p/interface-connection
|
||||
|
||||
### 6.3.3 Stream Muxing
|
||||
|
||||

|
||||
|
||||
https://github.com/libp2p/interface-stream-muxer
|
||||
|
||||
## 6.4 Distributed Record Store
|
||||
|
||||

|
||||
|
||||
https://github.com/libp2p/interface-record-store
|
||||
|
||||
## 6.5 Peer Discovery
|
||||
|
||||
A Peer Discovery module interface should return `PeerInfo` objects, as it finds new peers to be considered by our Peer Routing modules.
|
||||
|
||||
## 6.6 libp2p interface and UX
|
||||
|
||||
`libp2p` implementations should enable it to be instantiated programmatically, or to use a previous compiled library with some of the protocol decisions already made, so that the user can reuse or expand.
|
||||
|
||||
### Constructing a libp2p instance programatically
|
||||
|
||||
Example made with JavaScript, should be mapped to other languages:
|
||||
|
||||
```JavaScript
|
||||
var Libp2p = require('libp2p')
|
||||
|
||||
var node = new Libp2p()
|
||||
|
||||
// add a swarm instance
|
||||
node.addSwarm(swarmInstance)
|
||||
|
||||
// add one or more Peer Routing mechanisms
|
||||
node.addPeerRouting(peerRoutingInstance)
|
||||
|
||||
// add a Distributed Record Store
|
||||
node.addDistributedRecordStore(distributedRecordStoreInstance)
|
||||
```
|
||||
|
||||
Configuring `libp2p` is quite straightforward since most of the configuration comes from instantiating the several modules, one at a time.
|
||||
|
||||
### Dialing and Listening for connections to/from a peer
|
||||
|
||||
Ideally, `libp2p` uses its own mechanisms (PeerRouting and Record Store) to find a way to dial to a given peer:
|
||||
|
||||
```JavaScript
|
||||
node.dial(PeerInfo)
|
||||
```
|
||||
|
||||
To receive an incoming connection, specify one or more protocols to handle:
|
||||
|
||||
```JavaScript
|
||||
node.handleProtocol('<multicodec>', function (duplexStream) {
|
||||
|
||||
})
|
||||
```
|
||||
|
||||
### Finding a peer
|
||||
|
||||
Finding a peer is done through Peer Routing, so the interface is the same.
|
||||
|
||||
### Storing and Retrieving Records
|
||||
|
||||
Like Finding a peer, Storing and Retrieving records is done through Record Store, so the interface is the same.
|
||||
214
_archive/7-properties.md
Normal file
214
_archive/7-properties.md
Normal file
@@ -0,0 +1,214 @@
|
||||
7 Properties
|
||||
============
|
||||
|
||||
| ⚠️ Warning: this section is incomplete, and parts of it are out of date. Please see [this issue](https://github.com/libp2p/specs/issues/156) to track progress on improving it. ⚠️ |
|
||||
| --- |
|
||||
|
||||
## 7.1 Communication Model - Streams
|
||||
|
||||
The Network layer handles all the problems of connecting to a peer, and exposes
|
||||
simple bidirectional streams. Users can both open a new stream
|
||||
(`NewStream`) and register a stream handler (`SetStreamHandler`). The user
|
||||
is then free to implement whatever wire messaging protocol she desires. This
|
||||
makes it easy to build peer-to-peer protocols, as the complexities of
|
||||
connectivity, multi-transport support, flow control, and so on, are handled.
|
||||
|
||||
To help capture the model, consider that:
|
||||
|
||||
- `NewStream` is similar to making a Request in an HTTP client.
|
||||
- `SetStreamHandler` is similar to registering a URL handler in an HTTP server
|
||||
|
||||
So a protocol, such as a DHT, could:
|
||||
|
||||
```go
|
||||
node := p2p.NewNode(peerid)
|
||||
|
||||
// register a handler, here it is simply echoing everything.
|
||||
node.SetStreamHandler("/helloworld", func (s Stream) {
|
||||
io.Copy(s, s)
|
||||
})
|
||||
|
||||
// make a request.
|
||||
buf1 := []byte("Hello World!")
|
||||
buf2 := make([]byte, len(buf1))
|
||||
|
||||
stream, _ := node.NewStream("/helloworld", peerid) // open a new stream
|
||||
stream.Write(buf1) // write to the remote
|
||||
stream.Read(buf2) // read what was sent back
|
||||
fmt.Println(buf2) // print what was sent back
|
||||
```
|
||||
|
||||
## 7.2 Ports - Constrained Entrypoints
|
||||
|
||||
In the Internet of 2015, we have a processing model where a program may be
|
||||
running without the ability to open multiple -- or even single -- network
|
||||
ports. Most hosts are behind NAT, whether of the household ISP variety or the new
|
||||
containerized data-center type. And some programs may even be running in
|
||||
browsers, with no ability to open sockets directly (sort of). This presents
|
||||
challenges to completely peer-to-peer networks that aspire to connect _any_
|
||||
hosts together -- whether they're running on a page in the browser, or in
|
||||
a container within a container.
|
||||
|
||||
IPFS only needs a single channel of communication with the rest of the
|
||||
network. This may be a single TCP or UDP port, or a single connection
|
||||
through WebSockets or WebRTC. In a sense, the role of the TCP/UDP network
|
||||
stack -- i.e. multiplexing applications and connections -- may now be forced
|
||||
to happen at the application level.
|
||||
|
||||
## 7.3 Transport Protocols
|
||||
|
||||
IPFS is transport-agnostic. It can run on any transport protocol. The
|
||||
`ipfs-addr` format (which is an IPFS-specific
|
||||
[multiaddr](https://github.com/jbenet/multiaddr)) describes the transport.
|
||||
For example:
|
||||
|
||||
```sh
|
||||
# ipv4 + tcp
|
||||
/ip4/10.1.10.10/tcp/29087/ipfs/QmVcSqVEsvm5RR9mBLjwpb2XjFVn5bPdPL69mL8PH45pPC
|
||||
|
||||
# ipv6 + tcp
|
||||
/ip6/2601:9:4f82:5fff:aefd:ecff:fe0b:7cfe/tcp/1031/ipfs/QmRzjtZsTqL1bMdoJDwsC6ZnDX1PW1vTiav1xewHYAPJNT
|
||||
|
||||
# ipv4 + udp + udt
|
||||
/ip4/104.131.131.82/udp/4001/udt/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
|
||||
|
||||
# ipv4 + udp + utp
|
||||
/ip4/104.131.67.168/udp/1038/utp/ipfs/QmU184wLPg7afQjBjwUUFkeJ98Fp81GhHGurWvMqwvWEQN
|
||||
```
|
||||
|
||||
IPFS delegates the transport dialing to a multiaddr-based network package, such
|
||||
as [go-multiaddr-net](https://github.com/jbenet/go-multiaddr-net). It is
|
||||
advisable to build modules like this in other languages, and scope the
|
||||
implementation of other transport protocols.
|
||||
|
||||
Some of the transport protocols we will be using:
|
||||
|
||||
- UTP
|
||||
- UDT
|
||||
- SCTP
|
||||
- WebRTC (SCTP, etc)
|
||||
- WebSockets
|
||||
- TCP Remy
|
||||
|
||||
## 7.4 Non-IP Networks
|
||||
|
||||
Efforts like [NDN](http://named-data.net) and
|
||||
[XIA](http://www.cs.cmu.edu/~xia/) are new architectures for the Internet,
|
||||
which are closer to the model IPFS uses than what IP provides today. IPFS
|
||||
will be able to operate on top of these architectures trivially, as there
|
||||
are no assumptions made about the network stack in the protocol. Implementations
|
||||
will likely need to change, but changing implementations is vastly easier than
|
||||
changing protocols.
|
||||
|
||||
## 7.5 On the wire
|
||||
|
||||
We have the **hard constraint** of making IPFS work across _any_ duplex stream (an outgoing and an incoming stream pair, any arbitrary connection) and work on _any_ platform.
|
||||
|
||||
To make this work, IPFS has to solve a few problems:
|
||||
|
||||
- [Protocol Multiplexing](#751-protocol-multiplexing) - running multiple protocols over the same stream
|
||||
- [multistream](#752-multistream---self-describing-protocol-stream) - self-describing protocol streams
|
||||
- [multistream-select](#753-multistream-selector---self-describing-protocol-stream-selector) - a self-describing protocol selector
|
||||
- [Stream Multiplexing](#754-stream-multiplexing) - running many independent streams over the same wire
|
||||
- [Portable Encodings](#755-portable-encodings) - using portable serialization formats
|
||||
- [Secure Communications](#756-secure-communications) - using ciphersuites to establish security and privacy (like TLS)
|
||||
|
||||
### 7.5.1 Protocol-Multiplexing
|
||||
|
||||
Protocol Multiplexing means running multiple different protocols over the same stream. This could happen sequentially (one after the other), or concurrently (at the same time, with their messages interleaved). We achieve protocol multiplexing using three pieces:
|
||||
|
||||
- [multistream](#752-multistream---self-describing-protocol-stream) - self-describing protocol streams
|
||||
- [multistream-select](#753-multistream-selector---self-describing-protocol-stream-selector) - a self-describing protocol selector
|
||||
- [Stream Multiplexing](#754-stream-multiplexing) - running many independent streams over the same wire
|
||||
|
||||
### 7.5.2 multistream - self-describing protocol stream
|
||||
|
||||
[multistream](https://github.com/jbenet/multistream) is a self-describing protocol stream format. It is extremely simple. Its goal is to define a way to add headers to protocols that describe the protocol itself. It is sort of like adding versions to a protocol, but extremely explicit.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
/ipfs/QmVXZiejj3sXEmxuQxF2RjmFbEiE9w7T82xDn3uYNuhbFb/ipfs-dht/0.2.3
|
||||
<dht-message>
|
||||
<dht-message>
|
||||
...
|
||||
```
|
||||
|
||||
### 7.5.3 multistream-selector - self-describing protocol stream selector
|
||||
|
||||
[multistream-select](https://github.com/jbenet/multistream/tree/master/multistream) is a simple [multistream](https://github.com/jbenet/multistream) protocol that allows listing and selecting other protocols. This means that Protomux has a list of registered protocols, listens for one, and then _nests_ (or upgrades) the connection to speak the registered protocol. This takes direct advantage of multistream: it enables interleaving multiple protocols, as well as inspecting what protocols might be spoken by the remote endpoint.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
/ipfs/QmdRKVhvzyATs3L6dosSb6w8hKuqfZK2SyPVqcYJ5VLYa2/multistream-select/0.3.0
|
||||
/ipfs/QmVXZiejj3sXEmxuQxF2RjmFbEiE9w7T82xDn3uYNuhbFb/ipfs-dht/0.2.3
|
||||
<dht-message>
|
||||
<dht-message>
|
||||
...
|
||||
```
|
||||
|
||||
### 7.5.4 Stream Multiplexing
|
||||
|
||||
Stream Multiplexing is the process of multiplexing (or combining) many different streams into a single one. This is a complicated subject because it enables protocols to run concurrently over the same wire, and all sorts of notions regarding fairness, flow control, head-of-line blocking, etc. start affecting the protocols. In practice, stream multiplexing is well understood and there are many stream multiplexing protocols. To name a few:
|
||||
|
||||
- HTTP/2
|
||||
- SPDY
|
||||
- QUIC
|
||||
- SSH
|
||||
|
||||
IPFS nodes are free to support whatever stream multiplexors they wish, on top of the default one. The default one is there to enable even the simplest of nodes to speak multiple protocols at once. The default multiplexor will be HTTP/2 (or maybe QUIC?), but implementations for it are sparse, so we are beginning with SPDY. We simply select which protocol to use with a multistream header.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
/ipfs/QmdRKVhvzyATs3L6dosSb6w8hKuqfZK2SyPVqcYJ5VLYa2/multistream-select/0.3.0
|
||||
/ipfs/Qmb4d8ZLuqnnVptqTxwqt3aFqgPYruAbfeksvRV1Ds8Gri/spdy/3
|
||||
<spdy-header-opening-a-stream-0>
|
||||
/ipfs/QmVXZiejj3sXEmxuQxF2RjmFbEiE9w7T82xDn3uYNuhbFb/ipfs-dht/0.2.3
|
||||
<dht-message>
|
||||
<dht-message>
|
||||
<spdy-header-opening-a-stream-1>
|
||||
/ipfs/QmVXZiejj3sXEmxuQxF2RjmFbEiE9w7T82xDn3uYNuhbFb/ipfs-bitswap/0.3.0
|
||||
<bitswap-message>
|
||||
<bitswap-message>
|
||||
<spdy-header-selecting-stream-0>
|
||||
<dht-message>
|
||||
<dht-message>
|
||||
<dht-message>
|
||||
<dht-message>
|
||||
<spdy-header-selecting-stream-1>
|
||||
<bitswap-message>
|
||||
<bitswap-message>
|
||||
<bitswap-message>
|
||||
<bitswap-message>
|
||||
...
|
||||
```
|
||||
|
||||
### 7.5.5 Portable Encodings
|
||||
|
||||
In order to be ubiquitous, we _must_ use hyper-portable format encodings, those that are easy to use in various other platforms. Ideally these encodings are well-tested in the wild, and widely used. There may be cases where multiple encodings have to be supported (and hence we may need a [multicodec](https://github.com/jbenet/multicodec) self-describing encoding), but this has so far not been needed.
|
||||
For now, we use [protobuf](https://github.com/google/protobuf) for all protocol messages exclusively, but other good candidates are [capnp](https://capnproto.org/), [bson](http://bsonspec.org/), and [ubjson](http://ubjson.org/).
|
||||
|
||||
### 7.5.6 Secure Communications
|
||||
|
||||
The wire protocol is -- of course -- wrapped with encryption. We use cyphersuites similar to TLS. This is explained further in [requirements and considerations: encryption](3-requirements.md#33-encryption).
|
||||
|
||||
### 7.5.7 Protocol Multicodecs
|
||||
|
||||
Here, we present a table with the multicodecs defined for each IPFS protocol that has a wire componenent. This list may change over time and currently exists as a guide for implementation.
|
||||
|
||||
protocol | multicodec | comment
|
||||
:---- | :---- | :----
|
||||
secio | /secio/1.0.0 |
|
||||
TLS | /tls/1.3.0 | not implemented
|
||||
plaintext | /plaintext/1.0.0 |
|
||||
spdy | /spdy/3.1.0 |
|
||||
yamux | /yamux/1.0.0 |
|
||||
multiplex | /mplex/6.7.0 |
|
||||
identify | /ipfs/id/1.0.0 |
|
||||
ping | /ipfs/ping/1.0.0 |
|
||||
circuit-relay | /libp2p/relay/circuit/0.1.0 | [spec](/relay)
|
||||
diagnostics | /ipfs/diag/net/1.0.0 |
|
||||
Kademlia DHT | /ipfs/kad/1.0.0 |
|
||||
bitswap | /ipfs/bitswap/1.0.0 |
|
||||
122
_archive/8-implementations.md
Normal file
122
_archive/8-implementations.md
Normal file
@@ -0,0 +1,122 @@
|
||||
8 Implementations
|
||||
=================
|
||||
|
||||
A `libp2p` implementation should (recommended) follow a certain level of granularity when implementing different modules and functionalities, so that common interfaces are easy to expose, test and check for interoperability with other implementations.
|
||||
|
||||
This is the list of current modules available for `libp2p`:
|
||||
|
||||
- libp2p (entry point)
|
||||
- **Swarm**
|
||||
- libp2p-swarm
|
||||
- libp2p-identify
|
||||
- libp2p-ping
|
||||
- Transports
|
||||
- [interface-transport](https://github.com/diasdavid/interface-transport)
|
||||
- [interface-connection](https://github.com/diasdavid/interface-connection)
|
||||
- libp2p-tcp
|
||||
- libp2p-udp
|
||||
- libp2p-udt
|
||||
- libp2p-utp
|
||||
- libp2p-webrtc
|
||||
- libp2p-cjdns
|
||||
- Stream Muxing
|
||||
- [interface-stream-muxer](https://github.com/diasdavid/interface-stream-muxer)
|
||||
- libp2p-spdy
|
||||
- libp2p-multiplex
|
||||
- Crypto Channel
|
||||
- libp2p-tls
|
||||
- libp2p-secio
|
||||
- **Peer Routing**
|
||||
- libp2p-kad-routing
|
||||
- libp2p-mDNS-routing
|
||||
- **Discovery**
|
||||
- libp2p-mdns-discovery
|
||||
- libp2p-random-walk
|
||||
- libp2p-railing
|
||||
- **Distributed Record Store**
|
||||
- libp2p-record
|
||||
- [interface-record-store](https://github.com/diasdavid/interface-record-store)
|
||||
- libp2p-distributed-record-store
|
||||
- libp2p-kad-record-store
|
||||
- **Generic**
|
||||
- PeerInfo
|
||||
- PeerId
|
||||
- multihash
|
||||
- multiaddr
|
||||
- multistream
|
||||
- multicodec
|
||||
- ipld
|
||||
- repo
|
||||
|
||||
Current known implementations (or WIP) are:
|
||||
|
||||
- JavaScript - <https://github.com/libp2p/js-libp2p>
|
||||
- Go - <https://github.com/ipfs/go-libp2p>
|
||||
- Python - <https://github.com/candeira/py-ipfs/blob/readme-roadmap/README.md>
|
||||
- Rust - <https://github.com/libp2p/rust-libp2p>
|
||||
|
||||
## 8.1 Swarm
|
||||
|
||||
### 8.1.1 Swarm Dialer
|
||||
|
||||
The swarm dialer manages making a successful connection to a target peer, given a stream of addresses as inputs, and making sure to respect any and all rate limits imposed. To this end, we have designed the following logic for dialing:
|
||||
|
||||
```
|
||||
DialPeer(peerID) {
|
||||
if PeerIsBeingDialed(peerID) {
|
||||
waitForDialToComplete(peerID)
|
||||
return BestConnToPeer(peerID)
|
||||
}
|
||||
|
||||
StartDial(peerID)
|
||||
|
||||
waitForDialToComplete(peerID)
|
||||
return BestConnToPeer(peerID)
|
||||
}
|
||||
|
||||
|
||||
StartDial(peerID) {
|
||||
addrs = getAddressStream(peerID)
|
||||
|
||||
addrs.onNewAddr(function(addr) {
|
||||
if rateLimitCanDial(peerID, addr) {
|
||||
doDialAsync(peerID, addr)
|
||||
} else {
|
||||
rateLimitScheduleDial(peerID, addr)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// doDialAsync starts dialing to a specific address without blocking.
|
||||
// when the dial returns, it releases rate limit tokens, and if it
|
||||
// succeeded, will finalize the dial process.
|
||||
doDialAsync(peerID, addr) {
|
||||
go transportDial(addr, function(conn, err) {
|
||||
rateLimitReleaseTokens(peerID, addr)
|
||||
|
||||
if err != null {
|
||||
// handle error
|
||||
}
|
||||
|
||||
dialSuccess(conn)
|
||||
})
|
||||
}
|
||||
|
||||
// rateLimitReleaseTokens checks for any tokens the given dial
|
||||
// took, and then for each of them, checks if any other dial is waiting
|
||||
// for any of those tokens. If waiting dials are found, those dials are started
|
||||
// immediately. Otherwise, the tokens are released to their pools.
|
||||
rateLimitReleaseTokens(peerID, addr) {
|
||||
tokens = tokensForDial(peerID, addr)
|
||||
|
||||
for token in tokens {
|
||||
dial = dialWaitingForToken(token)
|
||||
if dial != null {
|
||||
doDialAsync(dial.peer, dial.addr)
|
||||
} else {
|
||||
token.release()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
1
_archive/9-references.md
Normal file
1
_archive/9-references.md
Normal file
@@ -0,0 +1 @@
|
||||
- State of Peer-to-Peer (P2P) Communication across Network Address Translators (NATs): <https://tools.ietf.org/html/rfc5128>
|
||||
244
_archive/IPRS.md
Normal file
244
_archive/IPRS.md
Normal file
@@ -0,0 +1,244 @@
|
||||
# IPRS - InterPlanetary Record System spec
|
||||
Authors: [Juan Benet](github.com/jbenet)
|
||||
|
||||
Reviewers:
|
||||
|
||||
- [Kristoffer Strom](github.com/krl)
|
||||
- [Jeromy Johnson](github.com/whyrusleeping)
|
||||
- [W. Trevor King](github.com/wking)
|
||||
|
||||
* * *
|
||||
|
||||
The [Spec](../) for IPRS.
|
||||
|
||||
This spec defines IPRS (InterPlanetary Record System) a system for distributed record keeping meant to operate across networks that may span massive distances (>1AU) or suffer long partitions (>1 earth yr).
|
||||
IPRS is meant to establish a common record-keeping layer to solve common problems. It is a well-layered protocol: it is agnostic to underlying replication and transport systems, and it supports a variety of different applications.
|
||||
IPRS is part of the InterPlanetary File System Project, and is general enough to be used in a variery of other systems.
|
||||
|
||||
## Definitions
|
||||
|
||||
### Records
|
||||
|
||||
A (distributed) `record` is a piece of data meant to be transmitted and stored in various computers across a network. It carries a `value` external to the record-keeping system, which clients of the record system use. For example: a namespace record may store the value of a name. All record systems include a notion of _record validity_, which allows users of the record system to verify whether the value of a record is correct and valid under the user's circumstances. For example, a record's validity may depend upon a cryptographic signature, a range of spacetime, et-cetera.
|
||||
|
||||
### Record System
|
||||
|
||||
A (distributed) `record system` is a protocol which defines a method for crafting, serializing, distributing, verifying, and using records over computer networks. (e.g. the Domain Name System).
|
||||
|
||||
|
||||
- `crafting` - construction of a record (the process of calculating the values of a record)
|
||||
- `serializing` - formating a record into a bitstring.
|
||||
- `distributing` - transportation of a record from one set of computers to another.
|
||||
- `verifying` - checking a record's values to ensure correctness and validity.
|
||||
|
||||
|
||||
### Validity Schemes
|
||||
|
||||
A `validity scheme` is a small sub-protocol that defines how a record's _validity_ is to be calculated. `Validity` is the quality of a record being usable by a user at a particular set of circumstances (e.g. a range of time). It is distinct from `correctness` in that `correctness` governs whether the record was correctly constructed, and `validity` governs whether a record may still be used. All _valid_ records must be _correct_. For simplicity, the process of checking correctness is included in the `validity scheme`.
|
||||
|
||||
For example, suppose Alice and Bob want to store records on a public bulletin board. To make sure their records are not tampered with, Alice and Bob decide they will include cryptographic signatures. This can ensure correctness. Further, they also agree to add new records every day, to detect whether their records are being replayed or censored. Thus, their `validity scheme` might be:
|
||||
|
||||
```go
|
||||
type Record struct {
|
||||
Value []byte
|
||||
Expires time.Time
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
func signablePart(r *Record) []byte {
|
||||
var sigbuf bytes.Buffer
|
||||
sigbuf.Write(r.Value)
|
||||
sigbuf.Write(r.Expires)
|
||||
return sigbuf.Bytes()
|
||||
}
|
||||
|
||||
func MakeRecord(value []byte, authorKey crypto.PrivateKey) Record {
|
||||
rec := Record{}
|
||||
rec.Value = value
|
||||
|
||||
// establish an expiration date
|
||||
rec.Expires = time.Now() + time.Day
|
||||
|
||||
// cryptographically sign the record
|
||||
rec.Signature = authorKey.Sign(signablePart(rec))
|
||||
|
||||
return rec
|
||||
}
|
||||
|
||||
func VerifyRecord(rec Record, authorKey crypto.PublicKey) (ok bool) {
|
||||
|
||||
// always check the signature first
|
||||
sigok := authorKey.Verify(rec.Signature, signablePart(rec))
|
||||
if !sigok {
|
||||
return false // sig did not check out! forged record?
|
||||
}
|
||||
|
||||
// check the expiration.
|
||||
if rec.Expires < time.Now() {
|
||||
return false // not valid anymore :(
|
||||
}
|
||||
|
||||
// everything seems ok!
|
||||
return true
|
||||
}
|
||||
```
|
||||
|
||||
Note that even in such a simple system, we already called out to two other systems Alice and Bob are subscribing to:
|
||||
|
||||
- a _Public Key Infrastructure_ (PKI) that lets Alice and Bob know each other's keys, and verify the validity of messages authored by each other.
|
||||
- a _Time Infrastructure_ (TI) that lets Alice and Bob agree upon a common notion of time intervals and validity durations.
|
||||
|
||||
Both of these are large systems on their own, which impose constraints and security parameters on the record system. For example, if Alice and Bob think that NTP timestamps are a good TI, the validity of their records is dependent on their ability to establish an accurate NTP timestamp securely (i.e. they need secure access to shared clocks). Another TI might be to "use the last observed record", and this also is dependent on having a secure announcement channel.
|
||||
|
||||
IPRS is _Validity Scheme Agnostic_, meaning that it seeks to establish a common way to craft and distribute records for users of a system without necessarily tying them down to specific world-views (e.g. "NTP is a secure way to keep time", "The CA system is a secure PKI"), or _forcing_ them to work around specific system choices that impose constraints unreasonable for their use case (e.g. "Real-Time Video Over TOR")
|
||||
|
||||
### Merkle DAG and IPFS Objects
|
||||
|
||||
A merkle dag is a directed acyclic graph whose links are (a) hashes of the edge target, and (b) contained within the edge source. (syn. merkle tree, hash tree)
|
||||
|
||||
In this spec, _the merkle dag_ (specific one) refers to the IPFS merkle dag. _IPFS Object_ refers to objects in the merkle dag, which follow the IPFS merkledag format. (Read those specs)
|
||||
|
||||
|
||||
## Constraints
|
||||
|
||||
IPRS has the following _hard_ constraints:
|
||||
|
||||
- **MUST** be transport agnostic. (transport refers to how computers communicate).
|
||||
- **MUST** be replication agnostic. (replication refers to the protocol computers use to transfer and propagate whole records and other objects)
|
||||
- **MUST** be validity scheme agnostic. (validity scheme includes PKI, TI, and other "agreed upon" trusted infrastructure)
|
||||
- **MUST** be trustless: no trusted third parties are imposed by IPRS (though some may be adopted by a validity scheme. e.g. root CAs in the CA system PKI, or a blockchain in a blockchain TI). In most cases, users may have to trust each other (as they must trust the record value -- e.g. DNS), but in some cases there may be cryptographic schemes that enable full trustlessness.
|
||||
|
||||
|
||||
It is easy to be agnostic to transport, replication, and validity scheme as long as users can expect to control or agree upon the programs or protocols used in concert with IPRS. Concretely, the user can select specific transports or validity schemes to suit the user's application constraints. It is the user's responsibility to ensure both record crafters and verifiers agree upon these selections.
|
||||
|
||||
## Construction
|
||||
|
||||
### The Objects
|
||||
|
||||
IPRS records are expressed as [merkledag](../merkledag) objects. This means that the records are linked authenticated data structures, and can be natively replicated over IPFS itself and other merkledag distribution systems.
|
||||
|
||||
The objects:
|
||||
|
||||
- A `Record` object expresses a value, a validity scheme, and validity data.
|
||||
- A `Signature` object could be used to sign and authenticate a record.
|
||||
- An `Encryption` object could be used to encrypt a record.
|
||||
|
||||
```go
|
||||
Record Node {
|
||||
Scheme Link // link to a validity scheme
|
||||
Value Link // link to an object representing the value.
|
||||
Version Data // record version number
|
||||
Validity Data // data needed to satisfy the validity scheme
|
||||
}
|
||||
```
|
||||
|
||||
To achieve good performance, record storage and transfer should bundle all the necessary objects and transmit them together. While "the record object" is only one of the dag objects, "the full record" means a bundle of all objects needed to fully represent, verify, and use the record. (This recommendation does not necessarily include data that records _describe_, for example an ipfs provider record (which signals to consumers that certain data is available) would not include the data itself as part of "the full record").
|
||||
|
||||
### The Interface
|
||||
|
||||
The IPRS interface is below. It has a few types and functions. We use the Go language to express it, but this is language agnostic.
|
||||
|
||||
```go
|
||||
// Record is the base type. user can define other types that
|
||||
// extend Record.
|
||||
type Record struct {
|
||||
Scheme Link // link to the validity scheme
|
||||
Signature Link // link to a cryptographic signature over the rest of record
|
||||
Value Data // an opaque value
|
||||
}
|
||||
|
||||
// Validator is a function that returns whether a record is valid.
|
||||
// Users provide their own Validator implementations.
|
||||
type Validator func(r *Record) (bool, error)
|
||||
|
||||
// Order is a function that sorts two records based on validity.
|
||||
// This means that one record should be preferred over the other.
|
||||
// there must be a total order. if return is 0, then a == b.
|
||||
// Return value is -1, 0, 1.
|
||||
type Order func(a, b *Record) int
|
||||
|
||||
// Marshal/Unmarshal specifies a way to code the record
|
||||
type Marshal(r *Record) ([]byte, error)
|
||||
type Unmarshal(r *Record, []byte) (error)
|
||||
```
|
||||
|
||||
### Interface Example
|
||||
|
||||
For example, Alice and Bob earlier could use the following interface:
|
||||
|
||||
```go
|
||||
type Record struct {
|
||||
Scheme Link // link to the validity scheme
|
||||
Expires Data // datetime at which record expires
|
||||
Value Data // an opaque value
|
||||
}
|
||||
|
||||
|
||||
func Validator(r *Record) (bool, error) {
|
||||
authorKey := recordSigningKey(r)
|
||||
|
||||
// always check the signature first
|
||||
sigok := authorKey.Verify(r.Signature, signablePart(r))
|
||||
if !sigok {
|
||||
return false, errors.New("invalid signature. forged record?")
|
||||
}
|
||||
|
||||
// check the expiration.
|
||||
if r.Expires < time.Now() {
|
||||
return false, errors.New("record expired.")
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func Order(a, b *Record) int {
|
||||
if a.Expires > b.Expires {
|
||||
return 1
|
||||
}
|
||||
if a.Expires < b.Expires {
|
||||
return -1
|
||||
}
|
||||
|
||||
// only return 0 if records are the exact same record.
|
||||
// otherwise, if the ordering doesn't matter (in this case
|
||||
// because the expiry is the same) return one of them
|
||||
// deterministically. Comparing the hashes takes care of this.
|
||||
ra := a.Hash()
|
||||
rb := b.Hash()
|
||||
return bytes.Compare(ra, rb)
|
||||
}
|
||||
|
||||
func Marshal(r *Record) ([]byte, error) {
|
||||
return recordProtobuf.Marshal(r)
|
||||
}
|
||||
|
||||
func Unmarshal(r *Record, d []byte) (error) {
|
||||
return recordProtobuf.Unmarshal(r, d)
|
||||
}
|
||||
```
|
||||
|
||||
## Example Record Types
|
||||
|
||||
For ease of use, IPRS implementations should include a set of common record types:
|
||||
|
||||
- signed, valid within a datetime range
|
||||
- signed, expiring after a Time-To-Live
|
||||
- signed, based on ancestry (chain)
|
||||
- signed, with cryptographic freshness
|
||||
|
||||
|
||||
### Signed, valid within a datetime range
|
||||
|
||||
This record type uses digital signatures (and thus a PKI) and timestamps (and thus a TI). It establishes that a record is valid during a particular datetime range. 0 (beginning of time), and infinity (end of time) can express unbounded validity.
|
||||
|
||||
### Signed, expiring after a Time-To-Live
|
||||
|
||||
This record type uses digital signatures (and thus a PKI) and TTLs (and thus a TI). It establishes that a record is valid for a certain amount of time after a particular event. For example, an event may be "upon receipt" to specify that a record is valid for a given amount of time after a processor first receives it. This is equivalent to the way DNS sets expiries.
|
||||
|
||||
### Signed, based on ancestry (chain)
|
||||
|
||||
This record type uses digital signatures (and thus a PKI) and merkle-links to other, previous records. It establishes that the "most recent" record (merkle-ordered) is the most valid. This functions similar to a git commit chain.
|
||||
|
||||
### Signed, with cryptographic freshness
|
||||
|
||||
This record type uses digital signatures (and thus a PKI) and a cryptographic notion of freshness (and therefore a TI). It establishes that records are only valid if within some threshold of recent time. It is similar to a TTL.
|
||||
104
_archive/README.md
Normal file
104
_archive/README.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# libp2p specification
|
||||
|
||||
<h1 align="center">
|
||||
<img src="https://raw.githubusercontent.com/libp2p/libp2p/a13997787e57d40d6315b422afbe1ceb62f45511/logo/libp2p-logo.png" alt="libp2p logo"/>
|
||||
</h1>
|
||||
|
||||
<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="http://webchat.freenode.net/?channels=%23libp2p"><img src="https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square" /></a>
|
||||
<a href="https://waffle.io/libp2p/libp2p"><img src="https://img.shields.io/badge/pm-waffle-yellow.svg?style=flat-square" /></a>
|
||||
|
||||
> This document presents `libp2p`, a modularized and extensible network stack to overcome the networking challenges faced when doing peer-to-peer applications. `libp2p` is used by IPFS as its networking library.
|
||||
|
||||
Authors:
|
||||
|
||||
- [Juan Benet](https://github.com/jbenet)
|
||||
- [David Dias](https://github.com/daviddias)
|
||||
|
||||
Reviewers:
|
||||
|
||||
- `N/A`
|
||||
|
||||
## Abstract
|
||||
|
||||
This describes the [IPFS](https://ipfs.io/) network protocol. The network layer provides point-to-point transports (reliable and unreliable) between any two IPFS nodes in the network.
|
||||
|
||||
This document defines the spec implemented in `libp2p`.
|
||||
|
||||
## Status of this spec 
|
||||
|
||||
## Organization of this document
|
||||
|
||||
This RFC is organized by chapters described on the *Table of contents* section. Each of the chapters can be found in its own file.
|
||||
|
||||
## Table of contents
|
||||
|
||||
- [1 Introduction](1-introduction.md)
|
||||
- [1.1 Motivation](1-introduction.md#11-motivation)
|
||||
- [1.2 Goals](1-introduction.md#12-goals)
|
||||
- [2 An analysis the state of the art in network stacks](2-state-of-the-art.md)
|
||||
- [2.1 The client-server model](2-state-of-the-art.md#21-the-client-server-model)
|
||||
- [2.2 Categorizing the network stack protocols by solutions](2-state-of-the-art.md#22-categorizing-the-network-stack-protocols-by-solutions)
|
||||
- [2.3 Current shortcomings](2-state-of-the-art.md#23-current-shortcomings)
|
||||
- [3 Requirements](3-requirements.md)
|
||||
- [3.1 Transport agnostic](3-requirements.md#34-transport-agnostic)
|
||||
- [3.2 Multi-multiplexing](3-requirements.md#35-multi-multiplexing)
|
||||
- [3.3 Encryption](3-requirements.md#33-encryption)
|
||||
- [3.4 NAT traversal](3-requirements.md#31-nat-traversal)
|
||||
- [3.5 Relay](3-requirements.md#32-relay)
|
||||
- [3.6 Enable several network topologies](3-requirements.md#36-enable-several-network-topologies)
|
||||
- [3.7 Resource discovery](3-requirements.md#37-resource-discovery)
|
||||
- [3.8 Messaging](3-requirements.md#38-messaging)
|
||||
- [3.9 Naming](3-requirements.md#38-naming)
|
||||
- [4 Architecture](4-architecture.md)
|
||||
- [4.1 Peer Routing](4-architecture.md#41-peer-routing)
|
||||
- [4.2 Swarm](4-architecture.md#42-swarm)
|
||||
- [4.3 Distributed Record Store](4-architecture.md#43-distributed-record-store)
|
||||
- [4.4 Discovery](4-architecture.md#44-discovery)
|
||||
- [4.5 Messaging](4-architecture.md#45-messaging)
|
||||
- [4.5.1 PubSub](4-architecture.md#451-pubsub)
|
||||
- [4.6 Naming](4-architecture.md#46-naming)
|
||||
- [4.6.1 IPRS](4-architecture.md#461-iprs)
|
||||
- [4.6.2 IPNS](4-architecture.md#462-ipns)
|
||||
- [5 Data structures](5-datastructures.md)
|
||||
- [6 Interfaces](6-interfaces.md)
|
||||
- [6.1 libp2p](6-interfaces.md#61-libp2p)
|
||||
- [6.1 Transport](6-interfaces.md)
|
||||
- [6.2 Connection](6-interfaces.md)
|
||||
- [6.3 Stream Multiplexer](6-interfaces.md)
|
||||
- [6.3 Swarm](6-interfaces.md#63-swarm)
|
||||
- [6.5 Peer Discovery](6-interfaces.md#65-peer-discovery)
|
||||
- [6.2 Peer Routing](6-interfaces.md#62-peer-routing)
|
||||
- [6.2 Content Routing](6-interfaces.md#62-peer-routing)
|
||||
- [6.3.1 Distributed Record Store](6-interfaces.md#64-distributed-record-store)
|
||||
- [6.6 libp2p interface and UX](6-interfaces.md#66-libp2p-interface-and-ux)
|
||||
- [7 Properties](7-properties.md)
|
||||
- [7.1 Communication Model - Streams](7-properties.md#71-communication-model---streams)
|
||||
- [7.2 Ports - Constrained Entrypoints](7-properties.md#72-ports---constrained-entrypoints)
|
||||
- [7.3 Transport Protocol](7-properties.md#73-transport-protocols)
|
||||
- [7.4 Non-IP Networks](7-properties.md#74-non-ip-networks)
|
||||
- [7.5 On the wire](7-properties.md#75-on-the-wire)
|
||||
- [7.5.1 Protocol-Multiplexing](7-properties.md#751-protocol-multiplexing)
|
||||
- [7.5.2 multistream - self-describing protocol stream](7-properties.md#752-multistream---self-describing-protocol-stream)
|
||||
- [7.5.3 multistream-selector - self-describing protocol stream selector](7-properties.md#753-multistream-selector---self-describing-protocol-stream-selector)
|
||||
- [7.5.4 Stream Multiplexing](7-properties.md#754-stream-multiplexing)
|
||||
- [7.5.5 Portable Encodings](7-properties.md#755-portable-encodings)
|
||||
- [7.5.6 Secure Communications](7-properties.md#756-secure-communications)
|
||||
- [8 Implementations](8-implementations.md)
|
||||
- [9 References](9-references.md)
|
||||
|
||||
## Other specs that haven't made to the main document
|
||||
|
||||
- [Relay](/relay)
|
||||
- [PubSub](/pubsub)
|
||||
|
||||
## Contribute
|
||||
|
||||
Please contribute! [Dive into the issues](https://github.com/libp2p/specs/issues)!
|
||||
|
||||
Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
|
||||
|
||||
## License
|
||||
|
||||
[CC-BY-SA 3.0 License](https://creativecommons.org/licenses/by-sa/3.0/us/) © Protocol Labs Inc.
|
||||
Reference in New Issue
Block a user