drand / drand-client

🎲 A JavaScript client to the drand randomness beacon network.
Other
54 stars 13 forks source link
bls bls12-381 client drand kyber random randomness unbiasable unpredictable verifiable

drand client

A JavaScript client to the drand randomness beacon network.

Table of Contents

Install

In the browser or Deno you can grab and use the client from a CDN e.g. https://cdn.jsdelivr.net/npm/drand-client/index.js.

In Node.js or when using a bundler, install with:

npm install drand-client

Typescript types are included and don't need installed separately.

Usage

The drand-client contains HTTP implementations, but other transports can be supported by implementing the DrandNode , Chain and ChainClient interfaces where appropriate.

Browser


<script type='module'>
    import { 
      fetchBeacon, 
      fetchBeaconByTime, 
      HttpChainClient, 
      watch, 
      HttpCachingChain, 
      FastestNodeClient, 
      MultiBeaconNode 
    } from 'https://cdn.jsdelivr.net/npm/drand-client'

    const chainHash = '8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce' // (hex encoded)
    const publicKey = '868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31' // (hex encoded)

    async function main () {
        const options = {
            disableBeaconVerification: false, // `true` disables checking of signatures on beacons - faster but insecure!!!
            noCache: false, // `true` disables caching when retrieving beacons for some providers
            chainVerificationParams: { chainHash, publicKey }  // these are optional, but recommended! They are compared for parity against the `/info` output of a given node
        }

        // if you want to connect to a single chain to grab the latest beacon you can simply do the following
        // note: if you want to access e.g. quicknet you must use 'https://api.drand.sh/52db9ba70e0cc0f6eaf7803dd07447a1f5477735fd3f661792ba94600c84e971'
        // passing the chainHash in the `chainVerificationParams` will not fill in the path for you (unless using `MultiBeaconNode`)
        const chain = new HttpCachingChain('https://api.drand.sh', options)
        const client = new HttpChainClient(chain, options)
        const theLatestBeacon = await fetchBeacon(client)

        // alternatively you can also get the beacon for a given time
        const theBeaconRightNow = await fetchBeaconByTime(client, Date.now())

        // if you're happy to get randomness from many APIs and automatically use the fastest
        // you can construct a `FastestNodeClient` with multiple URLs
        // note: the randomness beacons are cryptographically verifiable, so as long as you fill
        // in the `chainVerificationParams` in the options, you don't need to worry about malicious 
        // providers sending you fake randomness!
        const urls = [
            'https://api.drand.sh',
            'https://drand.cloudflare.com'
            // ...
        ]
        const fastestNodeClient = new FastestNodeClient(urls, options)
        // don't forget to start the client, or it won't periodically optimise for the fastest node!
        fastestNodeClient.start()

        const theLatestBeaconFromTheFastestClient = await fetchBeacon(fastestNodeClient)

        // don't forget to stop the speed testing, or you may leak a `setInterval` call!
        fastestNodeClient.stop()

        // you can also use the `watch` async generator to watch the latest randomness automatically!
        // use an abort controller to stop it
        const abortController = new AbortController()
        for await (const beacon of watch(client, abortController)) {
            if (beacon.round === 10) {
                abortController.abort('round 10 reached - listening stopped')
            }
        }

        // finally you can interact with multibeacon nodes by using the `MultiBeaconNode` class
        // prior to drand 1.4, each node could only follow and contribute to a single beacon chain 
        // - now nodes can contribute to many at once
        // here you only need the base URL, and the chain hashes for each respective beacon chain
        // will be filled in
        const multiBeaconNode = new MultiBeaconNode('https://api.drand.sh', options)

        // you can monitor its health
        const health = await multiBeaconNode.health()
        if (health.status === 200) {
            console.log(`Multibeacon node is healthy and has processed ${health.current} of ${health.expected} rounds`)
        }

        // get the chains it follows
        const chains = await multiBeaconNode.chains()
        for (const c of chains) {
            const info = await c.info()
            console.log(`Chain with baseUrl ${c.baseUrl} has a genesis time of ${info.genesis_time}`)
        }

        // and even create clients straight from the chains it returns
        const latestBeaconsFromAllChains = Promise.all(
                chains.map(chain => new HttpChainClient(chain, options))
                      .map(client => fetchBeacon(client))
        )
    }

    main()
</script>

Deno

Usage in Deno is the same as the browser, minus the HTML <script> tag. Ensure you run your script with the --allow-net flag e.g. deno run --allow-net client.js.

Node.js

If you'd like to run it in Node.js, add a fetch polyfill such as node-fetch and AbortController as globals e.g.

import fetch from 'node-fetch'
import AbortController from 'abort-controller'

global.fetch = fetch
global.AbortController = AbortController

// Use as per browser example...

From common.js:

const fetch = require('node-fetch')
const AbortController = require('abort-controller')

global.fetch = fetch
global.AbortController = AbortController

// Use as per browser example...

Publishing

This repo automatically publishes to npmjs.com as drand-client if changes hit the master branch with an updated version number.

Contribute

Feel free to dive in! Open an issue or submit PRs.

License

This project is dual-licensed under Apache 2.0 and MIT terms:

Limitations