add: Drand network integration with random beacon
This commit is contained in:
parent
c49acb189f
commit
5d17d90c28
30
config/drand.go
Normal file
30
config/drand.go
Normal file
@ -0,0 +1,30 @@
|
||||
package config
|
||||
|
||||
type DrandConfig struct {
|
||||
Servers []string
|
||||
GossipRelays []string
|
||||
ChainInfo string
|
||||
}
|
||||
|
||||
func NewDrandConfig() *DrandConfig {
|
||||
cfg := &DrandConfig{
|
||||
Servers: []string{
|
||||
"https://api.drand.sh",
|
||||
"https://api2.drand.sh",
|
||||
"https://api3.drand.sh",
|
||||
"https://drand.cloudflare.com",
|
||||
},
|
||||
GossipRelays: []string{
|
||||
"/dnsaddr/api.drand.sh/",
|
||||
"/dnsaddr/api2.drand.sh/",
|
||||
"/dnsaddr/api3.drand.sh/",
|
||||
},
|
||||
ChainInfo: `{
|
||||
"public_key": "868f005eb8e6e4ca0a47c8a77ceaa5309a47978a7c71bc5cce96366b5d7a569937c529eeda66c7293784a9402801af31",
|
||||
"period": 30,
|
||||
"genesis_time": 1595431050,
|
||||
"hash": "8990e7a9aaed2ffed73dbd7092123d6f289930540d7651336225dc172e51b2ce"
|
||||
}`,
|
||||
}
|
||||
return cfg
|
||||
}
|
25
go.mod
25
go.mod
@ -7,27 +7,31 @@ require (
|
||||
github.com/aristanetworks/goarista v0.0.0-20200224203130-895b4c57c44d // indirect
|
||||
github.com/cespare/cp v1.1.1 // indirect
|
||||
github.com/deckarep/golang-set v1.7.1 // indirect
|
||||
github.com/drand/drand v1.2.1
|
||||
github.com/drand/kyber v1.1.5
|
||||
github.com/elastic/gosigar v0.10.5 // indirect
|
||||
github.com/ethereum/go-ethereum v1.9.5
|
||||
github.com/filecoin-project/go-state-types v0.0.0-20201021025442-0ac4de847f4f
|
||||
github.com/filecoin-project/lotus v1.1.0
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
|
||||
github.com/go-kit/kit v0.10.0 // indirect
|
||||
github.com/go-kit/kit v0.10.0
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/protobuf v1.4.2 // indirect
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f // indirect
|
||||
github.com/ipfs/go-log v1.0.4
|
||||
github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4
|
||||
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 // indirect
|
||||
github.com/libp2p/go-libp2p v0.10.2
|
||||
github.com/libp2p/go-libp2p v0.11.0
|
||||
github.com/libp2p/go-libp2p-core v0.6.1
|
||||
github.com/libp2p/go-libp2p-discovery v0.5.0
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.8.3
|
||||
github.com/libp2p/go-libp2p-peerstore v0.2.6
|
||||
github.com/libp2p/go-libp2p-pubsub v0.3.3
|
||||
github.com/mattn/go-colorable v0.1.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/multiformats/go-multiaddr v0.2.2
|
||||
github.com/libp2p/go-libp2p-pubsub v0.3.6
|
||||
github.com/multiformats/go-multiaddr v0.3.1
|
||||
github.com/olekukonko/tablewriter v0.0.4 // indirect
|
||||
github.com/raulk/clock v1.1.0
|
||||
github.com/rjeczalik/notify v0.9.2 // indirect
|
||||
github.com/rs/cors v1.7.0 // indirect
|
||||
github.com/sirupsen/logrus v1.6.0
|
||||
@ -36,18 +40,13 @@ require (
|
||||
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 // indirect
|
||||
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570 // indirect
|
||||
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 // indirect
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/tyler-smith/go-bip39 v1.0.2 // indirect
|
||||
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208 // indirect
|
||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 // indirect
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 // indirect
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 // indirect
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4 // indirect
|
||||
google.golang.org/grpc v1.29.1 // indirect
|
||||
google.golang.org/protobuf v1.24.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 // indirect
|
||||
gopkg.in/urfave/cli.v1 v1.20.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.2.8 // indirect
|
||||
honnef.co/go/tools v0.0.1-2020.1.3 // indirect
|
||||
)
|
||||
|
5
lib/clock.go
Normal file
5
lib/clock.go
Normal file
@ -0,0 +1,5 @@
|
||||
package lib
|
||||
|
||||
import "github.com/raulk/clock"
|
||||
|
||||
var Clock = clock.New()
|
157
lib/drand/drand.go
Normal file
157
lib/drand/drand.go
Normal file
@ -0,0 +1,157 @@
|
||||
package drand
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/drand/drand/chain"
|
||||
"github.com/drand/drand/client"
|
||||
httpClient "github.com/drand/drand/client/http"
|
||||
libp2pClient "github.com/drand/drand/lp2p/client"
|
||||
"github.com/drand/kyber"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
|
||||
"github.com/Secured-Finance/dione/config"
|
||||
"github.com/Secured-Finance/dione/lib"
|
||||
)
|
||||
|
||||
type DrandRes struct {
|
||||
// PreviousSig is the previous signature generated
|
||||
PreviousSig []byte
|
||||
// Round is the round number this beacon is tied to
|
||||
Round uint64
|
||||
// Signature is the BLS deterministic signature over Round || PreviousRand
|
||||
Signature []byte
|
||||
// Randomness for specific round generated by Drand
|
||||
Randomness []byte
|
||||
}
|
||||
|
||||
type Beacon struct {
|
||||
DrandResponse DrandRes
|
||||
Error error
|
||||
}
|
||||
|
||||
type DrandBeacon struct {
|
||||
DrandClient client.Client
|
||||
PublicKey kyber.Point
|
||||
Interval time.Duration
|
||||
drandGenesisTime uint64
|
||||
cacheLock sync.Mutex
|
||||
localCache map[uint64]DrandRes
|
||||
}
|
||||
|
||||
func NewDrandBeacon(ps *pubsub.PubSub) (*DrandBeacon, error) {
|
||||
cfg := config.NewDrandConfig()
|
||||
|
||||
drandChain, err := chain.InfoFromJSON(bytes.NewReader([]byte(cfg.ChainInfo)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to unmarshal drand chain info: %w", err)
|
||||
}
|
||||
|
||||
var clients []client.Client
|
||||
for _, url := range cfg.Servers {
|
||||
client, err := httpClient.NewWithInfo(url, drandChain, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create http drand client: %w", err)
|
||||
}
|
||||
clients = append(clients, client)
|
||||
}
|
||||
|
||||
opts := []client.Option{
|
||||
client.WithChainInfo(drandChain),
|
||||
client.WithCacheSize(1024),
|
||||
client.WithAutoWatch(),
|
||||
}
|
||||
|
||||
if ps != nil {
|
||||
opts = append(opts, libp2pClient.WithPubsub(ps))
|
||||
} else {
|
||||
logrus.Info("Initiated drand with PubSub")
|
||||
}
|
||||
|
||||
drandClient, err := client.Wrap(clients, opts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Couldn't create Drand clients")
|
||||
}
|
||||
|
||||
db := &DrandBeacon{
|
||||
DrandClient: drandClient,
|
||||
localCache: make(map[uint64]DrandRes),
|
||||
}
|
||||
|
||||
db.PublicKey = drandChain.PublicKey
|
||||
db.Interval = drandChain.Period
|
||||
db.drandGenesisTime = uint64(drandChain.GenesisTime)
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func (db *DrandBeacon) Entry(ctx context.Context, round uint64) <-chan Beacon {
|
||||
out := make(chan Beacon, 1)
|
||||
if round != 0 {
|
||||
res := db.getCachedValue(round)
|
||||
if res != nil {
|
||||
out <- Beacon{DrandResponse: *res}
|
||||
close(out)
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
start := lib.Clock.Now()
|
||||
logrus.Info("start fetching randomness", "round", round)
|
||||
resp, err := db.DrandClient.Get(ctx, round)
|
||||
|
||||
var res Beacon
|
||||
if err != nil {
|
||||
res.Error = fmt.Errorf("drand failed Get request: %w", err)
|
||||
} else {
|
||||
res.DrandResponse.Round = resp.Round()
|
||||
res.DrandResponse.Signature = resp.Signature()
|
||||
}
|
||||
logrus.Info("done fetching randomness", "round", round, "took", lib.Clock.Since(start))
|
||||
out <- res
|
||||
close(out)
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
||||
func (db *DrandBeacon) cacheValue(res DrandRes) {
|
||||
db.cacheLock.Lock()
|
||||
defer db.cacheLock.Unlock()
|
||||
db.localCache[res.Round] = res
|
||||
}
|
||||
|
||||
func (db *DrandBeacon) getCachedValue(round uint64) *DrandRes {
|
||||
db.cacheLock.Lock()
|
||||
defer db.cacheLock.Unlock()
|
||||
v, ok := db.localCache[round]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return &v
|
||||
}
|
||||
|
||||
func (db *DrandBeacon) VerifyEntry(curr DrandRes, prev DrandRes) error {
|
||||
if prev.Round == 0 {
|
||||
return nil
|
||||
}
|
||||
if be := db.getCachedValue(curr.Round); be != nil {
|
||||
return nil
|
||||
}
|
||||
b := &chain.Beacon{
|
||||
PreviousSig: prev.PreviousSig,
|
||||
Round: curr.Round,
|
||||
Signature: curr.Signature,
|
||||
}
|
||||
err := chain.VerifyBeacon(db.PublicKey, b)
|
||||
if err == nil {
|
||||
db.cacheValue(curr)
|
||||
}
|
||||
return err
|
||||
}
|
23
lib/drand/drand_test.go
Normal file
23
lib/drand/drand_test.go
Normal file
@ -0,0 +1,23 @@
|
||||
package drand
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/Secured-Finance/dione/config"
|
||||
drandClient "github.com/drand/drand/client/http"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPrintGroupInfo(t *testing.T) {
|
||||
cfg := config.NewDrandConfig()
|
||||
ctx := context.Background()
|
||||
drandServer := cfg.Servers[0]
|
||||
client, err := drandClient.New(drandServer, nil, nil)
|
||||
assert.NoError(t, err)
|
||||
drandResult, err := client.Get(ctx, 266966)
|
||||
assert.NoError(t, err)
|
||||
stringSha256 := hex.EncodeToString(drandResult.Randomness())
|
||||
assert.Equal(t, stringSha256, "cb67e13477cad0e54540980a3b621dfd9c5fcd7c92ed42626289a1de6f25c3d1")
|
||||
}
|
Loading…
Reference in New Issue
Block a user