Package Exports
- ts-hashgraph
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (ts-hashgraph) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
π³ 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/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 --saveImport the library
import * as TsHashgraph from 'ts-hashgraph'Or import the browser script
<script src="https://unpkg.com/ts-hashgraph@latest/dist/library.js"></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 pastethe 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
<html>
<head>
<title>Hashgraph Example - A Distributed Game of Pong</title>
<script src="https://unpkg.com/ts-hashgraph@latest/dist/library.js"></script>
</head>
<body>
<script>
const peerID = 'alice'
const shard = new TsHashgraph.SharedWorld()
shard.onSendGossip(handleGossip)
shard.onTransactionOrder(handleTransactions)
main()
async function main () {
const myPublicKey = await shard.addMember(null, true)
}
function handleGossip (targetPeerID, syncEventList) {
// send syncEventList to target peer
}
function handleTransactions (previousState, transactionList, isConsensusOrder) {
// handle move paddle transactions
// handle move ball transactions
}
</script>
</body>
</html>π οΈA Distributed Shopping Mall
Keyboard controls: Press A to add inventory and P to make a purchase
Expand code details
<html>
<head>
<title>Hashgraph Example - A Distributed Shopping Mall</title>
<script src="https://unpkg.com/ts-hashgraph@latest/dist/library.js"></script>
</head>
<body>
<script>
const peerID = 'alice'
const shard = new TsHashgraph.SharedWorld()
shard.onSendGossip(handleGossip)
shard.onTransactionOrder(handleTransactions)
main()
async function main () {
const myPublicKey = await shard.addMember(null, true)
}
function handleGossip (targetPeerID, syncEventList) {
// send syncEventList to target peer
}
function handleTransactions (previousState, transactionList, isConsensusOrder) {
// handle add inventory logic transactions
// handle purchase logic transactions
}
</script>
</body>
</html>API Reference
new TsHashgraph.SharedWorldshard.startAutoSyncshard.stopAutoSyncshard.setSyncTickRateshard.manualSyncshard.onSendGossipshard.sendGossipshard.receiveGossipshard.setElapsedTimeToDeleteEventHistoryshard.onAddMembershard.onRemoveMembershard.addMembershard.removeMembershard.setMinimumVotePercentToAddMembershard.setMinimumVotePercentToRemoveMembershard.onMemberUpdateshard.getMemberPublicKeyshard.getMemberListshard.onTransactionOrdershard.sendTransactionshard.determineTransactionOrdershard.getState
new TsHashgraph.SharedWorld([shardID])
const shard = new TsHashgraph.SharedWorld()shardIDString. The ID of the hashgraph shard. Defaults to'hashgraph'.
Create a new hashgraph shard.
shard.startAutoSync()
shard.startAutoSync()- Returns void.
Start automatically syncing with peers at 1 sync per second. Use setSyncTickRate to change the frequency of syncs.
shard.stopAutoSync()
shard.stopAutoSync()- Returns void.
Stop automatically syncing with peers.
shard.setSyncTickRate(tickRate)
shard.setSyncTickRate(1000) // 1000 milliseconds per auto-synctickRateNumber. The number of milliseconds between automatic syncs (gossip + virtual voting). Defaults to1000milliseconds (ie. 1 sync per second).- Returns void.
Set the frequency of automatically synchronizing with connected peers.
shard.manualSync([targetPeerID])
await shard.manualSync()targetPeerIDString. 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(callback)
shard.onSendGossip((targetPeerID, syncEventList) => {
if (targetPeerID === 'alice' || targetPeerID === alicePublicKey) {
// Send syncEventList to 'alice' through your preferred transport protocol
//
// For example:
//
// datachannel_with_alice.send({ eventList: syncEventList })
}
})callbackFunction. A function that sends data to a connected peer.targetPeerIDString. The ID of the peer to send the events to. Defaults to the public key of the peer if peerID isn't specified.syncEventListHashgraphEvent[]. 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([targetPeerID])
await shard.sendGossip()targetPeerIDString. 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(syncEventList)
await shard.receiveGossip(syncEventList)syncEventListHashgraphEvent[]. 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(elapsedTime)
shard.setElapsedTimeToDeleteEventHistory(60) // 60 second delay before deleting event historyelapsedTimeNumber. 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(callback)
shard.onAddMember((candidateMember) => true) // Vote to allow anyone to join the shardcallbackFunction. A function used to vote on whether to add a candidate member to the shard.candidateMemberObject.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(callback)
shard.onRemoveMember((candidateMember) => {
const isArtist = candidateMember.details.isArtist
const isScientist = candidateMember.details.isScientist
const isMathematician = candidateMember.details.isMathematician
const isEngineer = candidateMember.details.isEngineer
const isHumanitarian = candidateMember.details.isHumanitarian
return !(isArtist || isScientist || isMathematician || isEngineer || isHumanitarian)
}) // Vote to remove non-interesting members from the shardcallbackFunction. A function used to vote on whether to remove a candidate member from the shard.candidateMemberObject.- 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([peerID, isSelf, isConnectedPeer, candidateMember, skipVoting])
await shard.addMember('alice', true) // On Alice's computerpeerIDString. The ID of the peer.isSelfBoolean. Set to true to initialize the self peer. Defaults tofalse.isConnectedPeerBoolean. Set to true if the self peer communicates directly to the peerID peer through the preferred protocol. Defaults tofalse.candidateMemberObject.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.
skipVotingBoolean. 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(candidateMember [, skipVoting])
shard.removeMember({ publicKey: shard.getMemberPublicKey('carol') })candidateMemberObject.skipVotingBoolean. 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(callback)
shard.setMinimumVotePercentToAddMember((candidateMember) => 100) // Require 100 percent (unanimous) approval by current members to add a membercallbackFunction. A function used to set the percent of yes votes required by current members to add a new member.candidateMemberObject.- 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(callback)
shard.setMinimumVotePercentToRemoveMember((candidateMember) => 80) // Require 80 percent approval by current members to remove a membercallbackFunction. A function used to set the percent of yes votes required by current members to remove an existing member.candidateMemberObject.- 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(callback)
shard.onMemberUpdate((member, updateType) => {
if (updateType === 'added') { console.log('Member joined: ', member) }
if (updateType === 'removed') { console.log('Member departed: ', member) }
})callbackFunction. A function used to be notified of member updates (ie. added or removed members).memberObject.updateTypeString. A description of the update; eitheraddedorremoved.- 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(peerID)
await shard.addMember('bob', false, true) // On Bob's computer
const bobPublicKey = shard.getMemberPublicKey('bob')
// Send bob's public key to alice, then..
await shard.addMember('bob', true, false, bobPublicKey) // On Alice's computerpeerIDString. 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()
const memberList = shard.getMemberList()- 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(callback)
shard.onTransactionOrder((previousState, transactionList, isConsensusOrder) => {
if (!isConsensusOrder) { return } // if strict consensus ordering is desired, return early
for (const transaction of transactionList) {
if (transaction.payload.name === 'Bob') { continue } // Validate transactions
previousState.chatHistory = (previousState.chatHistory || []).concat([transaction.payload]) // Apply transactions to the previous state
}
})callbackFunction. A callback function used to apply a list of transactions to a state object.previousStateObject. A copy of the previous consensus state.transactionListArray<{ timestamp: Date, payload: Any }>. A list of messages received from the shard.isConsensusOrderBoolean. 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(transaction)
shard.sendTransaction({ name: 'Alice', message: 'Hello World!' })transactionAny. A message or payload to be sent to the hashgraph shard.- Returns void.
Send a transaction.
shard.determineTransactionOrder()
await shard.determineTransactionOrder()- 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()
const state = shard.getState()- 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

