0.1.7 β€’ Published 4 years ago

ts-hashgraph v0.1.7

Weekly downloads
-
License
MIT
Repository
-
Last release
4 years ago

🌳 ts-hashgraph

npm version downloads coverage pipeline

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

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 MembersExample w/ 4 Members

Installation

Install the library

npm install ts-hashgraph --save

Import 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: 1. Copy and paste the code in 2 code environments (for example, 2 codepen browser tabs) 2. 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 ↓

<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

<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.SharedWorld(shardID)

const shard = new TsHashgraph.SharedWorld()
  • shardID String. 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-sync
  • tickRate Number. The number of milliseconds between automatic syncs (gossip + virtual voting). Defaults to 1000 milliseconds (ie. 1 sync per second).
  • Returns void.

Set the frequency of automatically synchronizing with connected peers.

shard.manualSync(targetPeerID)

await shard.manualSync()
  • 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(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 })
  }
})
  • 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(targetPeerID)

await shard.sendGossip()
  • 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(syncEventList)

await shard.receiveGossip(syncEventList)
  • 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(elapsedTime)

shard.setElapsedTimeToDeleteEventHistory(60) // 60 second delay before deleting event history
  • elapsedTime Number. The time to wait before deleting event history. Measured in seconds. Defaults to 20.
  • 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 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(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 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(peerID, isSelf, isConnectedPeer, candidateMember, skipVoting)

await shard.addMember('alice', true) // On Alice's computer
  • peerID String. The ID of the peer.
  • isSelf Boolean. Set to true to initialize the self peer. Defaults to false.
  • isConnectedPeer Boolean. Set to true if the self peer communicates directly to the peerID peer through the preferred protocol. Defaults to false.
  • 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 to false.
  • 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') })
  • candidateMember Object.
  • skipVoting Boolean. A flag used to skip the transaction-based voting to remove the candidate member from the shard. Defaults to false.
  • 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 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(callback)

shard.setMinimumVotePercentToRemoveMember((candidateMember) => 80) // 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(callback)

shard.onMemberUpdate((member, updateType) => {
  if (updateType === 'added') { console.log('Member joined: ', member) }
  if (updateType === 'removed') { console.log('Member departed: ', member) }
})
  • 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; either added or removed.
    • 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 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()

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
  }
})
  • 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(transaction)

shard.sendTransaction({ name: 'Alice', message: 'Hello World!' })
  • transaction Any. 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

ToolingEncryptionHashing
TypeScriptellipticobject-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.

NameProfessionLife work
Jacque FrescoSociocyberneeringVenus Project, Resource Based Economy
Ted NelsonSoftware DesignXanadu, ZigZag
Christopher AlexanderLiving ArchitectureThe 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

0.1.7

4 years ago

0.1.6

4 years ago

0.1.5

4 years ago

0.1.4

5 years ago

0.1.3

5 years ago

0.1.2

5 years ago

0.1.1

5 years ago

0.1.0

5 years ago