A Kotlin implementation of the libp2p networking stack.
libp2p is a modular peer-to-peer networking framework that standardizes how peers discover each other, establish secure connections, negotiate protocols, and exchange data.
This project provides an idiomatic Kotlin implementation of libp2p, closely aligned with the reference implementations while favoring explicit design, readability, and correctness.
For a detailed introduction to libp2p concepts, see https://libp2p.io/.
This project is under active development. Not all libp2p components are implemented, and API stability is not guaranteed.
The primary goals are:
- Protocol correctness
- Clear, explicit architecture
- Interoperability with existing libp2p implementations
Non-goals include:
- Feature completeness at all costs
- Aggressive performance optimizations
- Hiding libp2p concepts behind opaque abstractions
(see https://github.com/erwin-kok/multiformat)
- multiaddr
- multibase
- multicodec
- multihash
- multistream-select
- Ed25519
- ECDSA
- Secp256k1
- RSA
- TCP
- QUIC (planned)
- Mplex
- Yamux (planned)
- QUIC (planned)
- Noise
- TLS (planned)
- QUIC (planned)
- Identify
- Ping
- DHT / Kademlia (planned)
- GossipSub (planned)
- mDNS (planned)
- DHT / Kademlia (planned)
- RocksDB
Add the required dependencies:
repositories {
mavenCentral()
}
dependencies {
implementation("org.erwinkok.result:libp2p-xxx:$latest")
}libp2p-core is required. Other modules are optional and can be included depending on the desired feature set.
val hostBuilder = host {
identity(localIdentity)
muxers {
mplex()
}
securityTransport {
noise()
}
transports {
tcp()
}
swarm {
dialTimeout = 10.minutes
listenAddresses {
multiAddress("/ip4/0.0.0.0/tcp/10333")
}
}
datastore(datastore)
}
val host = hostBuilder.build(scope)
.getOrElse {
logger.error { "The following errors occurred while creating the host: ${errorMessage(it)}" }
return@runBlocking
}The configuration explicitly defines the identity, transports, security protocols, and multiplexers used by the host.
host.setStreamHandler(ProtocolId.of("/chat/1.0.0")) {
chatHandler(it)
}When a peer negotiates the /chat/1.0.0 protocol, the corresponding handler is invoked.
val stream = host.newStream(aPeerId, ProtocolId.of("/chat/1.0.0"))
.getOrElse {
logger.error { "Could not open chat stream with peer: ${errorMessage(it)}" }
return
}
chatHandler(stream)This establishes a connection to the peer (if needed) and opens a new stream for the requested protocol.
A simple chat example is available in examples/chat.
When started, the application logs the listening address, for example:
./chat -d /ip4/0.0.0.0/tcp/10333/p2p/12D3KooWDfaEJxpmjbFLb9wUakCd6Lo6LRntaV3drb4EaYZRtYuYThis address can be used by other libp2p implementations, including go-libp2p, to connect to the node.
This project is heavily inspired by the reference go-libp2p implementation.
Many design decisions and protocol details are derived from their work. Credit goes to the go-libp2p authors for laying the foundation of the libp2p ecosystem.
See also ACKNOWLEDGEMENTS
This project is licensed under the BSD-3-Clause license, see LICENSE file for more details.
