libp2p implementation in Nim https://status-im.github.io/nim-libp2p/docs/
Go to file
Dmitriy Ryajov e623e70e7b
PubSub (Gossip & Flood) Implementation (#36)
This adds gossipsub and floodsub, as well as basic interop testing with the go libp2p daemon. 

* add close event

* wip: gossipsub

* splitting rpc message

* making message handling more consistent

* initial gossipsub implementation

* feat: nim 1.0 cleanup

* wip: gossipsub protobuf

* adding encoding/decoding of gossipsub messages

* add disconnect handler

* add proper gossipsub msg handling

* misc: cleanup for nim 1.0

* splitting floodsub and gossipsub tests

* feat: add mesh rebalansing

* test pubsub

* add mesh rebalansing tests

* testing mesh maintenance

* finishing mcache implementatin

* wip: commenting out broken tests

* wip: don't run heartbeat for now

* switchout debug for trace logging

* testing gossip peer selection algorithm

* test stream piping

* more work around message amplification

* get the peerid from message

* use timed cache as backing store

* allow setting timeout in constructor

* several changes to improve performance

* more through testing of msg amplification

* prevent gc issues

* allow piping to self and prevent deadlocks

* improove floodsub

* allow running hook on cache eviction

* prevent race conditions

* prevent race conditions and improove tests

* use hashes as cache keys

* removing useless file

* don't create a new seq

* re-enable pubsub tests

* fix imports

* reduce number of runs to speed up tests

* break out control message processing

* normalize sleeps between steps

* implement proper transport filtering

* initial interop testing

* clean up floodsub publish logic

* allow dialing without a protocol

* adding multiple reads/writes

* use protobuf varint in mplex

* don't loose conn's peerInfo

* initial interop pubsub tests

* don't duplicate connections/peers

* bring back interop tests

* wip: interop

* re-enable interop and daemon tests

* add multiple read write tests from handlers

* don't cleanup channel prematurely

* use correct channel to send/receive msgs

* adjust tests with latest changes

* include interop tests

* remove temp logging output

* fix ci

* use correct public key serialization

* additional tests for pubsub interop
2019-12-05 20:16:18 -06:00
examples PubSub (Gossip & Flood) Implementation (#36) 2019-12-05 20:16:18 -06:00
libp2p PubSub (Gossip & Flood) Implementation (#36) 2019-12-05 20:16:18 -06:00
tests PubSub (Gossip & Flood) Implementation (#36) 2019-12-05 20:16:18 -06:00
.appveyor.yml Fix Appveyor problems with go-lang bug. 2019-10-07 21:56:08 +03:00
.gitignore misc: cleanup mplex 2019-10-11 08:15:24 +09:00
.travis.yml CI: always use the go-libp2p-daemon HEAD 2019-08-26 16:40:25 +02:00
LICENSE Initial commit 2018-11-19 03:58:31 +02:00
LICENSE-APACHEv2 Initialize travis and licenses. 2018-11-19 04:04:47 +02:00
LICENSE-MIT Initialize travis and licenses. 2018-11-19 04:04:47 +02:00
README.md fix typo in readme 2019-11-06 12:19:55 -06:00
libp2p.nim Fix varint import 2019-08-16 12:36:54 +02:00
libp2p.nimble PubSub (Gossip & Flood) Implementation (#36) 2019-12-05 20:16:18 -06:00

README.md

nim-libp2p

Build Status Build status License: Apache License: MIT Stability: experimental

Introduction

Running against the Go daemon

An implementation of libp2p in Nim, as a wrapper of the Libp2p Go daemon.

Note that you need Go 1.12+ for the below instructions to work!

Install dependencies and run tests with:

git clone https://github.com/status-im/nim-libp2p && cd nim-libp2p
nimble install
nimble test
git submodule update --init --recursive
go version
git clone https://github.com/libp2p/go-libp2p-daemon
cd go-libp2p-daemon
git checkout v0.0.1
go install ./...
cd ..

Try out the chat example:

nim c -r --threads:on examples\chat.nim

This will output a peer ID such as QmbmHfVvouKammmQDJck4hz33WvVktNEe7pasxz2HgseRu which you can use in another instance to connect to it.

./example/chat
/connect QmbmHfVvouKammmQDJck4hz33WvVktNEe7pasxz2HgseRu

You can now chat between the instances!

Chat example

API

Coming soon...

Experimental native implementation

The native Nim libp2p implementation has finally arrived. Currently, it's support is experimental and shouldn't be relied on for production use. It is however under active development and we hope to achieve a reasonable level of stability in the upcoming months, as we will be integrating it across our own set of products, such as the Nim Beacon Chain.

What to expect?

This implementation has a bare minimum set of components in order to provide a functional and interoperable libp2p stack. These are:

  • A TCP transport
  • multistream-select
  • Secio
  • Mplex
  • Identify
  • FloodSub (with gossipsub being added in the near future)

This stack reflects the minimal requirements for the upcoming Eth2 implementation.

How to try it out?

To run it, add nim-libp2p to your project's nimble file and spawn a node as follows:

import tables, options
import chronos, chronicles
import ../libp2p/[switch, 
                  multistream,
                  protocols/identify, 
                  connection,
                  transports/transport, 
                  transports/tcptransport,
                  multiaddress, 
                  peerinfo,
                  crypto/crypto, 
                  peer,
                  protocols/protocol, 
                  muxers/muxer,
                  muxers/mplex/mplex, 
                  muxers/mplex/types,
                  protocols/secure/secio,
                  protocols/secure/secure]

const TestCodec = "/test/proto/1.0.0" # custom protocol string

type
  TestProto = ref object of LPProtocol # declare a custom protocol

method init(p: TestProto) {.gcsafe.} =
  # handle incoming connections in closure
  proc handle(conn: Connection, proto: string) {.async, gcsafe.} = 
    let msg = cast[string](await conn.readLp())
    echo "Got from remote - ", cast[string](msg)
    await conn.writeLp("Hello!")
    await conn.close()

  p.codec = TestCodec # init proto with the correct string id
  p.handler = handle # set proto handler

proc createSwitch(ma: MultiAddress): (Switch, PeerInfo) =
  ## Helper to create a swith

  let seckey = PrivateKey.random(RSA) # use a random key for peer id
  var peerInfo: PeerInfo
  peerInfo.peerId = some(PeerID.init(seckey)) # create a peer id and assign
  peerInfo.addrs.add(ma) # set this peer's multiaddresses (can be any number)

  let identify = newIdentify(peerInfo) # create the identify proto

  proc createMplex(conn: Connection): Muxer =
    # helper proc to create multiplexers, 
    # use this to perform any custom setup up,
    # such as adjusting timeout or anything else 
    # that the muxer requires
    result = newMplex(conn)

  let mplexProvider = newMuxerProvider(createMplex, MplexCodec) # create multiplexer
  let transports = @[Transport(newTransport(TcpTransport))] # add all transports (tcp only for now, but can be anything in the future)
  let muxers = [(MplexCodec, mplexProvider)].toTable() # add all muxers
  let secureManagers = [(SecioCodec, Secure(newSecio(seckey)))].toTable() # setup the secio and any other secure provider

  # create the switch
  let switch = newSwitch(peerInfo, 
                         transports, 
                         identify, 
                         muxers, 
                         secureManagers)
  result = (switch, peerInfo)

proc main() {.async, gcsafe.} =
  let ma1: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
  let ma2: MultiAddress = Multiaddress.init("/ip4/0.0.0.0/tcp/0")
  
  var peerInfo1, peerInfo2: PeerInfo
  var switch1, switch2: Switch
  (switch1, peerInfo1) = createSwitch(ma1) # create node 1

  # setup the custom proto
  let testProto = new TestProto
  testProto.init() # run it's init method to perform any required initialization
  switch1.mount(testProto) # mount the proto
  var switch1Fut = await switch1.start() # start the node

  (switch2, peerInfo2) = createSwitch(ma2) # create node 2
  var switch2Fut = await switch2.start() # start second node
  let conn = await switch2.dial(switch1.peerInfo, TestCodec) # dial the first node

  await conn.writeLp("Hello!") # writeLp send a lenght prefixed buffer over the wire
  let msg = cast[string](await conn.readLp()) # readLp reads lenght prefixed bytes and returns a buffer without the prefix
  echo "Remote responded with - ", cast[string](msg)

  await allFutures(switch1.stop(), switch2.stop()) # close connections and shutdown all transports
  await allFutures(switch1Fut & switch2Fut) # wait for all transports to shutdown

waitFor(main())

For a more complete example, checkout the directchat.nim example in the examples directory.

License

Licensed and distributed under either of

or

at your option. This file may not be copied, modified, or distributed except according to those terms.