{"id":13509855,"url":"https://github.com/nknorg/nnet","last_synced_at":"2026-02-12T06:40:21.642Z","repository":{"id":37432191,"uuid":"152678018","full_name":"nknorg/nnet","owner":"nknorg","description":"nnet: a fast, scalable, and developer-friendly p2p overlay network stack","archived":false,"fork":false,"pushed_at":"2025-05-31T05:03:51.000Z","size":328,"stargazers_count":128,"open_issues_count":1,"forks_count":36,"subscribers_count":19,"default_branch":"master","last_synced_at":"2025-05-31T16:49:47.454Z","etag":null,"topics":["decentralized","distributed-systems","golang","network","p2p"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nknorg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-10-12T01:41:50.000Z","updated_at":"2025-05-31T05:03:55.000Z","dependencies_parsed_at":"2025-05-31T06:27:29.847Z","dependency_job_id":"062fcfb0-91f3-4b21-aefe-402fb1c77f98","html_url":"https://github.com/nknorg/nnet","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nknorg/nnet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nknorg%2Fnnet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nknorg%2Fnnet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nknorg%2Fnnet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nknorg%2Fnnet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nknorg","download_url":"https://codeload.github.com/nknorg/nnet/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nknorg%2Fnnet/sbom","scorecard":{"id":690272,"data":{"date":"2025-08-11","repo":{"name":"github.com/nknorg/nnet","commit":"69b4966af018c85e4d9a63a633a3cc549a9617f2"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.9,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":1,"reason":"1 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":1,"reason":"Found 2/19 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":7,"reason":"3 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2024-3333","Warn: Project is vulnerable to: GO-2025-3503 / GHSA-qxp5-gwg8-xv66","Warn: Project is vulnerable to: GO-2025-3595 / GHSA-vvgc-356p-c3xw"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T02:09:39.497Z","repository_id":37432191,"created_at":"2025-08-22T02:09:39.497Z","updated_at":"2025-08-22T02:09:39.497Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29360644,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-12T01:03:07.613Z","status":"online","status_checked_at":"2026-02-12T02:00:06.911Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["decentralized","distributed-systems","golang","network","p2p"],"created_at":"2024-08-01T02:01:14.893Z","updated_at":"2026-02-12T06:40:21.624Z","avatar_url":"https://github.com/nknorg.png","language":"Go","funding_links":[],"categories":["Go","p2p"],"sub_categories":[],"readme":"# nnet: a fast, scalable, easy-to-use p2p network stack\n\n[![GoDoc](https://godoc.org/github.com/nknorg/nnet?status.svg)](https://godoc.org/github.com/nknorg/nnet) [![GitHub license](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE) [![Go Report Card](https://goreportcard.com/badge/github.com/nknorg/nnet)](https://goreportcard.com/report/github.com/nknorg/nnet) [![Build Status](https://travis-ci.org/nknorg/nnet.svg?branch=master)](https://travis-ci.org/nknorg/nnet) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](#contributing)\n\n## Introduction\n\n**nnet** is a fast, scalable, and developer-friendly network stack/layer for\ndecentralized/distributed systems. It handles message delivery, topology\nmaintenance, etc in a highly efficient and scalable way, while providing enough\ncontrol and flexibility through developer-friendly messaging interface and\npowerful middleware architecture.\n\n## Features\n\n- nnet uses a **modular and layered overlay architecture**. By default an\n  improved and much more reliable version of Chord DHT protocol is used to\n  maintain a scalable overlay topology, while other topologies like Kademlia can\n  be easily added by implementing a few overlay interfaces.\n\n- Highly efficient messaging implementation that is able to send, receive and\n  handle ~**75k messages/s** or ~**1 GB/s** of messages on a 2-core personal\n  laptop.\n\n- Extremely easy to use message sending interface with **both async and sync\n  message flow** (block until reply). Message reply in sync mode are handled\n  efficiently and automatically, you just need to provide the content.\n\n- Deliver message to any node in the network (**not just the nodes you are\n  directly connected to**) reliably and efficiently in at most log_2(N) hops\n  (w.h.p) where N is the total number of nodes in the network.\n\n- **Novel and highly efficient** message broadcasting algorithm with exact once\n  (or K-times where K is something adjustable) message sending that achieves\n  **optimal throughput and near-optimal latency**. This is done by sending\n  message through the spanning tree constructed by utilizing the Chord topology.\n\n- **Powerful and flexible middleware architecture** that allows you to easily\n  interact with node/network lifecycle and events like topology change, routing,\n  message sending and delivery, etc. **Applying a middleware is as simple as\n  providing a function**.\n\n- Flexible **transport-aware address scheme**. Each node can choose its own\n  transport protocol to listen to, and nodes with different transport protocol\n  can communicate with each other transparently. nnet supports TCP and\n  [KCP](https://github.com/skywind3000/kcp/blob/master/README.en.md) transport\n  layer by default. Other transport layers can be easily supported by\n  implementing a few interfaces.\n\n- **Modular and extensible router architecture**. Implementing a new routing\n  algorithm is as simple as adding a router that implements a few router\n  interfaces.\n\n- Only **a fixed number of goroutines and connections** will be created given\n  network size, and the number can be changed easily by changing the number of\n  concurrent workers.\n\n- **NAT traversal** (UPnP and NAT-PMP) using middleware.\n\n- Use protocol buffers for message serialization/deserialization to support\n  cross platform and backward/forward compatibility.\n\n- Provide your own logger for logging integration with your application.\n\nComing soon:\n\n- [x] Latency measurement\n- [x] Proximity routing\n- [ ] Test cases\n\n## Usage\n\n### Requirements:\n\n* Go 1.11+\n\n### Install\n\n```bash\ngo get -u -d github.com/nknorg/nnet\n```\n\nIt's recommended to use [Go Modules](https://github.com/golang/go/wiki/Modules)\nto ensure reproducibility of dependencies.\n\n### Basic\n\nAssuming you have imported `github.com/nknorg/nnet`, The bare minimal way to\ncreate a nnet node is simply\n\n```go\nnn, err := nnet.NewNNet(nil, nil)\n```\n\nThis will create a nnet node with random ID and default configuration (listen to\na random port, etc). Starting the node is as simple as\n\n```go\nerr = nn.Start(true) // or false if joining rather than creating\n```\n\nTo join an existing network, simply call `Join` after node has been started\n\n```go\nerr = nn.Join(\"\u003cprotocol\u003e://\u003cip\u003e:\u003cport\u003e\")\n```\n\nPut them together, a local nnet cluster with 10 nodes can be created by just a\nfew lines of code.\n\n```go\nnnets := make([]*nnet.NNet, 10)\nfor i := 0; i \u003c len(nnets); i++ {\n  nnets[i], _ = nnet.NewNNet(nil, nil) // error is omitted here for simplicity\n  nnets[i].Start(i == 0) // error is omitted here for simplicity\n  if i \u003e 0 {\n    nnets[i].Join(nnets[0].GetLocalNode().Addr) // error is omitted here for simplicity\n  }\n}\n```\n\nA complete basic example can be found at\n[examples/basic/main.go](examples/basic/main.go). You can run it by\n\n```bash\ngo run examples/basic/main.go\n```\n\n### Middleware\n\nnnet uses middleware as a powerful and flexible architecture to interact with\nnode/network lifecycle and events such as topology change, routing, message\nsending and delivery, etc. A middleware is just a function that, once hooked,\nwill be called when certain event occurs. Applying a middleware is as simple as\ncalling `ApplyMiddleware` function (or `MustApplyMiddleware` which will panic if\nan error occurs). Let's apply a `node.RemoteNodeReady` middleware that will be\ncalled when a remote node is connected with the local node and exchanged node\ninfo\n\n```go\nerr = nn.ApplyMiddleware(node.RemoteNodeReady{func(remoteNode *node.RemoteNode) bool {\n  fmt.Printf(\"Remote node ready: %v\", remoteNode)\n  return true\n}, 0})\n```\n\nThe number 0 after the function is the middleware priority, which is an int32\ntype number. Different middleware types take different arguments and have\ndifferent return types, but they all share one thing in common: one of their\nreturned value is a boolean indicating whether we should call the next\nmiddleware (of the same type). Multiple middleware of the same type will be\ncalled in the order from highest priority to lowest priority. Middleware with\nthe same priority will be called in the order of being added. They form a\npipeline such that each one can respond to the event with some data, modify data\nthat will be passed to the rest middleware, or decides to stop the data flow.\nFor example, we can randomly reject remote nodes\n\n```go\nnn.MustApplyMiddleware(node.RemoteNodeConnected{func(remoteNode *node.RemoteNode) bool {\n  if rand.Float64() \u003c 0.23333 {\n    remoteNode.Stop(errors.New(\"YOU ARE UNLUCKY\"))\n    return false\n  }\n  return true\n}, 0})\n\nnn.MustApplyMiddleware(node.RemoteNodeConnected{func(remoteNode *node.RemoteNode) bool {\n  log.Infof(\"Only lucky remote node can get here :)\")\n  return true\n}, 0})\n```\n\nnnet internally use middleware with 0 priority to hook up events, e.g. to add\nneighbor to overlay network when a remote node is ready. You can make your\nmiddleware to be called earlier or later by choosing higher/lower priority.\n\nMiddleware itself is stateless, but very likely you may need a stateful\nmiddleware for more complex logic. Stateful middleware can be created in a\nvariety ways without introducing more complex API. One of the simplest ways is\njust calling a method in the middleware. As a conceptual example\n\n```go\ncoolObj := NewCoolObj()\nnn.MustApplyMiddleware(node.BytesReceived{func(msg, msgID, srcID []byte, remoteNode *node.RemoteNode) ([]byte, bool) {\n  coolObj.DoSomeCoolStuff(msg)\n  return msg, true\n}, 0})\n```\n\nStateful middleware if very powerful and can give you almost full control of the\nsystem, and it can define its own middleware for other components to use.\nActually the whole overlay network can be implemented as a stateful middleware\nthat hooked into a few places like `node.LocalNodeWillStart`. We didn't choose\nto do it because overlay network is a top-level type in nnet, but there is\nnothing that prevent you to do it.\n\nThere are lots of middleware types that can be (and should be) used to listen to\nand control topology change, message routing and handling, etc. Some of them\nprovide convenient shortcuts while some provide detailed low level control.\nCurrently middleware type declaration are distributed in a few places:\n\n- [node/middleware.go](node/middleware.go)\n\n- [overlay/middleware.go](overlay/middleware.go)\n\n- [overlay/chord/middleware.go](overlay/chord/middleware.go)\n\n- [overlay/routing/middleware.go](overlay/routing/middleware.go)\n\nMiddleware architecture is very flexible and new type of middleware can be added\neasily without breaking existing code. Feel free to [open an\nissue](https://github.com/nknorg/nnet/issues/new) if you feel the need for new\nmiddleware type.\n\nA complete middleware example can be found at\n[examples/middleware/main.go](examples/middleware/main.go). You can run it\nby\n\n```bash\ngo run examples/middleware/main.go\n```\n\nAlso, examples like [examples/message/main.go](examples/message/main.go) and\n[examples/efficient-broadcast/main.go](examples/efficient-broadcast/main.go)\nuse middleware to handle and count messages.\n\n### Sending and Receiving Messages\n\nSending message is top-level function in nnet. You can send arbitrary bytes to\nany other node/nodes by calling one of `.SendXXX` methods. Currently there are 3\ntypes of user-defined message classified by routing types:\n\n- Direct: message will be sent to a remote node that has a direct connection\n  with you.\n\n- Relay: message will be routed and delivered to the node with a certain ID, or\n  the node whose ID is closest to the destination ID, typically not directly\n  connected with you. Relay message is routed using DHT topology.\n\n- Broadcast: message will be routed and delivered to every node in the network,\n  not just the nodes you are directly connected to.\n\nThe broadcast message has a few subtypes:\n\n- Push message that use simple flooding/gossip protocol and try to send message\n  to every neighbors. Each node will receive the same message C times where C is\n  its neighbor count. **Push message is optimal in terms of latency and\n  robustness and is ideal for small piece of important message** (like votes in\n  consensus).\n\n- Pull message that use push message to send message hash first. Node receiving\n  a message hash and do not have the message itself will pull the message from\n  the neighbor that sent it the hash. Each node will receive the same message\n  hash C times but will only receive the message itself once, with a round trip\n  delay added for each hop. **Pull message is optimal in terms of bandwidth and\n  robustness and is ideal for large piece of important message** (like blocks in\n  blockchain). (to be implemented)\n\n- Tree message that send the message through the spanning tree constructed by\n  the Chord topology. Each node will only receive the same message K times where\n  K is adjustable and can be as small as 1. **Tree message is optimal in terms\n  of both bandwidth and latency but is less robust, and is ideal for small piece\n  of not-that-important information** (like transactions in blockchain).\n\nnnet uses router architecture such that implementing a new routing algorithm is\nas simple as implementing a `Router` interface defined in\n[routing/routing.go](routing/routing.go) that computes the next hop using\n`GetNodeToRoute` method and register the routing type by calling\n`localNode.RegisterRoutingType` if needed.\n\nFor each routing types, there are 2 sending message APIs: **async** where send\ncall is immediately returned if send success, and **sync** that will be blocked\nand wait for reply or timeout before return. Under the hood, sync mode creates a\nreply channel and waits for the message that replies to the original message ID\nso you can safely use it while sending/receiving other messages at the same\ntime.\n\nSending an async message is straightforward. Let's send a relay message as an\nexample:\n\n```go\nsuccess, err := nn.SendBytesRelayAsync([]byte(\"Hello world!\"), destID)\n```\n\nYou can choose to send the message in sync way such that the function call will\nonly return after receiving the reply or timeout:\n\n```go\nreply, senderID, err := nn.SendBytesRelaySync([]byte(\"Hello world!\"), destID)\n```\n\nTo handle received message and send back reply message, we can use the\n`node.BytesReceived` middleware together with `SendBytesRelayReply` method.\n\n```go\nnn.MustApplyMiddleware(node.BytesReceived{func(msg, msgID, srcID []byte, remoteNode *node.RemoteNode) ([]byte, bool) {\n  nn.SendBytesRelayReply(msgID, []byte(\"Well received!\"), srcID) // error is omitted here for simplicity\n  return msg, true\n}, 0})\n```\n\nA complete message example can be found at\n[examples/message/main.go](examples/message/main.go). You can run it\nby\n\n```bash\ngo run examples/message/main.go\n```\n\nThere is another example\n[examples/efficient-broadcast/main.go](examples/efficient-broadcast/main.go)\nthat counts and compares the received message count for push and tree broadcast\nmessage. You will see how tree message can reduce the bandwidth usage by an\norder of magnitude. You can run it by\n\n```bash\ngo run examples/efficient-broadcast/main.go\n```\n\n### Transport protocol\n\nTransport layer is a separate layer that is part of a node in nnet. Each node\ncan independently choose what transport protocol it listens to, and is able to\ntalk to nodes that listen to different transport protocol as long as the\ncorresponding transport layer is implemented. Each node address starts with the\ntransport protocol that the node listens to, e.g. `tcp://127.0.0.1:23333`, such\nthat other nodes know what protocol to use when talking to it.\n\nCurrently nnet have 2 transport protocol implemented: TCP and\n[KCP]((https://github.com/skywind3000/kcp/blob/master/README.en.md)) (a reliable\nlow-latency protocol based on UDP). In theory, any other reliable protocol can\nbe easily integrated by implementing `Dial` and `Listen` interface. Feel free to\n[open an issue](https://github.com/nknorg/nnet/issues/new) if you feel the need\nfor new transport protocol.\n\nChanging transport protocol is as simple as changing the `Transport` value in\nconfig when creating nnet. A complete example can be found at\n[examples/mixed-protocol/main.go](examples/mixed-protocol/main.go). You can run\nit by\n\n```bash\ngo run examples/mixed-protocol/main.go\n```\n\n### NAT Traversal\n\nIf you are developing an application that is open to public, it is very likely\nthat you need some sort of NAT traversal since lots of devices are behind NAT at\nthe moment. NAT traversal can be set up in middleware such as\n`overlay.NetworkWillStart` and `node.LocalNodeWillStart`, or anytime before the\nnetwork starts by calling the `SetInternalPort` method of the LocalNode. A\ncomplete NAT example that works for UPnP or NAT-PMP enabled routers can be found\nat [examples/nat/main.go](examples/nat/main.go). You can run it by\n\n```bash\ngo run examples/nat/main.go\n```\n\n### Logger\n\nTypically when you use nnet as the network layer of your application, you\nprobably want it to share the logger with the rest of your application. You can\ndo it by calling `nnet.SetLogger(logger)` method as long as `logger` implements\nthe `Logger` interface defined in [log/log.go](log/log.go). If you don't set it,\nnnet will use [go-logging](github.com/op/go-logging) by default.\n\n## Benchmark\n\nThroughput is a very important metric of the network stack. There are multiple\npotential bottlenecks when we consider throughput, e.g. network i/o, message\nserialization/deserialization, architecture and implementation efficiency. To\nmeasure the throughput, we wrote a simple local benchmark, which can be found at\n[examples/message-benchmark/main.go](examples/message-benchmark/main.go). You\ncan run it with default arguments (2 nodes, 1 KB message size) by\n\n```bash\ngo run examples/message-benchmark/main.go\n```\n\nOn a MacBook Pro 2018 this will give you around 75k message/s per node,\nfar more than enough for most p2p applications.\n\nWhen message size increase, the bottleneck will becomes bandwidth rather than\nmessage count. We can run the benchmark with 1 MB message by\n\n```bash\ngo run examples/message-benchmark/main.go -m 1048576\n```\n\nThis will give you around 900 MB/s per node on the same computer, again far\nmore than enough in typical cases.\n\nThe same benchmark can be used to see how spanning tree broadcasting can greatly\nimprove throughput. We first use the standard push method to broadcast in a\n16-node network:\n\n```bash\ngo run examples/message-benchmark/main.go -n 16 -b push\n```\n\nEach node can only receive around 300 unique message/s. The number is so low\nbecause: 1. we are running all 16 nodes on the same laptop with just 6 cores and\nmore importantly 2. Gossip protocol has a high message redundancy, and in this\nparticular example each node receives the same message 15 times! If we sum them\nup, the total messages being processed are 300*15*15, which is pretty close to\nthe 75k we got in 2-node benchmark. Of course if the overlay topology is fully\nconnected, we don't need Gossip protocol at all, but similar inefficiency will\nhappen once the network size is large enough so that fully connected topology is\nunrealistic.\n\nNow let's change to spanning tree broadcasting:\n\n```bash\ngo run examples/message-benchmark/main.go -n 16 -b tree\n```\n\nNow each node can receive 3k unique messages/s, an order of magnitude boost!\nActually if the benchmark is running on multiple computers with enough network\nresources, each node can again receive around 75k messages/s.\n\n## Who is using nnet\n\n- [NKN](https://github.com/nknorg/nkn): a blockchain-powered decentralized data\n  transmission network that uses nnet as network layer.\n\nWelcome to open a [pull request](https://github.com/nknorg/nkn/pulls) if you\nwant your project using nnet to be listed here. The project needs to be\nmaintained in order to be listed.\n\n## Contributing\n\n**Can I submit a bug, suggestion or feature request?**\n\nYes. Please [open an issue](https://github.com/nknorg/nnet/issues/new) for that.\n\n**Can I contribute patches to NKN project?**\n\nYes, we appreciate your help! To make contributions, please fork the repo, push\nyour changes to the forked repo with signed-off commits, and open a pull request\nhere.\n\nPlease sign off your commit by adding -s when committing:\n\n```shell\ngit commit -s\n```\n\nThis means git will automatically add a line \"Signed-off-by: Name \u003cemail\u003e\" at\nthe end of each commit, indicating that you wrote the code and have the right to\npass it on as an open source patch.\n\n## Community\n\n- [Forum](https://forum.nkn.org/)\n- [Discord](https://discord.gg/c7mTynX)\n- [Telegram](https://t.me/nknorg)\n- [Reddit](https://www.reddit.com/r/nknblockchain/)\n- [Twitter](https://twitter.com/NKN_ORG)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnknorg%2Fnnet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnknorg%2Fnnet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnknorg%2Fnnet/lists"}