🌳 ts-hashgraph
Demo | Video Tutorial | Paper
ts-hashgraph
is an implementation of the Swirlds Hashgraph Consensus Algorithm (view the whitepaper) written in TypeScript.
This project is a work-in-progress and does not completely work as suggested by this document. Parts of the system work as suggested, other parts are still being worked on.
About
Hashgraph is an algorithm and data structure that solves the problem of distributed consensus. The algorithm achieves this using 2 novel methods termed "Gossip about Gossip" and "Virtual Voting" coined by the inventor of the Hashgraph, Dr. Leemon Baird.
Gossip about Gossip refers to using a gossip protocol amongst connected peers in a network. Instead of gossiping the transactions alone, each peer gossips additional information about how the peers are gossiping to one another.
Virtual Voting allows peers to calculate the order in which transactions reached the majority, at least ⅔, of the community. By using the additional information about how peers gossip, this voting mechanism avoids the heavy bandwidth requirements peers would otherwise need to determine the consensus order of transactions.
Benefits
- 🏎️ Fast: Near-perfect efficiency in bandwidth usage and consequently can process hundreds of thousands of transactions per second in a single shard
- 🤝 Fair: The actual order transactions are received by the community will be reflected in the consensus order. ie. Fair access and ordering
- 🔐 Secure: Achieves the gold standard for security in the field of distributed consensus: asynchronous Byzantine Fault Tolerance (aBFT)
Features
- 🌎 Sharding: Distribute consensus state across multiple shared-worlds/shards
- 🔎 State Proofs: Uniquely identify shards to avoid state forks/splits (WIP)
- 🕸️ Network Agnostic: Gossip events through any network protocol (ie. WebRTC, WebSocket, HTTP, etc.)
- 🚀 Multi-threaded: Employs web workers to free the main thread from the heavy computations associated with Virtual Voting (WIP)
- 👾 GPU-accelerated: Uses WebGL or WebGPU for hardware-accelerated cryptogprahy (WIP)
- ⚛️ Post-Quantum Security: Cryptographic resistance to quantum attacks using SHA-284 hashing (WIP)
- ⚖️ Proof-of-Stake Support: Optionally, weight the votes of members to resist sybil attacks (WIP)
- 🔄 Auto-updates: Synchronously update transaction code (WIP)
- 📊 Visualizer: Optionally, visualize the real-time gossip traffic on a deployed hashgraph network
Limitations
- 🧪 Experimental: This project is a work-in-progress
- 🕵️ Less than ⅓ dishonest: Distributed consensus requires at least ⅔ of shard participants to be honest (ie. untampered code and working hardware)
Additional Notes
- 🕵️ Less than ⅓ dishonest: ⅔ of members being honest is also the theoretical minimum requirement to achieve distributed consensus
Progress Report
See the to-do list for a progress report on remaining tasks.
Browser Compatibility
ts-hashgraph supports all browsers that are ES5-compliant (IE8 and below are not supported).
Screenshots
Explore the public demo or visit the test/visual
directory to run the visualizer locally.
Example w/ 3 Members | Example w/ 4 Members |
---|---|
Installation
Install the library
npm install ts-hashgraph --save
Import the library
Or import the browser script
Example Usecases
For working demos that use this library, please visit the examples directory.
To run the following examples, take these steps:
Copy and paste
the code in 2 code environments (for example, 2 codepen browser tabs)- Replace the peerID from
'alice'
to'bob'
in the second code environment
🏓 A Distributed Game of Pong
Keyboard controls: Press W
to move ↑ and S
to move ↓
Expand code details
Hashgraph Example - A Distributed Game of Pong
🛍 ️A Distributed Shopping Mall
Keyboard controls: Press A
to add inventory and P
to make a purchase
Expand code details
Hashgraph Example - A Distributed Shopping Mall
API Reference
new TsHashgraph.SharedWorld
new TsHashgraph.SharedWorld([shardID])
const shard =
shardID
String. The ID of the hashgraph shard. Defaults to'hashgraph'
.
Create a new hashgraph shard.
shard.startAutoSync
shard.startAutoSync()
shard
- Returns void.
Start automatically syncing with peers at 1 sync per second. Use setSyncTickRate
to change the frequency of syncs.
shard.startAutoSync
shard.stopAutoSync()
shard
- Returns void.
Stop automatically syncing with peers.
shard.setSyncTickRate
shard.setSyncTickRate(tickRate)
shard // 1000 milliseconds per auto-sync
tickRate
Number. The number of milliseconds between automatic syncs (gossip + virtual voting). Defaults to1000
milliseconds (ie. 1 sync per second).- Returns void.
Set the frequency of automatically synchronizing with connected peers.
shard.manualSync
shard.manualSync([targetPeerID])
await shard
targetPeerID
String. PeerID or public key of the target to send gossip to.- Returns Promise<void>.
Manually sync with peers. Syncing involves (1) gossiping events and (2) calculating the events' order. Use startAutoSync()
to automatically sync with peers.
shard.onSendGossip
shard.onSendGossip(callback)
shard
callback
Function. A function that sends data to a connected peer.targetPeerID
String. The ID of the peer to send the events to. Defaults to the public key of the peer if peerID isn't specified.syncEventList
HashgraphEvent[]. A list of hashgraph events that the target peer/member may not know about yet.- Returns Promise<void>|void.
- Returns void.
Send the syncEventList to the member with targetPeerID.
Note: Use your preferred transport protocol (ie. HTTP, WebSocket, WebRTC, etc.) to communicate with peers.
shard.sendGossip
shard.sendGossip([targetPeerID])
await shard
targetPeerID
String. PeerID or public key of the target peer to send gossip to.- Returns Promise<void>.
Manually gossip to connected peers. Use startAutoSync()
to automatically send gossip.
shard.receiveGossip
shard.receiveGossip(syncEventList)
await shard
syncEventList
HashgraphEvent[]. A list of hashgraph events that the current peer may not know about yet.- Returns Promise<void>.
Receive the other parent event and sync event list.
shard.setElapsedTimeToDeleteEventHistory
shard.setElapsedTimeToDeleteEventHistory(elapsedTime)
shard // 60 second delay before deleting event history
elapsedTime
Number. The time to wait before deleting event history. Measured in seconds. Defaults to20
.- Returns void.
Set the time to wait before deleting event history.
shard.onAddMember
shard.onAddMember(callback)
shard // Vote to allow anyone to join the shard
callback
Function. A function used to vote on whether to add a candidate member to the shard.candidateMember
Object.publicKey
: String. The cryptographic public key used internally to validate transactions by members.peerID
: String. The optional peerID of the candidate member to add.peerConnectionMap
: Object<String, Boolean>. A map from the public keys of the existing shard members to whether the candidate will establish a connection to the respective member upon being accepted to join the shard.details
: Any. Optional additional data that can be used for determining a vote.
- Returns Promise<boolean>|boolean. Returns the vote to allow or disallow the candidate into the shard.
- Returns Promise<void>|void.
Vote to add a candidate to the shard.
shard.onRemoveMember
shard.onRemoveMember(callback)
shard // Vote to remove non-interesting members from the shard
callback
Function. A function used to vote on whether to remove a candidate member from the shard.candidateMember
Object.- Returns Promise<boolean>|boolean. Returns the vote to allow or disallow the candidate from the shard.
- Returns void.
Vote to remove a candidate from the shard.
shard.addMember
shard.addMember([peerID, isSelf, isConnectedPeer, candidateMember, skipVoting])
await shard // On Alice's computer
peerID
String. The ID of the peer.isSelf
Boolean. Set to true to initialize the self peer. Defaults tofalse
.isConnectedPeer
Boolean. Set to true if the self peer communicates directly to the peerID peer through the preferred protocol. Defaults tofalse
.candidateMember
Object.publicKey
: String (Required). The cryptographic public key used internally to validate transactions by members.peerID
: String. The optional peerID of the candidate member to add.peerConnectionMap
: Object<String, Boolean>. A map from the public keys of the existing shard members to whether the candidate will establish a connection to the respective member upon being accepted to join the shard.details
: Any. Optional data for sharing with current members to use when voting for whether to add the candidate to the shard.
skipVoting
Boolean. A flag used to skip the transaction-based voting to add the candidate member to the shard. Defaults tofalse
.- Returns Promise<String>. Returns the public key of the member that's been added.
Add a member to the hashgraph shard.
shard.removeMember
shard.removeMember(candidateMember [, skipVoting])
shard
candidateMember
Object.skipVoting
Boolean. A flag used to skip the transaction-based voting to remove the candidate member from the shard. Defaults tofalse
.- Returns void.
Remove a member from the hashgraph shard.
shard.setMinimumVotePercentToAddMember
shard.setMinimumVotePercentToAddMember(callback)
shard // Require 100 percent (unanimous) approval by current members to add a member
callback
Function. A function used to set the percent of yes votes required by current members to add a new member.candidateMember
Object.- Returns Promise<number>|number. Returns the percent.
- Returns void.
Set the percent of yes votes required by the current shard members to add a new member to the shard.
shard.setMinimumVotePercentToRemoveMember
shard.setMinimumVotePercentToRemoveMember(callback)
shard // Require 80 percent approval by current members to remove a member
callback
Function. A function used to set the percent of yes votes required by current members to remove an existing member.candidateMember
Object.- Returns Promise<number>|number. Returns the percent.
- Returns void.
Set the percent of yes votes required by the current shard members to remove an existing member from the shard.
shard.onMemberUpdate
shard.onMemberUpdate(callback)
shard
callback
Function. A function used to be notified of member updates (ie. added or removed members).member
Object.updateType
String. A description of the update; eitheradded
orremoved
.- Returns void.
- Returns void.
Set a callback function to be notified of when a member is added or removed from the hashgraph shard.
shard.getMemberPublicKey
shard.getMemberPublicKey(peerID)
await shard // On Bob's computer const bobPublicKey = shard // Send bob's public key to alice, then..await shard // On Alice's computer
peerID
String. The ID of the peer.- Returns String.
Retrieve the public key of a member.
Note: Send the public key of the current peer to participating peers in the hashgraph shard.
shard.getMemberList
shard.getMemberList()
const memberList = shard
- Returns Array<{ publicKey: String, peerID?: String }>.
Retrieve the public key and peerIDs of all members of the shard.
Note: Send the list to newly added members of the shard.
shard.onTransactionOrder
shard.onTransactionOrder(callback)
shard
callback
Function. A callback function used to apply a list of transactions to a state object.previousState
Object. A copy of the previous consensus state.transactionList
Array<{ timestamp: Date, payload: Any }>. A list of messages received from the shard.isConsensusOrder
Boolean. A flag determining whether the transactionList is in the consensus order. If you want to act on transactions as soon as they arrive, you don't need to check this value.- Returns Promise<void>|void.
- Returns void.
Receive transaction list.
shard.sendTransaction
shard.sendTransaction(transaction)
shard
transaction
Any. A message or payload to be sent to the hashgraph shard.- Returns void.
Send a transaction.
shard.determineTransactionOrder
shard.determineTransactionOrder()
await shard
- Returns Promise<void>.
Manually determine the order of transactions (ie. perform virtual voting on recently added events). Use startAutoSync()
to automatically determine transaction order.
shard.getState
shard.getState()
const state = shard
- Returns Object<String, Any>.
Retrieve the consensus state from the hashgraph shard.
Documentation
To check out project-related documentation, please visit docs. See metrics for performance-related documentation.
Contributing
Everyone can contribute. All are welcome. Please see contributing guide.
Acknowledgements
In general, thanks to the many people who contribute to the open ecosystem. In particular, thanks to Dr. Leemon Baird for being a genius and sharing his discovery.
Software Dependencies
Tooling | Encryption | Hashing |
---|---|---|
TypeScript | elliptic | object-hash |
tombstone (WIP) |
Contemporary Visionaries
These are a few individuals that we believe are inspiring sources for anyone looking to apply technical solutions to improving the human condition for everyone on earth.
Name | Profession | Life work |
---|---|---|
Jacque Fresco | Sociocyberneering | Venus Project, Resource Based Economy |
Ted Nelson | Software Design | Xanadu, ZigZag |
Christopher Alexander | Living Architecture | The Nature of Order, A Pattern Language |
Learn More
🕹️ Play with the visualizer
🎬 Watch a video on how to use the visualizer
🎬 Watch a video on how to use this library
🎬 Watch a video on how this library is made
🎬 Watch a video on how hashgraph works
📜 Read the hashgraph whitepaper
Related Work
Some well-known distributed consensus data structures include: Blockchain, Tangle, Holochain, Hashgraph
Some well-known distributed consensus algorithms include: Leader-based (Raft, Paxos, Hyperledger, EOS, IOTA), Proof-of-Work (Ethereum, Bitcoin), Economy-based/Proof-of-Stake (Casper, IOTA, EOS, Ouroboros), Voting-based (None in practice), Virtual-Voting (Hashgraph)
License
MIT