Merge pull request #16 from Secured-Finance/feat/blockchain
Implement blockchain for Dione, fix most consensus issues
This commit is contained in:
commit
1d12828313
2
.gitignore
vendored
2
.gitignore
vendored
@ -25,3 +25,5 @@ eth-contracts/node_modules
|
|||||||
/.dione-config-4.toml
|
/.dione-config-4.toml
|
||||||
.bootstrap_privkey
|
.bootstrap_privkey
|
||||||
eth-contracts/build
|
eth-contracts/build
|
||||||
|
.db
|
||||||
|
eth-contracts/secrets.json
|
112
beacon/beacon.go
112
beacon/beacon.go
@ -4,9 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/lib"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/types"
|
"github.com/Secured-Finance/dione/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,7 +14,7 @@ type BeaconResult struct {
|
|||||||
|
|
||||||
type BeaconNetworks []BeaconNetwork
|
type BeaconNetworks []BeaconNetwork
|
||||||
|
|
||||||
func (bn BeaconNetworks) BeaconNetworkForRound(e types.DrandRound) BeaconAPI {
|
func (bn BeaconNetworks) BeaconNetworkForRound(e uint64) BeaconAPI {
|
||||||
for i := len(bn) - 1; i >= 0; i-- {
|
for i := len(bn) - 1; i >= 0; i-- {
|
||||||
bp := bn[i]
|
bp := bn[i]
|
||||||
if e >= bp.Start {
|
if e >= bp.Start {
|
||||||
@ -28,7 +25,7 @@ func (bn BeaconNetworks) BeaconNetworkForRound(e types.DrandRound) BeaconAPI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type BeaconNetwork struct {
|
type BeaconNetwork struct {
|
||||||
Start types.DrandRound
|
Start uint64
|
||||||
Beacon BeaconAPI
|
Beacon BeaconAPI
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,111 +34,18 @@ type BeaconNetwork struct {
|
|||||||
// valid for a specific chain epoch. Also to verify beacon entries that have
|
// valid for a specific chain epoch. Also to verify beacon entries that have
|
||||||
// been posted on chain.
|
// been posted on chain.
|
||||||
type BeaconAPI interface {
|
type BeaconAPI interface {
|
||||||
Entry(context.Context, uint64) <-chan BeaconResult
|
Entry(context.Context, uint64) (types.BeaconEntry, error)
|
||||||
VerifyEntry(types.BeaconEntry, types.BeaconEntry) error
|
VerifyEntry(types.BeaconEntry, types.BeaconEntry) error
|
||||||
LatestBeaconRound() uint64
|
LatestBeaconRound() uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateTaskBeacons(beaconNetworks BeaconNetworks, t *types.DioneTask, prevEpoch types.DrandRound, prevEntry types.BeaconEntry) error {
|
// ValidateBlockBeacons is a function that verifies block randomness
|
||||||
parentBeacon := beaconNetworks.BeaconNetworkForRound(prevEpoch)
|
func (bn BeaconNetworks) ValidateBlockBeacons(beaconNetworks BeaconNetworks, curEntry, prevEntry types.BeaconEntry) error {
|
||||||
currBeacon := beaconNetworks.BeaconNetworkForRound(t.DrandRound)
|
defaultBeacon := beaconNetworks.BeaconNetworkForRound(0)
|
||||||
if parentBeacon != currBeacon {
|
|
||||||
if len(t.BeaconEntries) != 2 {
|
|
||||||
return fmt.Errorf("expected two beacon entries at beacon fork, got %d", len(t.BeaconEntries))
|
|
||||||
}
|
|
||||||
err := currBeacon.VerifyEntry(t.BeaconEntries[1], t.BeaconEntries[0])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("beacon at fork point invalid: (%v, %v): %w",
|
|
||||||
t.BeaconEntries[1], t.BeaconEntries[0], err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: fork logic
|
if err := defaultBeacon.VerifyEntry(curEntry, prevEntry); err != nil {
|
||||||
bNetwork := beaconNetworks.BeaconNetworkForRound(t.DrandRound)
|
return fmt.Errorf("beacon entry was invalid: %w", err)
|
||||||
if uint64(t.DrandRound) == prevEntry.Round {
|
|
||||||
if len(t.BeaconEntries) != 0 {
|
|
||||||
return fmt.Errorf("expected not to have any beacon entries in this task, got %d", len(t.BeaconEntries))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(t.BeaconEntries) == 0 {
|
|
||||||
return fmt.Errorf("expected to have beacon entries in this task, but didn't find any")
|
|
||||||
}
|
|
||||||
|
|
||||||
last := t.BeaconEntries[len(t.BeaconEntries)-1]
|
|
||||||
if last.Round != uint64(t.DrandRound) {
|
|
||||||
return fmt.Errorf("expected final beacon entry in task to be at round %d, got %d", uint64(t.DrandRound), last.Round)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, e := range t.BeaconEntries {
|
|
||||||
if err := bNetwork.VerifyEntry(e, prevEntry); err != nil {
|
|
||||||
return fmt.Errorf("beacon entry %d (%d - %x (%d)) was invalid: %w", i, e.Round, e.Data, len(e.Data), err)
|
|
||||||
}
|
|
||||||
prevEntry = e
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func BeaconEntriesForTask(ctx context.Context, beaconNetworks BeaconNetworks) ([]types.BeaconEntry, error) {
|
|
||||||
beacon := beaconNetworks.BeaconNetworkForRound(0)
|
|
||||||
round := beacon.LatestBeaconRound()
|
|
||||||
|
|
||||||
//prevBeacon := beaconNetworks.BeaconNetworkForRound(prevRound)
|
|
||||||
//currBeacon := beaconNetworks.BeaconNetworkForRound(round)
|
|
||||||
//if prevBeacon != currBeacon {
|
|
||||||
// // Fork logic
|
|
||||||
// round := currBeacon.LatestBeaconRound()
|
|
||||||
// out := make([]types.BeaconEntry, 2)
|
|
||||||
// rch := currBeacon.Entry(ctx, round-1)
|
|
||||||
// res := <-rch
|
|
||||||
// if res.Err != nil {
|
|
||||||
// return nil, fmt.Errorf("getting entry %d returned error: %w", round-1, res.Err)
|
|
||||||
// }
|
|
||||||
// out[0] = res.Entry
|
|
||||||
// rch = currBeacon.Entry(ctx, round)
|
|
||||||
// res = <-rch
|
|
||||||
// if res.Err != nil {
|
|
||||||
// return nil, fmt.Errorf("getting entry %d returned error: %w", round, res.Err)
|
|
||||||
// }
|
|
||||||
// out[1] = res.Entry
|
|
||||||
// return out, nil
|
|
||||||
//}
|
|
||||||
|
|
||||||
start := lib.Clock.Now()
|
|
||||||
|
|
||||||
//if round == prev.Round {
|
|
||||||
// return nil, nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//// TODO: this is a sketchy way to handle the genesis block not having a beacon entry
|
|
||||||
//if prev.Round == 0 {
|
|
||||||
// prev.Round = round - 1
|
|
||||||
//}
|
|
||||||
|
|
||||||
out := make([]types.BeaconEntry, 2)
|
|
||||||
rch := beacon.Entry(ctx, round-1)
|
|
||||||
res := <-rch
|
|
||||||
if res.Err != nil {
|
|
||||||
return nil, fmt.Errorf("getting entry %d returned error: %w", round-1, res.Err)
|
|
||||||
}
|
|
||||||
out[0] = res.Entry
|
|
||||||
rch = beacon.Entry(ctx, round)
|
|
||||||
res = <-rch
|
|
||||||
if res.Err != nil {
|
|
||||||
return nil, fmt.Errorf("getting entry %d returned error: %w", round, res.Err)
|
|
||||||
}
|
|
||||||
out[1] = res.Entry
|
|
||||||
|
|
||||||
logrus.Debugf("fetching beacon entries: took %v, count of entries: %v", lib.Clock.Since(start), len(out))
|
|
||||||
//reverse(out)
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func reverse(arr []types.BeaconEntry) {
|
|
||||||
for i := 0; i < len(arr)/2; i++ {
|
|
||||||
arr[i], arr[len(arr)-(1+i)] = arr[len(arr)-(1+i)], arr[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
8
beacon/domain_separation_tag.go
Normal file
8
beacon/domain_separation_tag.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package beacon
|
||||||
|
|
||||||
|
// RandomnessType specifies a type of randomness.
|
||||||
|
type RandomnessType int64
|
||||||
|
|
||||||
|
const (
|
||||||
|
RandomnessTypeElectionProofProduction RandomnessType = 1 + iota
|
||||||
|
)
|
@ -5,7 +5,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
|
"github.com/asaskevich/EventBus"
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/beacon"
|
"github.com/Secured-Finance/dione/beacon"
|
||||||
"github.com/drand/drand/chain"
|
"github.com/drand/drand/chain"
|
||||||
@ -30,31 +31,17 @@ var log = logrus.WithFields(logrus.Fields{
|
|||||||
"subsystem": "drand",
|
"subsystem": "drand",
|
||||||
})
|
})
|
||||||
|
|
||||||
// DrandResponse structure representing response from drand network
|
|
||||||
type DrandResponse 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 DrandBeacon struct {
|
type DrandBeacon struct {
|
||||||
DrandClient client.Client
|
DrandClient client.Client
|
||||||
PublicKey kyber.Point
|
PublicKey kyber.Point
|
||||||
Interval time.Duration
|
drandResultChannel <-chan client.Result
|
||||||
chainGenesisTime uint64
|
|
||||||
chainRoundTime uint64
|
|
||||||
|
|
||||||
drandGenesisTime uint64
|
|
||||||
cacheLock sync.Mutex
|
cacheLock sync.Mutex
|
||||||
localCache map[uint64]types.BeaconEntry
|
localCache map[uint64]types.BeaconEntry
|
||||||
|
latestDrandRound uint64
|
||||||
|
bus EventBus.Bus
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub) (*DrandBeacon, error) {
|
func NewDrandBeacon(ps *pubsub.PubSub, bus EventBus.Bus) (*DrandBeacon, error) {
|
||||||
cfg := config.NewDrandConfig()
|
cfg := config.NewDrandConfig()
|
||||||
|
|
||||||
drandChain, err := chain.InfoFromJSON(bytes.NewReader([]byte(cfg.ChainInfo)))
|
drandChain, err := chain.InfoFromJSON(bytes.NewReader([]byte(cfg.ChainInfo)))
|
||||||
@ -95,46 +82,69 @@ func NewDrandBeacon(genesisTs, interval uint64, ps *pubsub.PubSub) (*DrandBeacon
|
|||||||
db := &DrandBeacon{
|
db := &DrandBeacon{
|
||||||
DrandClient: drandClient,
|
DrandClient: drandClient,
|
||||||
localCache: make(map[uint64]types.BeaconEntry),
|
localCache: make(map[uint64]types.BeaconEntry),
|
||||||
|
bus: bus,
|
||||||
|
PublicKey: drandChain.PublicKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
db.PublicKey = drandChain.PublicKey
|
|
||||||
db.Interval = drandChain.Period
|
|
||||||
db.drandGenesisTime = uint64(drandChain.GenesisTime)
|
|
||||||
db.chainRoundTime = interval
|
|
||||||
db.chainGenesisTime = genesisTs
|
|
||||||
|
|
||||||
return db, nil
|
return db, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DrandBeacon) Entry(ctx context.Context, round uint64) <-chan beacon.BeaconResult {
|
func (db *DrandBeacon) Run(ctx context.Context) error {
|
||||||
out := make(chan beacon.BeaconResult, 1)
|
db.drandResultChannel = db.DrandClient.Watch(ctx)
|
||||||
|
err := db.getLatestDrandResult()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go db.loop(ctx)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DrandBeacon) getLatestDrandResult() error {
|
||||||
|
latestDround, err := db.DrandClient.Get(context.TODO(), 0)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("failed to get latest drand round: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
db.cacheValue(newBeaconEntryFromDrandResult(latestDround))
|
||||||
|
db.updateLatestDrandRound(latestDround.Round())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DrandBeacon) loop(ctx context.Context) {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
{
|
||||||
|
logrus.Debug("Stopping watching new DRAND entries...")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case res := <-db.drandResultChannel:
|
||||||
|
{
|
||||||
|
db.cacheValue(newBeaconEntryFromDrandResult(res))
|
||||||
|
db.updateLatestDrandRound(res.Round())
|
||||||
|
db.bus.Publish("beacon:newEntry", types.NewBeaconEntry(res.Round(), res.Randomness(), map[string]interface{}{"signature": res.Signature()}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DrandBeacon) Entry(ctx context.Context, round uint64) (types.BeaconEntry, error) {
|
||||||
if round != 0 {
|
if round != 0 {
|
||||||
be := db.getCachedValue(round)
|
be := db.getCachedValue(round)
|
||||||
if be != nil {
|
if be != nil {
|
||||||
out <- beacon.BeaconResult{Entry: *be}
|
return *be, nil
|
||||||
close(out)
|
|
||||||
return out
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
|
||||||
start := lib.Clock.Now()
|
start := lib.Clock.Now()
|
||||||
log.Infof("start fetching randomness: round %v", round)
|
log.Infof("start fetching randomness: round %v", round)
|
||||||
resp, err := db.DrandClient.Get(ctx, round)
|
resp, err := db.DrandClient.Get(ctx, round)
|
||||||
|
|
||||||
var br beacon.BeaconResult
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
br.Err = fmt.Errorf("drand failed Get request: %w", err)
|
return types.BeaconEntry{}, fmt.Errorf("drand failed Get request: %w", err)
|
||||||
} else {
|
|
||||||
br.Entry.Round = resp.Round()
|
|
||||||
br.Entry.Data = resp.Signature()
|
|
||||||
}
|
}
|
||||||
log.Infof("done fetching randomness: round %v, took %v", round, lib.Clock.Since(start))
|
log.Infof("done fetching randomness: round %v, took %v", round, lib.Clock.Since(start))
|
||||||
out <- br
|
return newBeaconEntryFromDrandResult(resp), nil
|
||||||
close(out)
|
|
||||||
}()
|
|
||||||
|
|
||||||
return out
|
|
||||||
}
|
}
|
||||||
func (db *DrandBeacon) cacheValue(res types.BeaconEntry) {
|
func (db *DrandBeacon) cacheValue(res types.BeaconEntry) {
|
||||||
db.cacheLock.Lock()
|
db.cacheLock.Lock()
|
||||||
@ -152,6 +162,12 @@ func (db *DrandBeacon) getCachedValue(round uint64) *types.BeaconEntry {
|
|||||||
return &v
|
return &v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *DrandBeacon) updateLatestDrandRound(round uint64) {
|
||||||
|
db.cacheLock.Lock()
|
||||||
|
defer db.cacheLock.Unlock()
|
||||||
|
db.latestDrandRound = round
|
||||||
|
}
|
||||||
|
|
||||||
func (db *DrandBeacon) VerifyEntry(curr, prev types.BeaconEntry) error {
|
func (db *DrandBeacon) VerifyEntry(curr, prev types.BeaconEntry) error {
|
||||||
if prev.Round == 0 {
|
if prev.Round == 0 {
|
||||||
return nil
|
return nil
|
||||||
@ -160,23 +176,21 @@ func (db *DrandBeacon) VerifyEntry(curr, prev types.BeaconEntry) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
b := &chain.Beacon{
|
b := &chain.Beacon{
|
||||||
PreviousSig: prev.Data,
|
PreviousSig: prev.Metadata["signature"].([]byte),
|
||||||
Round: curr.Round,
|
Round: curr.Round,
|
||||||
Signature: curr.Data,
|
Signature: curr.Metadata["signature"].([]byte),
|
||||||
}
|
}
|
||||||
err := chain.VerifyBeacon(db.PublicKey, b)
|
return chain.VerifyBeacon(db.PublicKey, b)
|
||||||
if err == nil {
|
|
||||||
db.cacheValue(curr)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DrandBeacon) LatestBeaconRound() uint64 {
|
func (db *DrandBeacon) LatestBeaconRound() uint64 {
|
||||||
latestDround, err := db.DrandClient.Get(context.TODO(), 0)
|
db.cacheLock.Lock()
|
||||||
if err != nil {
|
defer db.cacheLock.Unlock()
|
||||||
log.Errorf("failed to get latest drand round: %w", err)
|
return db.latestDrandRound
|
||||||
}
|
}
|
||||||
return latestDround.Round()
|
|
||||||
|
func newBeaconEntryFromDrandResult(res client.Result) types.BeaconEntry {
|
||||||
|
return types.NewBeaconEntry(res.Round(), res.Randomness(), map[string]interface{}{"signature": res.Signature()})
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ beacon.BeaconAPI = (*DrandBeacon)(nil)
|
var _ beacon.BeaconAPI = (*DrandBeacon)(nil)
|
29
beacon/utils.go
Normal file
29
beacon/utils.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package beacon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
|
"github.com/minio/blake2b-simd"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DrawRandomness(rbase []byte, randomnessType RandomnessType, round uint64, entropy []byte) ([]byte, error) {
|
||||||
|
h := blake2b.New256()
|
||||||
|
if err := binary.Write(h, binary.BigEndian, int64(randomnessType)); err != nil {
|
||||||
|
return nil, xerrors.Errorf("deriving randomness: %v", err)
|
||||||
|
}
|
||||||
|
VRFDigest := blake2b.Sum256(rbase)
|
||||||
|
_, err := h.Write(VRFDigest[:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("hashing VRFDigest: %w", err)
|
||||||
|
}
|
||||||
|
if err := binary.Write(h, binary.BigEndian, round); err != nil {
|
||||||
|
return nil, xerrors.Errorf("deriving randomness: %v", err)
|
||||||
|
}
|
||||||
|
_, err = h.Write(entropy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("hashing entropy: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return h.Sum(nil), nil
|
||||||
|
}
|
28
beacon/vrf.go
Normal file
28
beacon/vrf.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package beacon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/crypto"
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ComputeVRF(privKey crypto.PrivKey, sigInput []byte) ([]byte, error) {
|
||||||
|
return privKey.Sign(sigInput)
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifyVRF(worker peer.ID, vrfBase, vrfproof []byte) error {
|
||||||
|
pk, err := worker.ExtractPublicKey()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ok, err := pk.Verify(vrfBase, vrfproof)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("vrf was invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
434
blockchain/blockchain.go
Normal file
434
blockchain/blockchain.go
Normal file
@ -0,0 +1,434 @@
|
|||||||
|
package blockchain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
drand2 "github.com/Secured-Finance/dione/beacon/drand"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/beacon"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/consensus/validation"
|
||||||
|
"github.com/Secured-Finance/dione/types"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/wealdtech/go-merkletree"
|
||||||
|
"github.com/wealdtech/go-merkletree/keccak256"
|
||||||
|
|
||||||
|
"github.com/asaskevich/EventBus"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain/utils"
|
||||||
|
|
||||||
|
types2 "github.com/Secured-Finance/dione/blockchain/types"
|
||||||
|
"github.com/fxamacker/cbor/v2"
|
||||||
|
|
||||||
|
"github.com/ledgerwatch/lmdb-go/lmdb"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultBlockDataPrefix = "blockdata_"
|
||||||
|
DefaultBlockHeaderPrefix = "header_"
|
||||||
|
DefaultMetadataIndexName = "metadata"
|
||||||
|
LatestBlockHeightKey = "latest_block_height"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrBlockNotFound = errors.New("block isn't found")
|
||||||
|
ErrLatestHeightNil = errors.New("latest block height is nil")
|
||||||
|
)
|
||||||
|
|
||||||
|
type BlockChain struct {
|
||||||
|
// db-related
|
||||||
|
dbEnv *lmdb.Env
|
||||||
|
db lmdb.DBI
|
||||||
|
metadataIndex *utils.Index
|
||||||
|
heightIndex *utils.Index
|
||||||
|
|
||||||
|
bus EventBus.Bus
|
||||||
|
miner *Miner
|
||||||
|
drandBeacon *drand2.DrandBeacon
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBlockChain(path string, bus EventBus.Bus, miner *Miner, db *drand2.DrandBeacon) (*BlockChain, error) {
|
||||||
|
chain := &BlockChain{
|
||||||
|
bus: bus,
|
||||||
|
miner: miner,
|
||||||
|
drandBeacon: db,
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure lmdb env
|
||||||
|
env, err := lmdb.NewEnv()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = env.SetMaxDBs(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = env.SetMapSize(100 * 1024 * 1024 * 1024) // 100 GB
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.MkdirAll(path, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = env.Open(path, 0, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
chain.dbEnv = env
|
||||||
|
|
||||||
|
var dbi lmdb.DBI
|
||||||
|
err = env.Update(func(txn *lmdb.Txn) error {
|
||||||
|
dbi, err = txn.OpenDBI("blocks", lmdb.Create)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
chain.db = dbi
|
||||||
|
|
||||||
|
// create index instances
|
||||||
|
metadataIndex := utils.NewIndex(DefaultMetadataIndexName, env, dbi)
|
||||||
|
heightIndex := utils.NewIndex("height", env, dbi)
|
||||||
|
chain.metadataIndex = metadataIndex
|
||||||
|
chain.heightIndex = heightIndex
|
||||||
|
|
||||||
|
return chain, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *BlockChain) setLatestBlockHeight(height uint64) error {
|
||||||
|
err := bc.metadataIndex.PutUint64([]byte(LatestBlockHeightKey), height)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *BlockChain) GetLatestBlockHeight() (uint64, error) {
|
||||||
|
height, err := bc.metadataIndex.GetUint64([]byte(LatestBlockHeightKey))
|
||||||
|
if err != nil {
|
||||||
|
if err == utils.ErrIndexKeyNotFound {
|
||||||
|
return 0, ErrLatestHeightNil
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return height, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *BlockChain) StoreBlock(block *types2.Block) error {
|
||||||
|
if exists, err := bc.HasBlock(block.Header.Hash); err != nil {
|
||||||
|
return err
|
||||||
|
} else if exists {
|
||||||
|
//return fmt.Errorf("block already exists in blockchain")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if block.Header.Height != 0 {
|
||||||
|
err := bc.ValidateBlock(block)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to store block: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := bc.dbEnv.Update(func(txn *lmdb.Txn) error {
|
||||||
|
data, err := cbor.Marshal(block.Data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
headerData, err := cbor.Marshal(block.Header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
blockHash := hex.EncodeToString(block.Header.Hash)
|
||||||
|
err = txn.Put(bc.db, []byte(DefaultBlockDataPrefix+blockHash), data, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = txn.Put(bc.db, []byte(DefaultBlockHeaderPrefix+blockHash), headerData, 0) // store header separately for easy fetching
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update index "height -> block hash"
|
||||||
|
heightBytes := make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(heightBytes, block.Header.Height)
|
||||||
|
err = bc.heightIndex.PutBytes(heightBytes, block.Header.Hash)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update latest block height
|
||||||
|
height, err := bc.GetLatestBlockHeight()
|
||||||
|
if err != nil && err != ErrLatestHeightNil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == ErrLatestHeightNil || block.Header.Height > height {
|
||||||
|
if err = bc.setLatestBlockHeight(block.Header.Height); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
bc.bus.Publish("blockchain:latestBlockHeightUpdated", block)
|
||||||
|
}
|
||||||
|
bc.bus.Publish("blockchain:blockCommitted", block)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *BlockChain) HasBlock(blockHash []byte) (bool, error) {
|
||||||
|
var blockExists bool
|
||||||
|
err := bc.dbEnv.View(func(txn *lmdb.Txn) error {
|
||||||
|
h := hex.EncodeToString(blockHash)
|
||||||
|
_, err := txn.Get(bc.db, []byte(DefaultBlockHeaderPrefix+h)) // try to fetch block header
|
||||||
|
if err != nil {
|
||||||
|
if lmdb.IsNotFound(err) {
|
||||||
|
blockExists = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
blockExists = true
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return blockExists, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *BlockChain) FetchBlockData(blockHash []byte) ([]*types2.Transaction, error) {
|
||||||
|
var data []*types2.Transaction
|
||||||
|
err := bc.dbEnv.View(func(txn *lmdb.Txn) error {
|
||||||
|
h := hex.EncodeToString(blockHash)
|
||||||
|
blockData, err := txn.Get(bc.db, []byte(DefaultBlockDataPrefix+h))
|
||||||
|
if err != nil {
|
||||||
|
if lmdb.IsNotFound(err) {
|
||||||
|
return ErrBlockNotFound
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = cbor.Unmarshal(blockData, &data)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *BlockChain) FetchBlockHeader(blockHash []byte) (*types2.BlockHeader, error) {
|
||||||
|
var blockHeader types2.BlockHeader
|
||||||
|
err := bc.dbEnv.View(func(txn *lmdb.Txn) error {
|
||||||
|
h := hex.EncodeToString(blockHash)
|
||||||
|
data, err := txn.Get(bc.db, []byte(DefaultBlockHeaderPrefix+h))
|
||||||
|
if err != nil {
|
||||||
|
if lmdb.IsNotFound(err) {
|
||||||
|
return ErrBlockNotFound
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = cbor.Unmarshal(data, &blockHeader)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &blockHeader, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *BlockChain) FetchBlock(blockHash []byte) (*types2.Block, error) {
|
||||||
|
var block types2.Block
|
||||||
|
header, err := bc.FetchBlockHeader(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
block.Header = header
|
||||||
|
|
||||||
|
data, err := bc.FetchBlockData(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
block.Data = data
|
||||||
|
|
||||||
|
return &block, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *BlockChain) FetchBlockByHeight(height uint64) (*types2.Block, error) {
|
||||||
|
var heightBytes = make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(heightBytes, height)
|
||||||
|
blockHash, err := bc.heightIndex.GetBytes(heightBytes)
|
||||||
|
if err != nil {
|
||||||
|
if err == utils.ErrIndexKeyNotFound {
|
||||||
|
return nil, ErrBlockNotFound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
block, err := bc.FetchBlock(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return block, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *BlockChain) FetchBlockHeaderByHeight(height uint64) (*types2.BlockHeader, error) {
|
||||||
|
var heightBytes = make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(heightBytes, height)
|
||||||
|
blockHash, err := bc.heightIndex.GetBytes(heightBytes)
|
||||||
|
if err != nil {
|
||||||
|
if err == utils.ErrIndexKeyNotFound {
|
||||||
|
return nil, ErrBlockNotFound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
blockHeader, err := bc.FetchBlockHeader(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return blockHeader, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *BlockChain) ValidateBlock(block *types2.Block) error {
|
||||||
|
// === verify block signature ===
|
||||||
|
pubkey, err := block.Header.Proposer.ExtractPublicKey()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to extract public key from block proposer's peer id: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := pubkey.Verify(block.Header.Hash, block.Header.Signature)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to verify block signature: %w", err)
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("signature of block %x is invalid", block.Header.Hash)
|
||||||
|
}
|
||||||
|
/////////////////////////////////
|
||||||
|
|
||||||
|
// === check last hash merkle proof ===
|
||||||
|
latestHeight, err := bc.GetLatestBlockHeight()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
previousBlockHeader, err := bc.FetchBlockHeaderByHeight(latestHeight)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !bytes.Equal(block.Header.LastHash, previousBlockHeader.Hash) {
|
||||||
|
return fmt.Errorf("block header has invalid last block hash (expected: %x, actual %x)", previousBlockHeader.Hash, block.Header.LastHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
verified, err := merkletree.VerifyProofUsing(previousBlockHeader.Hash, true, block.Header.LastHashProof, [][]byte{block.Header.Hash}, keccak256.New())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to verify last block hash merkle proof: %w", err)
|
||||||
|
}
|
||||||
|
if !verified {
|
||||||
|
return fmt.Errorf("merkle hash of block doesn't contain hash of previous block")
|
||||||
|
}
|
||||||
|
/////////////////////////////////
|
||||||
|
|
||||||
|
// === verify election proof wincount preliminarily ===
|
||||||
|
if block.Header.ElectionProof.WinCount < 1 {
|
||||||
|
return fmt.Errorf("block proposer %s is not a winner", block.Header.Proposer.String())
|
||||||
|
}
|
||||||
|
/////////////////////////////////
|
||||||
|
|
||||||
|
// === verify miner's eligibility to propose this task ===
|
||||||
|
err = bc.miner.IsMinerEligibleToProposeBlock(block.Header.ProposerEth)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("block proposer is not eligible to propose block: %w", err)
|
||||||
|
}
|
||||||
|
/////////////////////////////////
|
||||||
|
|
||||||
|
// === verify election proof vrf ===
|
||||||
|
proposerBuf, err := block.Header.Proposer.MarshalBinary()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := bc.drandBeacon.Entry(context.TODO(), block.Header.ElectionProof.RandomnessRound)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
eproofRandomness, err := beacon.DrawRandomness(
|
||||||
|
res.Data,
|
||||||
|
beacon.RandomnessTypeElectionProofProduction,
|
||||||
|
block.Header.Height,
|
||||||
|
proposerBuf,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to draw ElectionProof randomness: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = beacon.VerifyVRF(*block.Header.Proposer, eproofRandomness, block.Header.ElectionProof.VRFProof)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to verify election proof vrf: %w", err)
|
||||||
|
}
|
||||||
|
//////////////////////////////////////
|
||||||
|
|
||||||
|
// === compute wincount locally and verify values ===
|
||||||
|
mStake, nStake, err := bc.miner.GetStakeInfo(block.Header.ProposerEth)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get miner stake: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actualWinCount := block.Header.ElectionProof.ComputeWinCount(mStake, nStake)
|
||||||
|
if block.Header.ElectionProof.WinCount != actualWinCount {
|
||||||
|
return fmt.Errorf("locally computed wincount of block is not matching to the received value")
|
||||||
|
}
|
||||||
|
//////////////////////////////////////
|
||||||
|
|
||||||
|
// === validate block transactions ===
|
||||||
|
result := make(chan error)
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for _, v := range block.Data {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(v *types2.Transaction, c chan error) {
|
||||||
|
defer wg.Done()
|
||||||
|
if err := utils.VerifyTx(block.Header, v); err != nil {
|
||||||
|
c <- fmt.Errorf("failed to verify tx: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var task types.DioneTask
|
||||||
|
err = cbor.Unmarshal(v.Data, &task)
|
||||||
|
if err != nil {
|
||||||
|
c <- fmt.Errorf("failed to unmarshal transaction payload: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if validationFunc := validation.GetValidationMethod(task.OriginChain, task.RequestType); validationFunc != nil {
|
||||||
|
if err := validationFunc(&task); err != nil {
|
||||||
|
c <- fmt.Errorf("payload validation has been failed: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"originChain": task.OriginChain,
|
||||||
|
"requestType": task.RequestType,
|
||||||
|
}).Debug("This origin chain/request type doesn't have any payload validation!")
|
||||||
|
}
|
||||||
|
}(v, result)
|
||||||
|
}
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
close(result)
|
||||||
|
}()
|
||||||
|
for err := range result {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/////////////////////////////////
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
199
blockchain/miner.go
Normal file
199
blockchain/miner.go
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
package blockchain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/host"
|
||||||
|
|
||||||
|
"github.com/asaskevich/EventBus"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/beacon"
|
||||||
|
"github.com/Secured-Finance/dione/types"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain/pool"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/crypto"
|
||||||
|
|
||||||
|
types2 "github.com/Secured-Finance/dione/blockchain/types"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/ethclient"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNoTxForBlock = fmt.Errorf("no transactions for including into block")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Miner struct {
|
||||||
|
bus EventBus.Bus
|
||||||
|
address peer.ID
|
||||||
|
ethClient *ethclient.EthereumClient
|
||||||
|
minerStake *big.Int
|
||||||
|
networkStake *big.Int
|
||||||
|
privateKey crypto.PrivKey
|
||||||
|
mempool *pool.Mempool
|
||||||
|
latestBlockHeader *types2.BlockHeader
|
||||||
|
blockchain *BlockChain
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMiner(
|
||||||
|
h host.Host,
|
||||||
|
ethClient *ethclient.EthereumClient,
|
||||||
|
privateKey crypto.PrivKey,
|
||||||
|
mempool *pool.Mempool,
|
||||||
|
bus EventBus.Bus,
|
||||||
|
) *Miner {
|
||||||
|
m := &Miner{
|
||||||
|
address: h.ID(),
|
||||||
|
ethClient: ethClient,
|
||||||
|
privateKey: privateKey,
|
||||||
|
mempool: mempool,
|
||||||
|
bus: bus,
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Miner) SetBlockchainInstance(b *BlockChain) {
|
||||||
|
m.blockchain = b
|
||||||
|
|
||||||
|
m.bus.SubscribeAsync("blockchain:latestBlockHeightUpdated", func(block *types2.Block) {
|
||||||
|
m.latestBlockHeader = block.Header
|
||||||
|
}, true)
|
||||||
|
|
||||||
|
height, _ := m.blockchain.GetLatestBlockHeight()
|
||||||
|
header, err := m.blockchain.FetchBlockHeaderByHeight(height)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithField("err", err.Error()).Fatal("Failed to initialize miner subsystem")
|
||||||
|
}
|
||||||
|
m.latestBlockHeader = header
|
||||||
|
|
||||||
|
logrus.Info("Mining subsystem has been initialized!")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Miner) UpdateCurrentStakeInfo() error {
|
||||||
|
mStake, err := m.ethClient.GetMinerStake(*m.ethClient.GetEthAddress())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warn("Can't get miner stake", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nStake, err := m.ethClient.GetTotalStake()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warn("Can't get miner stake", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m.minerStake = mStake
|
||||||
|
m.networkStake = nStake
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Miner) GetStakeInfo(miner common.Address) (*big.Int, *big.Int, error) {
|
||||||
|
mStake, err := m.ethClient.GetMinerStake(miner)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warn("Can't get miner stake", err)
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nStake, err := m.ethClient.GetTotalStake()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warn("Can't get miner stake", err)
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return mStake, nStake, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Miner) MineBlock(randomness []byte, randomnessRound uint64) (*types2.Block, error) {
|
||||||
|
if m.latestBlockHeader == nil {
|
||||||
|
return nil, fmt.Errorf("latest block header is null")
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithField("height", m.latestBlockHeader.Height+1).Debug("Trying to mine new block...")
|
||||||
|
|
||||||
|
if err := m.UpdateCurrentStakeInfo(); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to update miner stake: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
winner, err := isRoundWinner(
|
||||||
|
m.latestBlockHeader.Height+1,
|
||||||
|
m.address,
|
||||||
|
randomness,
|
||||||
|
randomnessRound,
|
||||||
|
m.minerStake,
|
||||||
|
m.networkStake,
|
||||||
|
m.privateKey,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to check if we winned in next round: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if winner == nil {
|
||||||
|
logrus.WithField("height", m.latestBlockHeader.Height+1).Debug("Block is not mined because we are not leader in consensus round")
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithField("height", m.latestBlockHeader.Height+1).Infof("We have been elected in the current consensus round")
|
||||||
|
|
||||||
|
txs := m.mempool.GetTransactionsForNewBlock()
|
||||||
|
if txs == nil {
|
||||||
|
return nil, ErrNoTxForBlock // skip new consensus round because there is no transaction for processing
|
||||||
|
}
|
||||||
|
|
||||||
|
newBlock, err := types2.CreateBlock(m.latestBlockHeader, txs, *m.ethClient.GetEthAddress(), m.privateKey, winner)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create new block: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newBlock, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Miner) IsMinerEligibleToProposeBlock(ethAddress common.Address) error {
|
||||||
|
mStake, err := m.ethClient.GetMinerStake(ethAddress)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if mStake.Cmp(big.NewInt(ethclient.MinMinerStake)) == -1 {
|
||||||
|
return errors.New("miner doesn't have enough staked tokens")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isRoundWinner(round uint64,
|
||||||
|
worker peer.ID, randomness []byte, randomnessRound uint64, minerStake, networkStake *big.Int, privKey crypto.PrivKey) (*types.ElectionProof, error) {
|
||||||
|
|
||||||
|
buf, err := worker.MarshalBinary()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to marshal address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
electionRand, err := beacon.DrawRandomness(randomness, beacon.RandomnessTypeElectionProofProduction, round, buf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to draw randomness: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
vrfout, err := beacon.ComputeVRF(privKey, electionRand)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to compute VRF: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ep := &types.ElectionProof{VRFProof: vrfout, RandomnessRound: randomnessRound}
|
||||||
|
j := ep.ComputeWinCount(minerStake, networkStake)
|
||||||
|
ep.WinCount = j
|
||||||
|
if j < 1 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return ep, nil
|
||||||
|
}
|
107
blockchain/pool/mempool.go
Normal file
107
blockchain/pool/mempool.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package pool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/asaskevich/EventBus"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
types2 "github.com/Secured-Finance/dione/blockchain/types"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/consensus/policy"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/cache"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultTxTTL = 10 * time.Minute
|
||||||
|
DefaultTxPrefix = "tx_"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrTxNotFound = errors.New("tx isn't found in mempool")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mempool struct {
|
||||||
|
cache cache.Cache
|
||||||
|
bus EventBus.Bus
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMempool(bus EventBus.Bus) (*Mempool, error) {
|
||||||
|
mp := &Mempool{
|
||||||
|
cache: cache.NewInMemoryCache(), // here we need to use separate cache
|
||||||
|
bus: bus,
|
||||||
|
}
|
||||||
|
|
||||||
|
return mp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *Mempool) StoreTx(tx *types2.Transaction) error {
|
||||||
|
hashStr := hex.EncodeToString(tx.Hash)
|
||||||
|
err := mp.cache.StoreWithTTL(DefaultTxPrefix+hashStr, tx, DefaultTxTTL)
|
||||||
|
logrus.WithField("txHash", hex.EncodeToString(tx.Hash)).Info("Submitted new transaction in mempool")
|
||||||
|
mp.bus.Publish("mempool:transactionAdded", tx)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *Mempool) DeleteTx(txHash []byte) error {
|
||||||
|
hashStr := hex.EncodeToString(txHash)
|
||||||
|
var tx types2.Transaction
|
||||||
|
err := mp.cache.Get(DefaultTxPrefix+hashStr, &tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mp.cache.Delete(DefaultTxPrefix + hashStr)
|
||||||
|
logrus.WithField("txHash", hex.EncodeToString(txHash)).Debugf("Deleted transaction from mempool")
|
||||||
|
mp.bus.Publish("mempool:transactionRemoved", tx)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *Mempool) GetTransactionsForNewBlock() []*types2.Transaction {
|
||||||
|
var txForBlock []*types2.Transaction
|
||||||
|
allTxs := mp.GetAllTransactions()
|
||||||
|
sort.Slice(allTxs, func(i, j int) bool {
|
||||||
|
return allTxs[i].Timestamp.Before(allTxs[j].Timestamp)
|
||||||
|
})
|
||||||
|
|
||||||
|
for i := 0; i < policy.BlockMaxTransactionCount; i++ {
|
||||||
|
if len(allTxs) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
tx := allTxs[0] // get oldest tx
|
||||||
|
allTxs = allTxs[1:] // pop tx
|
||||||
|
txForBlock = append(txForBlock, tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return txForBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *Mempool) GetAllTransactions() []*types2.Transaction {
|
||||||
|
var allTxs []*types2.Transaction
|
||||||
|
|
||||||
|
for _, v := range mp.cache.Items() {
|
||||||
|
tx := v.(*types2.Transaction)
|
||||||
|
allTxs = append(allTxs, tx)
|
||||||
|
}
|
||||||
|
return allTxs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *Mempool) GetTransaction(hash []byte) (*types2.Transaction, error) {
|
||||||
|
hashStr := hex.EncodeToString(hash)
|
||||||
|
var tx types2.Transaction
|
||||||
|
err := mp.cache.Get(DefaultTxPrefix+hashStr, &tx)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, cache.ErrNotFound) {
|
||||||
|
return nil, ErrTxNotFound
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tx, nil
|
||||||
|
}
|
278
blockchain/sync/sync_mgr.go
Normal file
278
blockchain/sync/sync_mgr.go
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/fxamacker/cbor/v2"
|
||||||
|
|
||||||
|
"github.com/asaskevich/EventBus"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain/utils"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/pubsub"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/consensus/policy"
|
||||||
|
|
||||||
|
"github.com/wealdtech/go-merkletree/keccak256"
|
||||||
|
|
||||||
|
"github.com/wealdtech/go-merkletree"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/node/wire"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
|
||||||
|
types2 "github.com/Secured-Finance/dione/blockchain/types"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain/pool"
|
||||||
|
gorpc "github.com/libp2p/go-libp2p-gorpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SyncManager interface {
|
||||||
|
Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
type syncManager struct {
|
||||||
|
blockpool *blockchain.BlockChain
|
||||||
|
mempool *pool.Mempool
|
||||||
|
wg sync.WaitGroup
|
||||||
|
ctx context.Context
|
||||||
|
ctxCancelFunc context.CancelFunc
|
||||||
|
initialSyncCompleted bool
|
||||||
|
bootstrapPeer peer.ID
|
||||||
|
rpcClient *gorpc.Client
|
||||||
|
psb *pubsub.PubSubRouter
|
||||||
|
bus EventBus.Bus
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSyncManager(bus EventBus.Bus, bc *blockchain.BlockChain, mp *pool.Mempool, p2pRPCClient *gorpc.Client, bootstrapPeer peer.ID, psb *pubsub.PubSubRouter) SyncManager {
|
||||||
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||||
|
sm := &syncManager{
|
||||||
|
bus: bus,
|
||||||
|
blockpool: bc,
|
||||||
|
mempool: mp,
|
||||||
|
ctx: ctx,
|
||||||
|
ctxCancelFunc: cancelFunc,
|
||||||
|
initialSyncCompleted: false,
|
||||||
|
bootstrapPeer: bootstrapPeer,
|
||||||
|
rpcClient: p2pRPCClient,
|
||||||
|
psb: psb,
|
||||||
|
}
|
||||||
|
|
||||||
|
return sm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *syncManager) Run() {
|
||||||
|
sm.psb.Hook(pubsub.NewTxMessageType, sm.onNewTransaction)
|
||||||
|
sm.psb.Hook(pubsub.NewBlockMessageType, sm.onNewBlock)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := sm.initialSync(); err != nil {
|
||||||
|
logrus.Error(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *syncManager) initialSync() error {
|
||||||
|
if err := sm.doInitialBlockPoolSync(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := sm.doInitialMempoolSync(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sm.bus.Publish("sync:initialSyncCompleted")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *syncManager) doInitialBlockPoolSync() error {
|
||||||
|
if sm.initialSyncCompleted {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ourLastHeight, _ := sm.blockpool.GetLatestBlockHeight()
|
||||||
|
|
||||||
|
if sm.bootstrapPeer == "" {
|
||||||
|
return nil // FIXME
|
||||||
|
}
|
||||||
|
|
||||||
|
var reply wire.LastBlockHeightReply
|
||||||
|
err := sm.rpcClient.Call(sm.bootstrapPeer, "NetworkService", "LastBlockHeight", nil, &reply)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if reply.Height > ourLastHeight {
|
||||||
|
heightCount := reply.Height - ourLastHeight
|
||||||
|
var from uint64
|
||||||
|
to := ourLastHeight
|
||||||
|
var receivedBlocks []types2.Block
|
||||||
|
for heightCount > 0 {
|
||||||
|
from = to + 1
|
||||||
|
var addedVal uint64
|
||||||
|
if heightCount < policy.MaxBlockCountForRetrieving {
|
||||||
|
addedVal = heightCount
|
||||||
|
} else {
|
||||||
|
addedVal = policy.MaxBlockCountForRetrieving
|
||||||
|
}
|
||||||
|
heightCount -= addedVal
|
||||||
|
to += addedVal
|
||||||
|
var getBlocksReply wire.GetRangeOfBlocksReply
|
||||||
|
arg := wire.GetRangeOfBlocksArg{From: from, To: to}
|
||||||
|
err = sm.rpcClient.Call(sm.bootstrapPeer, "NetworkService", "GetRangeOfBlocks", arg, &getBlocksReply)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
receivedBlocks = append(receivedBlocks, getBlocksReply.Blocks...)
|
||||||
|
if len(getBlocksReply.FailedBlockHeights) != 0 {
|
||||||
|
logrus.Warnf("remote node is unable to retrieve block heights: %s", strings.Trim(strings.Join(strings.Fields(fmt.Sprint(getBlocksReply.FailedBlockHeights)), ", "), "[]"))
|
||||||
|
// FIXME we definitely need to handle it, because in that case our chain isn't complete!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, b := range receivedBlocks {
|
||||||
|
err := sm.processReceivedBlock(b) // it should process the block synchronously
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("unable to process block %d: %s", b.Header.Height, err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// FIXME probably we need to pick up better peer for syncing, because chain of current peer can be out-of-date as well
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *syncManager) doInitialMempoolSync() error {
|
||||||
|
if sm.bootstrapPeer == "" {
|
||||||
|
return nil // FIXME
|
||||||
|
}
|
||||||
|
|
||||||
|
var reply wire.InvMessage
|
||||||
|
err := sm.rpcClient.Call(sm.bootstrapPeer, "NetworkService", "Mempool", nil, &reply)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var txsToRetrieve [][]byte
|
||||||
|
|
||||||
|
for _, v := range reply.Inventory {
|
||||||
|
_, err = sm.mempool.GetTransaction(v.Hash)
|
||||||
|
if errors.Is(err, pool.ErrTxNotFound) {
|
||||||
|
txsToRetrieve = append(txsToRetrieve, v.Hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
var txHashes [][]byte
|
||||||
|
|
||||||
|
if len(txsToRetrieve) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(txsToRetrieve) > policy.MaxTransactionCountForRetrieving {
|
||||||
|
txHashes = txsToRetrieve[:policy.MaxTransactionCountForRetrieving]
|
||||||
|
txsToRetrieve = txsToRetrieve[policy.MaxTransactionCountForRetrieving:]
|
||||||
|
} else {
|
||||||
|
txHashes = txsToRetrieve
|
||||||
|
txsToRetrieve = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
getMempoolTxArg := wire.GetMempoolTxsArg{
|
||||||
|
Items: txHashes,
|
||||||
|
}
|
||||||
|
var getMempoolTxReply wire.GetMempoolTxsReply
|
||||||
|
err := sm.rpcClient.Call(sm.bootstrapPeer, "NetworkService", "GetMempoolTxs", getMempoolTxArg, &getMempoolTxReply)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, v := range getMempoolTxReply.Transactions {
|
||||||
|
err := sm.mempool.StoreTx(&v)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO handle not found transactions
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *syncManager) processReceivedBlock(block types2.Block) error {
|
||||||
|
// validate block
|
||||||
|
previousBlockHeader, err := sm.blockpool.FetchBlockHeaderByHeight(block.Header.Height - 1)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to retrieve previous block %d", block.Header.Height-1)
|
||||||
|
}
|
||||||
|
if bytes.Compare(block.Header.LastHash, previousBlockHeader.Hash) != 0 {
|
||||||
|
return fmt.Errorf("block header has invalid last block hash")
|
||||||
|
}
|
||||||
|
verified, err := merkletree.VerifyProofUsing(previousBlockHeader.Hash, false, block.Header.LastHashProof, [][]byte{block.Header.Hash}, keccak256.New())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to verify last block hash merkle proof: %w", err)
|
||||||
|
}
|
||||||
|
if !verified {
|
||||||
|
return fmt.Errorf("merkle hash of current block doesn't contain hash of previous block")
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if hashes of block transactions are present in the block hash merkle tree
|
||||||
|
for _, tx := range block.Data { // FIXME we need to do something with rejected txs
|
||||||
|
if err := utils.VerifyTx(block.Header, tx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sm.blockpool.StoreBlock(&block)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to store block in blockpool: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *syncManager) onNewTransaction(message *pubsub.PubSubMessage) {
|
||||||
|
var tx types2.Transaction
|
||||||
|
err := cbor.Unmarshal(message.Payload, &tx)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("failed to convert payload to transaction: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO add more checks on tx
|
||||||
|
if !tx.ValidateHash() {
|
||||||
|
logrus.WithField("txHash", hex.EncodeToString(tx.Hash)).Warn("failed to validate transaction hash, rejecting it")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sm.mempool.StoreTx(&tx)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("failed to store incoming transaction in mempool: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *syncManager) onNewBlock(message *pubsub.PubSubMessage) {
|
||||||
|
var block types2.Block
|
||||||
|
|
||||||
|
err := cbor.Unmarshal(message.Payload, &block)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithField("err", err.Error()).Error("failed to unmarshal payload of NewBlock message")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sm.blockpool.StoreBlock(&block)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"err": err.Error(),
|
||||||
|
"blockHash": fmt.Sprintf("%x", block.Header.Hash),
|
||||||
|
}).Error("failed to store block from NewBlock message")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
109
blockchain/types/block.go
Normal file
109
blockchain/types/block.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/types"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/crypto"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
|
"github.com/wealdtech/go-merkletree"
|
||||||
|
"github.com/wealdtech/go-merkletree/keccak256"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Block struct {
|
||||||
|
Header *BlockHeader
|
||||||
|
Data []*Transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlockHeader struct {
|
||||||
|
Timestamp int64
|
||||||
|
Height uint64
|
||||||
|
Hash []byte
|
||||||
|
LastHash []byte
|
||||||
|
LastHashProof *merkletree.Proof
|
||||||
|
Proposer *peer.ID
|
||||||
|
ProposerEth common.Address
|
||||||
|
Signature []byte
|
||||||
|
BeaconEntry types.BeaconEntry
|
||||||
|
ElectionProof *types.ElectionProof
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenesisBlock() *Block {
|
||||||
|
return &Block{
|
||||||
|
Header: &BlockHeader{
|
||||||
|
Timestamp: 1620845070,
|
||||||
|
Height: 0,
|
||||||
|
Hash: []byte("DIMICANDUM"),
|
||||||
|
},
|
||||||
|
Data: []*Transaction{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateBlock(lastBlockHeader *BlockHeader, txs []*Transaction, minerEth common.Address, privateKey crypto.PrivKey, eproof *types.ElectionProof) (*Block, error) {
|
||||||
|
timestamp := time.Now().UnixNano()
|
||||||
|
|
||||||
|
// extract hashes from transactions
|
||||||
|
var merkleHashes [][]byte
|
||||||
|
for _, tx := range txs {
|
||||||
|
merkleHashes = append(merkleHashes, tx.Hash)
|
||||||
|
}
|
||||||
|
merkleHashes = append(merkleHashes, lastBlockHeader.Hash)
|
||||||
|
timestampBytes := make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(timestampBytes, uint64(timestamp))
|
||||||
|
merkleHashes = append(merkleHashes, timestampBytes)
|
||||||
|
|
||||||
|
tree, err := merkletree.NewUsing(merkleHashes, keccak256.New(), true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch merkle tree root hash (block hash)
|
||||||
|
blockHash := tree.Root()
|
||||||
|
|
||||||
|
// sign the block hash
|
||||||
|
s, err := privateKey.Sign(blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
lastHashProof, err := tree.GenerateProof(lastBlockHeader.Hash, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
proposer, err := peer.IDFromPrivateKey(privateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tx := range txs {
|
||||||
|
mp, err := tree.GenerateProof(tx.Hash, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tx.MerkleProof = mp
|
||||||
|
}
|
||||||
|
|
||||||
|
block := &Block{
|
||||||
|
Header: &BlockHeader{
|
||||||
|
Timestamp: timestamp,
|
||||||
|
Height: lastBlockHeader.Height + 1,
|
||||||
|
Proposer: &proposer,
|
||||||
|
ProposerEth: minerEth,
|
||||||
|
Signature: s,
|
||||||
|
Hash: blockHash,
|
||||||
|
LastHash: lastBlockHeader.Hash,
|
||||||
|
LastHashProof: lastHashProof,
|
||||||
|
ElectionProof: eproof,
|
||||||
|
},
|
||||||
|
Data: txs,
|
||||||
|
}
|
||||||
|
|
||||||
|
return block, nil
|
||||||
|
}
|
36
blockchain/types/transaction.go
Normal file
36
blockchain/types/transaction.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/wealdtech/go-merkletree"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Transaction struct {
|
||||||
|
Hash []byte
|
||||||
|
MerkleProof *merkletree.Proof // sets when transaction is added to block
|
||||||
|
Timestamp time.Time
|
||||||
|
Data []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateTransaction(data []byte) *Transaction {
|
||||||
|
timestamp := time.Now()
|
||||||
|
encodedData := hex.EncodeToString(data)
|
||||||
|
hash := crypto.Keccak256([]byte(fmt.Sprintf("%s", encodedData)))
|
||||||
|
return &Transaction{
|
||||||
|
Hash: hash,
|
||||||
|
Timestamp: timestamp,
|
||||||
|
Data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *Transaction) ValidateHash() bool {
|
||||||
|
encodedData := hex.EncodeToString(tx.Data)
|
||||||
|
h := crypto.Keccak256([]byte(fmt.Sprintf("%s", encodedData)))
|
||||||
|
return bytes.Equal(h, tx.Hash)
|
||||||
|
}
|
96
blockchain/utils/index.go
Normal file
96
blockchain/utils/index.go
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ledgerwatch/lmdb-go/lmdb"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultIndexPrefix = "indexes/"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrIndexKeyNotFound = fmt.Errorf("key is not found in the index")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Index struct {
|
||||||
|
name string
|
||||||
|
dbEnv *lmdb.Env
|
||||||
|
db lmdb.DBI
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIndex(name string, dbEnv *lmdb.Env, db lmdb.DBI) *Index {
|
||||||
|
return &Index{
|
||||||
|
name: name,
|
||||||
|
db: db,
|
||||||
|
dbEnv: dbEnv,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Index) PutUint64(key []byte, value uint64) error {
|
||||||
|
return i.dbEnv.Update(func(txn *lmdb.Txn) error {
|
||||||
|
data := make([]byte, 8)
|
||||||
|
binary.LittleEndian.PutUint64(data, value)
|
||||||
|
return txn.Put(i.db, i.constructIndexKey(key), data, 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Index) GetUint64(key []byte) (uint64, error) {
|
||||||
|
var num uint64
|
||||||
|
err := i.dbEnv.View(func(txn *lmdb.Txn) error {
|
||||||
|
data, err := txn.Get(i.db, i.constructIndexKey(key))
|
||||||
|
if err != nil {
|
||||||
|
if lmdb.IsNotFound(err) {
|
||||||
|
return ErrIndexKeyNotFound
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
num = binary.LittleEndian.Uint64(data)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return num, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Index) PutBytes(key []byte, value []byte) error {
|
||||||
|
return i.dbEnv.Update(func(txn *lmdb.Txn) error {
|
||||||
|
return txn.Put(i.db, i.constructIndexKey(key), value, 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Index) GetBytes(key []byte) ([]byte, error) {
|
||||||
|
var data []byte
|
||||||
|
err := i.dbEnv.View(func(txn *lmdb.Txn) error {
|
||||||
|
valueData, err := txn.Get(i.db, i.constructIndexKey(key))
|
||||||
|
if err != nil {
|
||||||
|
if lmdb.IsNotFound(err) {
|
||||||
|
return ErrIndexKeyNotFound
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data = valueData
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Index) Delete(key []byte) error {
|
||||||
|
return i.dbEnv.Update(func(txn *lmdb.Txn) error {
|
||||||
|
return txn.Del(i.db, i.constructIndexKey(key), nil)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Index) constructIndexKey(key []byte) []byte {
|
||||||
|
k := hex.EncodeToString(key)
|
||||||
|
return []byte(fmt.Sprintf("%s/%s/%s", DefaultIndexPrefix, i.name, k))
|
||||||
|
}
|
27
blockchain/utils/verification.go
Normal file
27
blockchain/utils/verification.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain/types"
|
||||||
|
"github.com/wealdtech/go-merkletree"
|
||||||
|
"github.com/wealdtech/go-merkletree/keccak256"
|
||||||
|
)
|
||||||
|
|
||||||
|
func VerifyTx(blockHeader *types.BlockHeader, tx *types.Transaction) error {
|
||||||
|
if tx.MerkleProof == nil {
|
||||||
|
return fmt.Errorf("block transaction doesn't have merkle proof")
|
||||||
|
}
|
||||||
|
txProofVerified, err := merkletree.VerifyProofUsing(tx.Hash, true, tx.MerkleProof, [][]byte{blockHeader.Hash}, keccak256.New())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to verify tx hash merkle proof: %s", err.Error())
|
||||||
|
}
|
||||||
|
if !txProofVerified {
|
||||||
|
return fmt.Errorf("transaction doesn't present in block hash merkle tree")
|
||||||
|
}
|
||||||
|
if !tx.ValidateHash() {
|
||||||
|
return fmt.Errorf("transaction hash is invalid")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
17
cache/cache.go
vendored
Normal file
17
cache/cache.go
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrNotFound = errors.New("key doesn't exist in cache")
|
||||||
|
|
||||||
|
type Cache interface {
|
||||||
|
Store(key string, value interface{}) error
|
||||||
|
StoreWithTTL(key string, value interface{}, ttl time.Duration) error
|
||||||
|
Get(key string, value interface{}) error
|
||||||
|
Delete(key string)
|
||||||
|
Items() map[string]interface{}
|
||||||
|
Exists(key string) bool
|
||||||
|
}
|
9
cache/event_cache_interface.go
vendored
9
cache/event_cache_interface.go
vendored
@ -1,9 +0,0 @@
|
|||||||
package cache
|
|
||||||
|
|
||||||
import "github.com/Secured-Finance/dione/contracts/dioneOracle"
|
|
||||||
|
|
||||||
type EventCache interface {
|
|
||||||
Store(key string, event interface{}) error
|
|
||||||
GetOracleRequestEvent(key string) (*dioneOracle.DioneOracleNewOracleRequest, error)
|
|
||||||
Delete(key string)
|
|
||||||
}
|
|
50
cache/event_log_cache.go
vendored
50
cache/event_log_cache.go
vendored
@ -1,50 +0,0 @@
|
|||||||
package cache
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Secured-Finance/dione/contracts/dioneOracle"
|
|
||||||
"github.com/VictoriaMetrics/fastcache"
|
|
||||||
"github.com/fxamacker/cbor/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// in megabytes
|
|
||||||
DefaultEventLogCacheCapacity = 32000000
|
|
||||||
)
|
|
||||||
|
|
||||||
type EventLogCache struct {
|
|
||||||
cache *fastcache.Cache
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEventLogCache() *EventLogCache {
|
|
||||||
return &EventLogCache{
|
|
||||||
cache: fastcache.New(DefaultEventLogCacheCapacity),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (elc *EventLogCache) Store(key string, event interface{}) error {
|
|
||||||
mRes, err := cbor.Marshal(event)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
elc.cache.SetBig([]byte(key), mRes)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (elc *EventLogCache) GetOracleRequestEvent(key string) (*dioneOracle.DioneOracleNewOracleRequest, error) {
|
|
||||||
var mData []byte
|
|
||||||
mData = elc.cache.GetBig(mData, []byte(key))
|
|
||||||
|
|
||||||
var event *dioneOracle.DioneOracleNewOracleRequest
|
|
||||||
err := cbor.Unmarshal(mData, &event)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return event, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (elc *EventLogCache) Delete(key string) {
|
|
||||||
elc.cache.Del([]byte(key))
|
|
||||||
}
|
|
58
cache/event_redis_cache.go
vendored
58
cache/event_redis_cache.go
vendored
@ -1,58 +0,0 @@
|
|||||||
package cache
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/config"
|
|
||||||
"github.com/Secured-Finance/dione/contracts/dioneOracle"
|
|
||||||
"github.com/fxamacker/cbor/v2"
|
|
||||||
"github.com/go-redis/redis/v8"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EventRedisCache struct {
|
|
||||||
Client *redis.Client
|
|
||||||
ctx context.Context
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewEventRedisCache(config *config.Config) *EventRedisCache {
|
|
||||||
client := redis.NewClient(&redis.Options{
|
|
||||||
Addr: config.Redis.Addr,
|
|
||||||
Password: config.Redis.Password,
|
|
||||||
DB: config.Redis.DB,
|
|
||||||
})
|
|
||||||
|
|
||||||
return &EventRedisCache{
|
|
||||||
Client: client,
|
|
||||||
ctx: context.Background(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (erc *EventRedisCache) Store(key string, event interface{}) error {
|
|
||||||
mRes, err := cbor.Marshal(event)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
erc.Client.Set(erc.ctx, key, mRes, 0)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (erc *EventRedisCache) GetOracleRequestEvent(key string) (*dioneOracle.DioneOracleNewOracleRequest, error) {
|
|
||||||
mData, err := erc.Client.Get(erc.ctx, key).Bytes()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var event *dioneOracle.DioneOracleNewOracleRequest
|
|
||||||
err = cbor.Unmarshal(mData, &event)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return event, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (erc *EventRedisCache) Delete(key string) {
|
|
||||||
erc.Client.Del(erc.ctx, key)
|
|
||||||
}
|
|
69
cache/inmemory_cache.go
vendored
Normal file
69
cache/inmemory_cache.go
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/patrickmn/go-cache"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultCacheExpiration = 5 * time.Minute
|
||||||
|
DefaultGCInterval = 10 * time.Minute
|
||||||
|
)
|
||||||
|
|
||||||
|
type InMemoryCache struct {
|
||||||
|
cache *cache.Cache
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInMemoryCache() Cache {
|
||||||
|
return &InMemoryCache{
|
||||||
|
cache: cache.New(DefaultCacheExpiration, DefaultGCInterval),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (imc *InMemoryCache) Store(key string, value interface{}) error {
|
||||||
|
imc.cache.Set(key, value, cache.NoExpiration)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (imc *InMemoryCache) StoreWithTTL(key string, value interface{}, ttl time.Duration) error {
|
||||||
|
imc.cache.Set(key, value, ttl)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (imc *InMemoryCache) Get(key string, value interface{}) error {
|
||||||
|
v, exists := imc.cache.Get(key)
|
||||||
|
if !exists {
|
||||||
|
return ErrNotFound
|
||||||
|
}
|
||||||
|
reflectedValue := reflect.ValueOf(value)
|
||||||
|
if reflectedValue.Kind() != reflect.Ptr {
|
||||||
|
return fmt.Errorf("value isn't a pointer")
|
||||||
|
}
|
||||||
|
if reflectedValue.IsNil() {
|
||||||
|
reflectedValue.Set(reflect.New(reflectedValue.Type().Elem()))
|
||||||
|
}
|
||||||
|
reflectedValue.Elem().Set(reflect.ValueOf(v).Elem())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (imc *InMemoryCache) Delete(key string) {
|
||||||
|
imc.cache.Delete(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (imc *InMemoryCache) Items() map[string]interface{} {
|
||||||
|
m := make(map[string]interface{})
|
||||||
|
for k, v := range imc.cache.Items() {
|
||||||
|
m[k] = v.Object
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (imc *InMemoryCache) Exists(key string) bool {
|
||||||
|
_, exists := imc.cache.Get(key)
|
||||||
|
return exists
|
||||||
|
}
|
98
cache/redis_cache.go
vendored
Normal file
98
cache/redis_cache.go
vendored
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/gob"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/config"
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RedisCache struct {
|
||||||
|
Client *redis.Client
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRedisCache(config *config.Config) *RedisCache {
|
||||||
|
client := redis.NewClient(&redis.Options{
|
||||||
|
Addr: config.Redis.Addr,
|
||||||
|
Password: config.Redis.Password,
|
||||||
|
DB: config.Redis.DB,
|
||||||
|
})
|
||||||
|
|
||||||
|
return &RedisCache{
|
||||||
|
Client: client,
|
||||||
|
ctx: context.Background(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *RedisCache) Store(key string, value interface{}) error {
|
||||||
|
data, err := gobMarshal(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.Client.Set(rc.ctx, key, data, 0)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *RedisCache) StoreWithTTL(key string, value interface{}, ttl time.Duration) error {
|
||||||
|
data, err := gobMarshal(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rc.Client.Set(rc.ctx, key, data, ttl)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func gobMarshal(val interface{}) ([]byte, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
enc := gob.NewEncoder(buf)
|
||||||
|
err := enc.Encode(val)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func gobUnmarshal(data []byte, val interface{}) error {
|
||||||
|
buf := bytes.NewBuffer(data)
|
||||||
|
dec := gob.NewDecoder(buf)
|
||||||
|
return dec.Decode(&val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *RedisCache) Get(key string, value interface{}) error {
|
||||||
|
data, err := rc.Client.Get(rc.ctx, key).Bytes()
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, redis.Nil) {
|
||||||
|
return ErrNotFound
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gobUnmarshal(data, &value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *RedisCache) Delete(key string) {
|
||||||
|
rc.Client.Del(rc.ctx, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *RedisCache) Items() map[string]interface{} {
|
||||||
|
return nil // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *RedisCache) Exists(key string) bool {
|
||||||
|
res := rc.Client.Exists(context.TODO(), key)
|
||||||
|
if res.Err() != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if res.Val() == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
@ -14,11 +14,13 @@ type Config struct {
|
|||||||
Rendezvous string `mapstructure:"rendezvous"`
|
Rendezvous string `mapstructure:"rendezvous"`
|
||||||
Ethereum EthereumConfig `mapstructure:"ethereum"`
|
Ethereum EthereumConfig `mapstructure:"ethereum"`
|
||||||
Filecoin FilecoinConfig `mapstructure:"filecoin"`
|
Filecoin FilecoinConfig `mapstructure:"filecoin"`
|
||||||
PubSub PubSubConfig `mapstructure:"pubSub"`
|
PubSub PubSubConfig `mapstructure:"pubsub"`
|
||||||
Store StoreConfig `mapstructure:"store"`
|
Store StoreConfig `mapstructure:"store"`
|
||||||
ConsensusMinApprovals int `mapstructure:"consensus_min_approvals"`
|
ConsensusMinApprovals int `mapstructure:"consensus_min_approvals"`
|
||||||
Redis RedisConfig `mapstructure:"redis"`
|
Redis RedisConfig `mapstructure:"redis"`
|
||||||
CacheType string `mapstructure:"cache_type"`
|
CacheType string `mapstructure:"cache_type"`
|
||||||
|
Blockchain BlockchainConfig `mapstructure:"blockchain"`
|
||||||
|
PrivateKeyPath string `mapstructure:"private_key_path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type EthereumConfig struct {
|
type EthereumConfig struct {
|
||||||
@ -39,8 +41,7 @@ type FilecoinConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type PubSubConfig struct {
|
type PubSubConfig struct {
|
||||||
ProtocolID string `mapstructure:"protocolID"`
|
ServiceTopicName string `mapstructure:"service_topic_name"`
|
||||||
ServiceTopicName string `mapstructure:"serviceTopicName"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type StoreConfig struct {
|
type StoreConfig struct {
|
||||||
@ -53,6 +54,10 @@ type RedisConfig struct {
|
|||||||
DB int `mapstructure:"redis_db"`
|
DB int `mapstructure:"redis_db"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BlockchainConfig struct {
|
||||||
|
DatabasePath string `mapstructure:"database_path"`
|
||||||
|
}
|
||||||
|
|
||||||
// NewConfig creates a new config based on default values or provided .env file
|
// NewConfig creates a new config based on default values or provided .env file
|
||||||
func NewConfig(configPath string) (*Config, error) {
|
func NewConfig(configPath string) (*Config, error) {
|
||||||
dbName := "dione"
|
dbName := "dione"
|
||||||
@ -64,12 +69,12 @@ func NewConfig(configPath string) (*Config, error) {
|
|||||||
ListenAddr: "localhost",
|
ListenAddr: "localhost",
|
||||||
ListenPort: 8000,
|
ListenPort: 8000,
|
||||||
BootstrapNodes: []string{"/ip4/127.0.0.1/tcp/0"},
|
BootstrapNodes: []string{"/ip4/127.0.0.1/tcp/0"},
|
||||||
Rendezvous: "filecoin-p2p-oracle",
|
Rendezvous: "dione",
|
||||||
Ethereum: EthereumConfig{
|
Ethereum: EthereumConfig{
|
||||||
PrivateKey: "",
|
PrivateKey: "",
|
||||||
},
|
},
|
||||||
PubSub: PubSubConfig{
|
PubSub: PubSubConfig{
|
||||||
ProtocolID: "p2p-oracle",
|
ServiceTopicName: "dione",
|
||||||
},
|
},
|
||||||
Store: StoreConfig{
|
Store: StoreConfig{
|
||||||
DatabaseURL: dbURL,
|
DatabaseURL: dbURL,
|
||||||
|
@ -28,3 +28,5 @@ func NewDrandConfig() *DrandConfig {
|
|||||||
}
|
}
|
||||||
return cfg
|
return cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var DrandChainGenesisTime = uint64(1603603302)
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
var ExpectedLeadersPerEpoch = int64(5)
|
|
||||||
|
|
||||||
var TasksPerEpoch = uint64(ExpectedLeadersPerEpoch)
|
|
||||||
|
|
||||||
var ChainGenesis = uint64(1603603302)
|
|
||||||
|
|
||||||
var TaskEpochInterval = uint64(15)
|
|
5
config/win_config.go
Normal file
5
config/win_config.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import "math/big"
|
||||||
|
|
||||||
|
var ExpectedLeadersPerEpoch = big.NewInt(2)
|
@ -1,169 +1,424 @@
|
|||||||
package consensus
|
package consensus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sync"
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/cache"
|
drand2 "github.com/Secured-Finance/dione/beacon/drand"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
|
||||||
|
"github.com/fxamacker/cbor/v2"
|
||||||
|
|
||||||
|
"github.com/asaskevich/EventBus"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain"
|
||||||
|
|
||||||
|
types3 "github.com/Secured-Finance/dione/blockchain/types"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/crypto"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain/pool"
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/consensus/types"
|
"github.com/Secured-Finance/dione/consensus/types"
|
||||||
|
types2 "github.com/Secured-Finance/dione/types"
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/ethclient"
|
"github.com/Secured-Finance/dione/ethclient"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/pubsub"
|
"github.com/Secured-Finance/dione/pubsub"
|
||||||
types2 "github.com/Secured-Finance/dione/types"
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrNoAcceptedBlocks = errors.New("there is no accepted blocks")
|
||||||
)
|
)
|
||||||
|
|
||||||
type PBFTConsensusManager struct {
|
type PBFTConsensusManager struct {
|
||||||
|
bus EventBus.Bus
|
||||||
psb *pubsub.PubSubRouter
|
psb *pubsub.PubSubRouter
|
||||||
minApprovals int
|
privKey crypto.PrivKey
|
||||||
privKey []byte
|
|
||||||
msgLog *MessageLog
|
|
||||||
validator *ConsensusValidator
|
validator *ConsensusValidator
|
||||||
consensusMap map[string]*Consensus
|
|
||||||
ethereumClient *ethclient.EthereumClient
|
ethereumClient *ethclient.EthereumClient
|
||||||
miner *Miner
|
miner *blockchain.Miner
|
||||||
eventCache cache.EventCache
|
consensusRoundPool *ConsensusStatePool
|
||||||
|
mempool *pool.Mempool
|
||||||
|
blockchain *blockchain.BlockChain
|
||||||
|
address peer.ID
|
||||||
|
stateChangeChannels map[string]map[State][]chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Consensus struct {
|
func NewPBFTConsensusManager(
|
||||||
mutex sync.Mutex
|
bus EventBus.Bus,
|
||||||
Finished bool
|
psb *pubsub.PubSubRouter,
|
||||||
IsCurrentMinerLeader bool
|
privKey crypto.PrivKey,
|
||||||
Task *types2.DioneTask
|
ethereumClient *ethclient.EthereumClient,
|
||||||
}
|
miner *blockchain.Miner,
|
||||||
|
bc *blockchain.BlockChain,
|
||||||
|
bp *ConsensusStatePool,
|
||||||
|
db *drand2.DrandBeacon,
|
||||||
|
mempool *pool.Mempool,
|
||||||
|
address peer.ID,
|
||||||
|
) *PBFTConsensusManager {
|
||||||
|
pcm := &PBFTConsensusManager{
|
||||||
|
psb: psb,
|
||||||
|
miner: miner,
|
||||||
|
validator: NewConsensusValidator(miner, bc, db),
|
||||||
|
privKey: privKey,
|
||||||
|
ethereumClient: ethereumClient,
|
||||||
|
bus: bus,
|
||||||
|
consensusRoundPool: bp,
|
||||||
|
mempool: mempool,
|
||||||
|
blockchain: bc,
|
||||||
|
address: address,
|
||||||
|
stateChangeChannels: map[string]map[State][]chan bool{},
|
||||||
|
}
|
||||||
|
|
||||||
|
pcm.psb.Hook(pubsub.PrePrepareMessageType, pcm.handlePrePrepare)
|
||||||
|
pcm.psb.Hook(pubsub.PrepareMessageType, pcm.handlePrepare)
|
||||||
|
pcm.psb.Hook(pubsub.CommitMessageType, pcm.handleCommit)
|
||||||
|
|
||||||
|
pcm.bus.SubscribeAsync("beacon:newEntry", func(entry types2.BeaconEntry) {
|
||||||
|
pcm.onNewBeaconEntry(entry)
|
||||||
|
}, true)
|
||||||
|
|
||||||
|
pcm.bus.SubscribeAsync("consensus:newState", func(block *types3.Block, newStateNumber int) {
|
||||||
|
newState := State(newStateNumber) // hacky, because reflection panics if we pass int to a handler which has type-alias for int
|
||||||
|
|
||||||
|
consensusMessageType := types.ConsensusMessageTypeUnknown
|
||||||
|
|
||||||
|
switch newState {
|
||||||
|
case StateStatusPrePrepared:
|
||||||
|
{
|
||||||
|
logrus.WithField("blockHash", fmt.Sprintf("%x", block.Header.Hash)).Debugf("Entered into PREPREPARED state")
|
||||||
|
if *block.Header.Proposer == pcm.address {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
consensusMessageType = types.ConsensusMessageTypePrepare
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case StateStatusPrepared:
|
||||||
|
{
|
||||||
|
consensusMessageType = types.ConsensusMessageTypeCommit
|
||||||
|
logrus.WithField("blockHash", fmt.Sprintf("%x", block.Header.Hash)).Debugf("Entered into PREPARED state")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case StateStatusCommited:
|
||||||
|
{
|
||||||
|
logrus.WithField("blockHash", fmt.Sprintf("%x", block.Header.Hash)).Debugf("Entered into COMMITTED state")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if consensusMessageType == types.ConsensusMessageTypeUnknown {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
message, err := NewMessage(&types.ConsensusMessage{
|
||||||
|
Type: consensusMessageType,
|
||||||
|
Blockhash: block.Header.Hash,
|
||||||
|
}, pcm.privKey)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("Failed to create consensus message: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = pcm.psb.BroadcastToServiceTopic(message); err != nil {
|
||||||
|
logrus.Errorf("Failed to send consensus message: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}, true)
|
||||||
|
|
||||||
func NewPBFTConsensusManager(psb *pubsub.PubSubRouter, minApprovals int, privKey []byte, ethereumClient *ethclient.EthereumClient, miner *Miner, evc cache.EventCache) *PBFTConsensusManager {
|
|
||||||
pcm := &PBFTConsensusManager{}
|
|
||||||
pcm.psb = psb
|
|
||||||
pcm.miner = miner
|
|
||||||
pcm.validator = NewConsensusValidator(evc, miner)
|
|
||||||
pcm.msgLog = NewMessageLog()
|
|
||||||
pcm.minApprovals = minApprovals
|
|
||||||
pcm.privKey = privKey
|
|
||||||
pcm.ethereumClient = ethereumClient
|
|
||||||
pcm.eventCache = evc
|
|
||||||
pcm.consensusMap = map[string]*Consensus{}
|
|
||||||
pcm.psb.Hook(types.MessageTypePrePrepare, pcm.handlePrePrepare)
|
|
||||||
pcm.psb.Hook(types.MessageTypePrepare, pcm.handlePrepare)
|
|
||||||
pcm.psb.Hook(types.MessageTypeCommit, pcm.handleCommit)
|
|
||||||
return pcm
|
return pcm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pcm *PBFTConsensusManager) Propose(task types2.DioneTask) error {
|
func (pcm *PBFTConsensusManager) propose(blk *types3.Block) error {
|
||||||
pcm.createConsensusInfo(&task, true)
|
cmsg := &types.ConsensusMessage{
|
||||||
|
Type: StateStatusPrePrepared,
|
||||||
prePrepareMsg, err := CreatePrePrepareWithTaskSignature(&task, pcm.privKey)
|
Block: blk,
|
||||||
|
Blockhash: blk.Header.Hash,
|
||||||
|
From: pcm.address,
|
||||||
|
}
|
||||||
|
prePrepareMsg, err := NewMessage(cmsg, pcm.privKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
pcm.psb.BroadcastToServiceTopic(prePrepareMsg)
|
|
||||||
|
time.Sleep(1 * time.Second) // wait until all nodes will commit previous blocks
|
||||||
|
|
||||||
|
if err = pcm.consensusRoundPool.InsertMessageIntoLog(cmsg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = pcm.psb.BroadcastToServiceTopic(prePrepareMsg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithField("blockHash", fmt.Sprintf("%x", blk.Header.Hash)).Debugf("Entered into PREPREPARED state")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pcm *PBFTConsensusManager) handlePrePrepare(message *types.Message) {
|
func (pcm *PBFTConsensusManager) handlePrePrepare(message *pubsub.PubSubMessage) {
|
||||||
if message.Payload.Task.Miner == pcm.miner.address {
|
var prePrepare types.PrePrepareMessage
|
||||||
return
|
err := cbor.Unmarshal(message.Payload, &prePrepare)
|
||||||
}
|
|
||||||
if pcm.msgLog.Exists(*message) {
|
|
||||||
logrus.Debugf("received existing pre_prepare msg, dropping...")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !pcm.validator.Valid(*message) {
|
|
||||||
logrus.Warn("received invalid pre_prepare msg, dropping...")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pcm.msgLog.AddMessage(*message)
|
|
||||||
|
|
||||||
prepareMsg, err := NewMessage(message, types.MessageTypePrepare)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("failed to create prepare message: %v", err)
|
logrus.Errorf("failed to convert payload to PrePrepare message: %s", err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pcm.createConsensusInfo(&message.Payload.Task, false)
|
if *prePrepare.Block.Header.Proposer == pcm.address {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
pcm.psb.BroadcastToServiceTopic(&prepareMsg)
|
cmsg := &types.ConsensusMessage{
|
||||||
|
Type: types.ConsensusMessageTypePrePrepare,
|
||||||
|
From: message.From,
|
||||||
|
Block: prePrepare.Block,
|
||||||
|
Blockhash: prePrepare.Block.Header.Hash,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pcm.validator.Valid(cmsg) {
|
||||||
|
logrus.WithField("blockHash", hex.EncodeToString(cmsg.Block.Header.Hash)).Warn("Received invalid PREPREPARE for block")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = pcm.consensusRoundPool.InsertMessageIntoLog(cmsg)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithField("err", err.Error()).Warn("Failed to add PREPARE message to log")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"blockHash": fmt.Sprintf("%x", cmsg.Block.Header.Hash),
|
||||||
|
"from": message.From.String(),
|
||||||
|
}).Debug("Received PREPREPARE message")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pcm *PBFTConsensusManager) handlePrepare(message *types.Message) {
|
func (pcm *PBFTConsensusManager) handlePrepare(message *pubsub.PubSubMessage) {
|
||||||
if pcm.msgLog.Exists(*message) {
|
var prepare types.PrepareMessage
|
||||||
logrus.Debugf("received existing prepare msg, dropping...")
|
err := cbor.Unmarshal(message.Payload, &prepare)
|
||||||
return
|
|
||||||
}
|
|
||||||
if !pcm.validator.Valid(*message) {
|
|
||||||
logrus.Warn("received invalid prepare msg, dropping...")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pcm.msgLog.AddMessage(*message)
|
|
||||||
|
|
||||||
if len(pcm.msgLog.GetMessagesByTypeAndConsensusID(types.MessageTypePrepare, message.Payload.Task.ConsensusID)) >= pcm.minApprovals {
|
|
||||||
commitMsg, err := NewMessage(message, types.MessageTypeCommit)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("failed to create commit message: %w", err)
|
logrus.Errorf("failed to convert payload to Prepare message: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmsg := &types.ConsensusMessage{
|
||||||
|
Type: types.ConsensusMessageTypePrepare,
|
||||||
|
From: message.From,
|
||||||
|
Blockhash: prepare.Blockhash,
|
||||||
|
Signature: prepare.Signature,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pcm.validator.Valid(cmsg) {
|
||||||
|
logrus.Warnf("received invalid prepare msg for block %x", cmsg.Blockhash)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = pcm.consensusRoundPool.InsertMessageIntoLog(cmsg)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithField("err", err.Error()).Warn("Failed to add PREPARE message to log")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"blockHash": fmt.Sprintf("%x", cmsg.Blockhash),
|
||||||
|
"from": message.From.String(),
|
||||||
|
}).Debug("Received PREPARE message")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pcm *PBFTConsensusManager) handleCommit(message *pubsub.PubSubMessage) {
|
||||||
|
var commit types.CommitMessage
|
||||||
|
err := cbor.Unmarshal(message.Payload, &commit)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("failed to convert payload to Commit message: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cmsg := &types.ConsensusMessage{
|
||||||
|
Type: types.ConsensusMessageTypeCommit,
|
||||||
|
From: message.From,
|
||||||
|
Blockhash: commit.Blockhash,
|
||||||
|
Signature: commit.Signature,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pcm.validator.Valid(cmsg) {
|
||||||
|
logrus.Warnf("received invalid commit msg for block %x", cmsg.Blockhash)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = pcm.consensusRoundPool.InsertMessageIntoLog(cmsg)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithField("err", err.Error()).Warn("Failed to add COMMIT message to log")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"blockHash": fmt.Sprintf("%x", cmsg.Blockhash),
|
||||||
|
"from": message.From.String(),
|
||||||
|
}).Debug("Received COMMIT message")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pcm *PBFTConsensusManager) onNewBeaconEntry(entry types2.BeaconEntry) {
|
||||||
|
block, err := pcm.commitAcceptedBlocks()
|
||||||
|
height, _ := pcm.blockchain.GetLatestBlockHeight()
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, ErrNoAcceptedBlocks) {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"height": height + 1,
|
||||||
|
}).Infof("No accepted blocks in the current consensus round")
|
||||||
|
} else {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"height": height + 1,
|
||||||
|
"err": err.Error(),
|
||||||
|
}).Errorf("Failed to select the block in the current consensus round")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if block != nil {
|
||||||
|
// broadcast new block
|
||||||
|
var newBlockMessage pubsub.PubSubMessage
|
||||||
|
newBlockMessage.Type = pubsub.NewBlockMessageType
|
||||||
|
blockSerialized, err := cbor.Marshal(block)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("Failed to serialize block %x for broadcasting!", block.Header.Hash)
|
||||||
|
} else {
|
||||||
|
newBlockMessage.Payload = blockSerialized
|
||||||
|
pcm.psb.BroadcastToServiceTopic(&newBlockMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are miner of this block
|
||||||
|
// then post dione tasks to target chains (currently, only Ethereum)
|
||||||
|
if block.Header.Proposer.String() == pcm.address.String() {
|
||||||
|
pcm.submitTasksFromBlock(block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range pcm.stateChangeChannels {
|
||||||
|
for k1, j := range v {
|
||||||
|
for _, ch := range j {
|
||||||
|
ch <- true
|
||||||
|
close(ch)
|
||||||
|
}
|
||||||
|
delete(v, k1)
|
||||||
|
}
|
||||||
|
delete(pcm.stateChangeChannels, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
minedBlock, err := pcm.miner.MineBlock(entry.Data, entry.Round)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, blockchain.ErrNoTxForBlock) {
|
||||||
|
logrus.Info("Sealing skipped, no transactions in mempool")
|
||||||
|
} else {
|
||||||
|
logrus.Errorf("Failed to mine the block: %s", err.Error())
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we are round winner
|
||||||
|
if minedBlock != nil {
|
||||||
|
err = pcm.propose(minedBlock)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("Failed to propose the block: %s", err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
pcm.psb.BroadcastToServiceTopic(&commitMsg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pcm *PBFTConsensusManager) handleCommit(message *types.Message) {
|
func (pcm *PBFTConsensusManager) submitTasksFromBlock(block *types3.Block) {
|
||||||
if pcm.msgLog.Exists(*message) {
|
for _, tx := range block.Data {
|
||||||
logrus.Debugf("received existing commit msg, dropping...")
|
var task types2.DioneTask
|
||||||
return
|
err := cbor.Unmarshal(tx.Data, &task)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"err": err.Error(),
|
||||||
|
"txHash": hex.EncodeToString(tx.Hash),
|
||||||
|
}).Error("Failed to unmarshal transaction payload")
|
||||||
|
continue // FIXME
|
||||||
}
|
}
|
||||||
if !pcm.validator.Valid(*message) {
|
reqIDNumber, ok := big.NewInt(0).SetString(task.RequestID, 10)
|
||||||
logrus.Warn("received invalid commit msg, dropping...")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pcm.msgLog.AddMessage(*message)
|
|
||||||
|
|
||||||
consensusMsg := message.Payload
|
|
||||||
if len(pcm.msgLog.GetMessagesByTypeAndConsensusID(types.MessageTypeCommit, message.Payload.Task.ConsensusID)) >= pcm.minApprovals {
|
|
||||||
info := pcm.GetConsensusInfo(consensusMsg.Task.ConsensusID)
|
|
||||||
if info == nil {
|
|
||||||
logrus.Debugf("consensus doesn't exist in our consensus map - skipping...")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
info.mutex.Lock()
|
|
||||||
defer info.mutex.Unlock()
|
|
||||||
if info.Finished {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if info.IsCurrentMinerLeader {
|
|
||||||
logrus.Infof("Submitting on-chain result for consensus ID: %s", consensusMsg.Task.ConsensusID)
|
|
||||||
reqID, ok := new(big.Int).SetString(consensusMsg.Task.RequestID, 10)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
logrus.Errorf("Failed to parse request ID: %v", consensusMsg.Task.RequestID)
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"txHash": hex.EncodeToString(tx.Hash),
|
||||||
|
}).Error("Failed to parse request id number in Dione task")
|
||||||
|
continue // FIXME
|
||||||
}
|
}
|
||||||
|
|
||||||
err := pcm.ethereumClient.SubmitRequestAnswer(reqID, consensusMsg.Task.Payload)
|
err = pcm.ethereumClient.SubmitRequestAnswer(reqIDNumber, task.Payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Failed to submit on-chain result: %v", err)
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"err": err.Error(),
|
||||||
|
"txHash": hex.EncodeToString(tx.Hash),
|
||||||
|
"reqID": reqIDNumber.String(),
|
||||||
|
}).Error("Failed to submit task to ETH chain")
|
||||||
|
continue // FIXME
|
||||||
}
|
}
|
||||||
}
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"txHash": hex.EncodeToString(tx.Hash),
|
||||||
info.Finished = true
|
"reqID": reqIDNumber.String(),
|
||||||
|
}).Debug("Dione task has been sucessfully submitted to ETH chain (DioneOracle contract)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pcm *PBFTConsensusManager) createConsensusInfo(task *types2.DioneTask, isLeader bool) {
|
func (pcm *PBFTConsensusManager) commitAcceptedBlocks() (*types3.Block, error) {
|
||||||
if _, ok := pcm.consensusMap[task.ConsensusID]; !ok {
|
blocks := pcm.consensusRoundPool.GetAllBlocksWithCommit()
|
||||||
pcm.consensusMap[task.ConsensusID] = &Consensus{
|
if blocks == nil {
|
||||||
IsCurrentMinerLeader: isLeader,
|
return nil, ErrNoAcceptedBlocks
|
||||||
Task: task,
|
|
||||||
Finished: false,
|
|
||||||
}
|
}
|
||||||
}
|
var selectedBlock *types3.Block
|
||||||
}
|
|
||||||
|
|
||||||
func (pcm *PBFTConsensusManager) GetConsensusInfo(consensusID string) *Consensus {
|
sort.Slice(blocks, func(i, j int) bool {
|
||||||
c, ok := pcm.consensusMap[consensusID]
|
iStake, err := pcm.ethereumClient.GetMinerStake(blocks[i].Block.Header.ProposerEth)
|
||||||
if !ok {
|
if err != nil {
|
||||||
return nil
|
logrus.Error(err)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
jStake, err := pcm.ethereumClient.GetMinerStake(blocks[j].Block.Header.ProposerEth)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Error(err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if iStake.Cmp(jStake) == -1 {
|
||||||
|
return false
|
||||||
|
} else if iStake.Cmp(jStake) == 1 {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return blocks[i].Block.Header.Timestamp > blocks[j].Block.Header.Timestamp
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
selectedBlock = blocks[0].Block
|
||||||
|
|
||||||
|
stake, err := pcm.ethereumClient.GetMinerStake(selectedBlock.Header.ProposerEth)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Error(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"winCount": selectedBlock.Header.ElectionProof.WinCount,
|
||||||
|
"proposerStake": stake.String(),
|
||||||
|
}).Debug("Selected the block with maximal win count and proposer's stake.")
|
||||||
|
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"hash": hex.EncodeToString(selectedBlock.Header.Hash),
|
||||||
|
"height": selectedBlock.Header.Height,
|
||||||
|
"miner": selectedBlock.Header.Proposer.String(),
|
||||||
|
}).Info("Committed new block")
|
||||||
|
pcm.consensusRoundPool.Prune()
|
||||||
|
for _, v := range selectedBlock.Data {
|
||||||
|
err := pcm.mempool.DeleteTx(v.Hash)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"err": err.Error(),
|
||||||
|
"tx": hex.EncodeToString(v.Hash),
|
||||||
|
}).Errorf("Failed to delete committed tx from mempool")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return selectedBlock, pcm.blockchain.StoreBlock(selectedBlock)
|
||||||
}
|
}
|
||||||
|
126
consensus/consensus_round_pool.go
Normal file
126
consensus/consensus_round_pool.go
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package consensus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
types2 "github.com/Secured-Finance/dione/consensus/types"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain/pool"
|
||||||
|
|
||||||
|
"github.com/asaskevich/EventBus"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type State uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
StateStatusUnknown = iota
|
||||||
|
|
||||||
|
StateStatusPrePrepared
|
||||||
|
StateStatusPrepared
|
||||||
|
StateStatusCommited
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConsensusStatePool is pool for blocks that isn't not validated or committed yet
|
||||||
|
type ConsensusStatePool struct {
|
||||||
|
mempool *pool.Mempool
|
||||||
|
consensusInfoMap map[string]*ConsensusInfo
|
||||||
|
mapMutex sync.Mutex
|
||||||
|
bus EventBus.Bus
|
||||||
|
minApprovals int // FIXME
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConsensusRoundPool(mp *pool.Mempool, bus EventBus.Bus, minApprovals int) (*ConsensusStatePool, error) {
|
||||||
|
bp := &ConsensusStatePool{
|
||||||
|
consensusInfoMap: map[string]*ConsensusInfo{},
|
||||||
|
mempool: mp,
|
||||||
|
bus: bus,
|
||||||
|
minApprovals: minApprovals,
|
||||||
|
}
|
||||||
|
|
||||||
|
return bp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConsensusInfo struct {
|
||||||
|
Blockhash []byte
|
||||||
|
Block *types.Block
|
||||||
|
State State
|
||||||
|
MessageLog *ConsensusMessageLog
|
||||||
|
}
|
||||||
|
|
||||||
|
func (crp *ConsensusStatePool) InsertMessageIntoLog(cmsg *types2.ConsensusMessage) error {
|
||||||
|
crp.mapMutex.Lock()
|
||||||
|
defer crp.mapMutex.Unlock()
|
||||||
|
consensusInfo, ok := crp.consensusInfoMap[hex.EncodeToString(cmsg.Blockhash)]
|
||||||
|
if !ok {
|
||||||
|
consensusInfo = &ConsensusInfo{
|
||||||
|
Block: cmsg.Block,
|
||||||
|
Blockhash: cmsg.Blockhash,
|
||||||
|
State: StateStatusUnknown,
|
||||||
|
MessageLog: NewConsensusMessageLog(),
|
||||||
|
}
|
||||||
|
crp.consensusInfoMap[hex.EncodeToString(cmsg.Blockhash)] = consensusInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
added := consensusInfo.MessageLog.AddMessage(cmsg)
|
||||||
|
if !added {
|
||||||
|
return fmt.Errorf("consensus message already exists in message log")
|
||||||
|
}
|
||||||
|
|
||||||
|
crp.maybeUpdateConsensusState(consensusInfo, cmsg)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (crp *ConsensusStatePool) maybeUpdateConsensusState(ci *ConsensusInfo, cmsg *types2.ConsensusMessage) {
|
||||||
|
if ci.State == StateStatusUnknown && cmsg.Type == types2.ConsensusMessageTypePrePrepare && cmsg.Block != nil {
|
||||||
|
ci.Block = cmsg.Block
|
||||||
|
logrus.WithField("hash", fmt.Sprintf("%x", cmsg.Block.Header.Hash)).Debug("New block discovered")
|
||||||
|
ci.State = StateStatusPrePrepared
|
||||||
|
crp.bus.Publish("consensus:newState", ci.Block, StateStatusPrePrepared)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ci.MessageLog.Get(types2.ConsensusMessageTypePrepare, cmsg.Blockhash)) >= crp.minApprovals-1 && ci.State == StateStatusPrePrepared { // FIXME approval across 2f nodes
|
||||||
|
ci.State = StateStatusPrepared
|
||||||
|
crp.bus.Publish("consensus:newState", ci.Block, StateStatusPrepared)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ci.MessageLog.Get(types2.ConsensusMessageTypeCommit, cmsg.Blockhash)) >= crp.minApprovals && ci.State == StateStatusPrepared { // FIXME approval across 2f+1 nodes
|
||||||
|
ci.State = StateStatusCommited
|
||||||
|
crp.bus.Publish("consensus:newState", ci.Block, StateStatusCommited)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prune cleans known blocks list. It is called when new consensus round starts.
|
||||||
|
func (crp *ConsensusStatePool) Prune() {
|
||||||
|
for k := range crp.consensusInfoMap {
|
||||||
|
delete(crp.consensusInfoMap, k)
|
||||||
|
}
|
||||||
|
crp.bus.Publish("blockpool:pruned")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (crp *ConsensusStatePool) GetAllBlocksWithCommit() []*ConsensusInfo {
|
||||||
|
crp.mapMutex.Lock()
|
||||||
|
defer crp.mapMutex.Unlock()
|
||||||
|
var consensusInfos []*ConsensusInfo
|
||||||
|
for _, v := range crp.consensusInfoMap {
|
||||||
|
if v.State == StateStatusCommited {
|
||||||
|
consensusInfos = append(consensusInfos, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return consensusInfos
|
||||||
|
}
|
||||||
|
|
||||||
|
//func containsTx(s []*types.Transaction, e *types.Transaction) bool {
|
||||||
|
// for _, a := range s {
|
||||||
|
// if bytes.Equal(a.Hash, e.Hash) {
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return false
|
||||||
|
//}
|
@ -1,156 +1,62 @@
|
|||||||
package consensus
|
package consensus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/Secured-Finance/dione/cache"
|
"encoding/hex"
|
||||||
types2 "github.com/Secured-Finance/dione/consensus/types"
|
|
||||||
"github.com/Secured-Finance/dione/consensus/validation"
|
drand2 "github.com/Secured-Finance/dione/beacon/drand"
|
||||||
"github.com/Secured-Finance/dione/types"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain"
|
||||||
|
types2 "github.com/Secured-Finance/dione/consensus/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConsensusValidator struct {
|
type ConsensusValidator struct {
|
||||||
validationFuncMap map[types2.MessageType]func(msg types2.Message) bool
|
validationFuncMap map[types2.ConsensusMessageType]func(msg *types2.ConsensusMessage) bool
|
||||||
eventCache cache.EventCache
|
miner *blockchain.Miner
|
||||||
miner *Miner
|
beacon *drand2.DrandBeacon
|
||||||
|
blockchain *blockchain.BlockChain
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConsensusValidator(ec cache.EventCache, miner *Miner) *ConsensusValidator {
|
func NewConsensusValidator(miner *blockchain.Miner, bc *blockchain.BlockChain, db *drand2.DrandBeacon) *ConsensusValidator {
|
||||||
cv := &ConsensusValidator{
|
cv := &ConsensusValidator{
|
||||||
eventCache: ec,
|
|
||||||
miner: miner,
|
miner: miner,
|
||||||
|
blockchain: bc,
|
||||||
|
beacon: db,
|
||||||
}
|
}
|
||||||
|
|
||||||
cv.validationFuncMap = map[types2.MessageType]func(msg types2.Message) bool{
|
cv.validationFuncMap = map[types2.ConsensusMessageType]func(msg *types2.ConsensusMessage) bool{
|
||||||
types2.MessageTypePrePrepare: func(msg types2.Message) bool {
|
types2.ConsensusMessageTypePrePrepare: func(msg *types2.ConsensusMessage) bool {
|
||||||
// TODO here we need to do validation of tx itself
|
if err := cv.blockchain.ValidateBlock(msg.Block); err != nil {
|
||||||
consensusMsg := msg.Payload
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"blockHash": hex.EncodeToString(msg.Block.Header.Hash),
|
||||||
// === verify task signature ===
|
"err": err.Error(),
|
||||||
err := VerifyTaskSignature(consensusMsg.Task)
|
}).Error("failed to validate block from PrePrepare message")
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("unable to verify signature: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
/////////////////////////////////
|
|
||||||
|
|
||||||
// === verify if request exists in event log cache ===
|
|
||||||
requestEvent, err := cv.eventCache.GetOracleRequestEvent("request_" + consensusMsg.Task.RequestID)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("the incoming request task event doesn't exist in the EVC, or is broken: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if requestEvent.OriginChain != consensusMsg.Task.OriginChain ||
|
|
||||||
requestEvent.RequestType != consensusMsg.Task.RequestType ||
|
|
||||||
requestEvent.RequestParams != consensusMsg.Task.RequestParams {
|
|
||||||
|
|
||||||
logrus.Errorf("the incoming task and cached request event don't match!")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
/////////////////////////////////
|
|
||||||
|
|
||||||
// === verify election proof wincount preliminarily ===
|
|
||||||
if consensusMsg.Task.ElectionProof.WinCount < 1 {
|
|
||||||
logrus.Error("miner isn't a winner!")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
/////////////////////////////////
|
|
||||||
|
|
||||||
// === verify miner's eligibility to propose this task ===
|
|
||||||
err = cv.miner.IsMinerEligibleToProposeTask(common.HexToAddress(consensusMsg.Task.MinerEth))
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("miner is not eligible to propose task: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
/////////////////////////////////
|
|
||||||
|
|
||||||
// === verify election proof vrf ===
|
|
||||||
minerAddressMarshalled, err := consensusMsg.Task.Miner.MarshalBinary()
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("failed to marshal miner address: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
electionProofRandomness, err := DrawRandomness(
|
|
||||||
consensusMsg.Task.BeaconEntries[1].Data,
|
|
||||||
crypto.DomainSeparationTag_ElectionProofProduction,
|
|
||||||
consensusMsg.Task.DrandRound,
|
|
||||||
minerAddressMarshalled,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("failed to draw electionProofRandomness: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
err = VerifyVRF(consensusMsg.Task.Miner, electionProofRandomness, consensusMsg.Task.ElectionProof.VRFProof)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("failed to verify election proof vrf: %v", err)
|
|
||||||
}
|
|
||||||
//////////////////////////////////////
|
|
||||||
|
|
||||||
// === verify ticket vrf ===
|
|
||||||
ticketRandomness, err := DrawRandomness(
|
|
||||||
consensusMsg.Task.BeaconEntries[1].Data,
|
|
||||||
crypto.DomainSeparationTag_TicketProduction,
|
|
||||||
consensusMsg.Task.DrandRound-types.TicketRandomnessLookback,
|
|
||||||
minerAddressMarshalled,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("failed to draw ticket electionProofRandomness: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
err = VerifyVRF(consensusMsg.Task.Miner, ticketRandomness, consensusMsg.Task.Ticket.VRFProof)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("failed to verify ticket vrf: %v", err)
|
|
||||||
}
|
|
||||||
//////////////////////////////////////
|
|
||||||
|
|
||||||
// === compute wincount locally and verify values ===
|
|
||||||
mStake, nStake, err := cv.miner.GetStakeInfo(common.HexToAddress(consensusMsg.Task.MinerEth))
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("failed to get miner stake: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
actualWinCount := consensusMsg.Task.ElectionProof.ComputeWinCount(*mStake, *nStake)
|
|
||||||
if consensusMsg.Task.ElectionProof.WinCount != actualWinCount {
|
|
||||||
logrus.Errorf("locally computed wincount isn't matching received value!", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
//////////////////////////////////////
|
|
||||||
|
|
||||||
// === validate payload by specific-chain checks ===
|
|
||||||
if validationFunc := validation.GetValidationMethod(consensusMsg.Task.OriginChain, consensusMsg.Task.RequestType); validationFunc != nil {
|
|
||||||
err := validationFunc(consensusMsg.Task.Payload)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("payload validation has failed: %v", err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
logrus.Debugf("Origin chain [%v]/request type[%v] doesn't have any payload validation!", consensusMsg.Task.OriginChain, consensusMsg.Task.RequestType)
|
|
||||||
}
|
|
||||||
/////////////////////////////////
|
|
||||||
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
types2.MessageTypePrepare: func(msg types2.Message) bool {
|
|
||||||
err := VerifyTaskSignature(msg.Payload.Task)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
types2.MessageTypeCommit: func(msg types2.Message) bool {
|
|
||||||
err := VerifyTaskSignature(msg.Payload.Task)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
types2.ConsensusMessageTypePrepare: checkSignatureForBlockhash,
|
||||||
|
types2.ConsensusMessageTypeCommit: checkSignatureForBlockhash,
|
||||||
}
|
}
|
||||||
|
|
||||||
return cv
|
return cv
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cv *ConsensusValidator) Valid(msg types2.Message) bool {
|
func (cv *ConsensusValidator) Valid(msg *types2.ConsensusMessage) bool {
|
||||||
return cv.validationFuncMap[msg.Type](msg)
|
return cv.validationFuncMap[msg.Type](msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkSignatureForBlockhash(msg *types2.ConsensusMessage) bool {
|
||||||
|
pubKey, err := msg.From.ExtractPublicKey()
|
||||||
|
if err != nil {
|
||||||
|
// TODO logging
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ok, err := pubKey.Verify(msg.Blockhash, msg.Signature)
|
||||||
|
if err != nil {
|
||||||
|
// TODO logging
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
@ -5,14 +5,21 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"math/big"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
|
||||||
|
types2 "github.com/Secured-Finance/dione/blockchain/types"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/types"
|
||||||
|
"github.com/fxamacker/cbor/v2"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"golang.org/x/crypto/sha3"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain"
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/contracts/dioneDispute"
|
"github.com/Secured-Finance/dione/contracts/dioneDispute"
|
||||||
"github.com/Secured-Finance/dione/contracts/dioneOracle"
|
"github.com/Secured-Finance/dione/contracts/dioneOracle"
|
||||||
"github.com/Secured-Finance/dione/ethclient"
|
"github.com/Secured-Finance/dione/ethclient"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"golang.org/x/crypto/sha3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type DisputeManager struct {
|
type DisputeManager struct {
|
||||||
@ -22,15 +29,22 @@ type DisputeManager struct {
|
|||||||
submissionMap map[string]*dioneOracle.DioneOracleSubmittedOracleRequest
|
submissionMap map[string]*dioneOracle.DioneOracleSubmittedOracleRequest
|
||||||
disputeMap map[string]*dioneDispute.DioneDisputeNewDispute
|
disputeMap map[string]*dioneDispute.DioneDisputeNewDispute
|
||||||
voteWindow time.Duration
|
voteWindow time.Duration
|
||||||
|
blockchain *blockchain.BlockChain
|
||||||
|
|
||||||
|
submissionChan chan *dioneOracle.DioneOracleSubmittedOracleRequest
|
||||||
|
submissionSubscription event.Subscription
|
||||||
|
|
||||||
|
disputesChan chan *dioneDispute.DioneDisputeNewDispute
|
||||||
|
disputesSubscription event.Subscription
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDisputeManager(ctx context.Context, ethClient *ethclient.EthereumClient, pcm *PBFTConsensusManager, voteWindow int) (*DisputeManager, error) {
|
func NewDisputeManager(ctx context.Context, ethClient *ethclient.EthereumClient, pcm *PBFTConsensusManager, voteWindow int, bc *blockchain.BlockChain) (*DisputeManager, error) {
|
||||||
newSubmittionsChan, submSubscription, err := ethClient.SubscribeOnNewSubmittions(ctx)
|
submissionChan, submSubscription, err := ethClient.SubscribeOnNewSubmittions(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
newDisputesChan, dispSubscription, err := ethClient.SubscribeOnNewDisputes(ctx)
|
disputesChan, dispSubscription, err := ethClient.SubscribeOnNewDisputes(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -42,54 +56,56 @@ func NewDisputeManager(ctx context.Context, ethClient *ethclient.EthereumClient,
|
|||||||
submissionMap: map[string]*dioneOracle.DioneOracleSubmittedOracleRequest{},
|
submissionMap: map[string]*dioneOracle.DioneOracleSubmittedOracleRequest{},
|
||||||
disputeMap: map[string]*dioneDispute.DioneDisputeNewDispute{},
|
disputeMap: map[string]*dioneDispute.DioneDisputeNewDispute{},
|
||||||
voteWindow: time.Duration(voteWindow) * time.Second,
|
voteWindow: time.Duration(voteWindow) * time.Second,
|
||||||
|
blockchain: bc,
|
||||||
|
submissionChan: submissionChan,
|
||||||
|
submissionSubscription: submSubscription,
|
||||||
|
disputesChan: disputesChan,
|
||||||
|
disputesSubscription: dispSubscription,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return dm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dm *DisputeManager) Run(ctx context.Context) {
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
{
|
{
|
||||||
submSubscription.Unsubscribe()
|
dm.disputesSubscription.Unsubscribe()
|
||||||
dispSubscription.Unsubscribe()
|
dm.disputesSubscription.Unsubscribe()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case s := <-newSubmittionsChan:
|
case s := <-dm.submissionChan:
|
||||||
{
|
{
|
||||||
dm.onNewSubmission(s)
|
dm.onNewSubmission(s)
|
||||||
}
|
}
|
||||||
case d := <-newDisputesChan:
|
case d := <-dm.disputesChan:
|
||||||
{
|
{
|
||||||
dm.onNewDispute(d)
|
dm.onNewDispute(d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return dm, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dm *DisputeManager) onNewSubmission(submittion *dioneOracle.DioneOracleSubmittedOracleRequest) {
|
func (dm *DisputeManager) onNewSubmission(submission *dioneOracle.DioneOracleSubmittedOracleRequest) {
|
||||||
c := dm.pcm.GetConsensusInfo(submittion.ReqID.String())
|
// find a block that contains the dione task with specified request id
|
||||||
if c == nil {
|
task, block, err := dm.findTaskAndBlockWithRequestID(submission.ReqID.String())
|
||||||
// todo: warn
|
if err != nil {
|
||||||
|
logrus.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dm.submissionMap[submittion.ReqID.String()] = submittion
|
dm.submissionMap[submission.ReqID.String()] = submission
|
||||||
|
|
||||||
submHashBytes := sha3.Sum256(submittion.Data)
|
submHashBytes := sha3.Sum256(submission.Data)
|
||||||
localHashBytes := sha3.Sum256(c.Task.Payload)
|
localHashBytes := sha3.Sum256(task.Payload)
|
||||||
submHash := hex.EncodeToString(submHashBytes[:])
|
submHash := hex.EncodeToString(submHashBytes[:])
|
||||||
localHash := hex.EncodeToString(localHashBytes[:])
|
localHash := hex.EncodeToString(localHashBytes[:])
|
||||||
if submHash != localHash {
|
if submHash != localHash {
|
||||||
logrus.Debugf("submission of request id %s isn't valid - beginning dispute", c.Task.RequestID)
|
logrus.Debugf("submission of request id %s isn't valid - beginning dispute", submission.ReqID)
|
||||||
addr := common.HexToAddress(c.Task.MinerEth)
|
err := dm.ethClient.BeginDispute(block.Header.ProposerEth, submission.ReqID)
|
||||||
reqID, ok := big.NewInt(0).SetString(c.Task.RequestID, 10)
|
|
||||||
if !ok {
|
|
||||||
logrus.Errorf("cannot parse request id: %s", c.Task.RequestID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err := dm.ethClient.BeginDispute(addr, reqID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf(err.Error())
|
logrus.Errorf(err.Error())
|
||||||
return
|
return
|
||||||
@ -102,7 +118,7 @@ func (dm *DisputeManager) onNewSubmission(submittion *dioneOracle.DioneOracleSub
|
|||||||
return
|
return
|
||||||
case <-disputeFinishTimer.C:
|
case <-disputeFinishTimer.C:
|
||||||
{
|
{
|
||||||
d, ok := dm.disputeMap[reqID.String()]
|
d, ok := dm.disputeMap[submission.ReqID.String()]
|
||||||
if !ok {
|
if !ok {
|
||||||
logrus.Error("cannot finish dispute: it doesn't exist in manager's dispute map!")
|
logrus.Error("cannot finish dispute: it doesn't exist in manager's dispute map!")
|
||||||
return
|
return
|
||||||
@ -121,16 +137,45 @@ func (dm *DisputeManager) onNewSubmission(submittion *dioneOracle.DioneOracleSub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (dm *DisputeManager) findTaskAndBlockWithRequestID(requestID string) (*types.DioneTask, *types2.Block, error) {
|
||||||
|
height, err := dm.blockchain.GetLatestBlockHeight()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
block, err := dm.blockchain.FetchBlockByHeight(height)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range block.Data {
|
||||||
|
var task types.DioneTask
|
||||||
|
err := cbor.Unmarshal(v.Data, &task)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if task.RequestID == requestID {
|
||||||
|
return &task, block, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
height--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (dm *DisputeManager) onNewDispute(dispute *dioneDispute.DioneDisputeNewDispute) {
|
func (dm *DisputeManager) onNewDispute(dispute *dioneDispute.DioneDisputeNewDispute) {
|
||||||
c := dm.pcm.GetConsensusInfo(dispute.RequestID.String())
|
task, _, err := dm.findTaskAndBlockWithRequestID(dispute.RequestID.String())
|
||||||
if c == nil {
|
if err != nil {
|
||||||
// todo: warn
|
logrus.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
subm, ok := dm.submissionMap[dispute.RequestID.String()]
|
subm, ok := dm.submissionMap[dispute.RequestID.String()]
|
||||||
if !ok {
|
if !ok {
|
||||||
// todo: warn
|
logrus.Warn("desired submission isn't found in map")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +186,7 @@ func (dm *DisputeManager) onNewDispute(dispute *dioneDispute.DioneDisputeNewDisp
|
|||||||
}
|
}
|
||||||
|
|
||||||
submHashBytes := sha3.Sum256(subm.Data)
|
submHashBytes := sha3.Sum256(subm.Data)
|
||||||
localHashBytes := sha3.Sum256(c.Task.Payload)
|
localHashBytes := sha3.Sum256(task.Payload)
|
||||||
submHash := hex.EncodeToString(submHashBytes[:])
|
submHash := hex.EncodeToString(submHashBytes[:])
|
||||||
localHash := hex.EncodeToString(localHashBytes[:])
|
localHash := hex.EncodeToString(localHashBytes[:])
|
||||||
if submHash == localHash {
|
if submHash == localHash {
|
||||||
@ -152,7 +197,7 @@ func (dm *DisputeManager) onNewDispute(dispute *dioneDispute.DioneDisputeNewDisp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := dm.ethClient.VoteDispute(dispute.Dhash, true)
|
err = dm.ethClient.VoteDispute(dispute.Dhash, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf(err.Error())
|
logrus.Errorf(err.Error())
|
||||||
return
|
return
|
||||||
|
@ -1,187 +0,0 @@
|
|||||||
package consensus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
big2 "github.com/filecoin-project/go-state-types/big"
|
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/sigs"
|
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/rpc"
|
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/beacon"
|
|
||||||
"github.com/Secured-Finance/dione/contracts/dioneOracle"
|
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/ethclient"
|
|
||||||
"github.com/Secured-Finance/dione/types"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Miner struct {
|
|
||||||
address peer.ID
|
|
||||||
ethAddress common.Address
|
|
||||||
mutex sync.Mutex
|
|
||||||
beacon beacon.BeaconNetworks
|
|
||||||
ethClient *ethclient.EthereumClient
|
|
||||||
minerStake types.BigInt
|
|
||||||
networkStake types.BigInt
|
|
||||||
privateKey []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMiner(
|
|
||||||
address peer.ID,
|
|
||||||
ethAddress common.Address,
|
|
||||||
beacon beacon.BeaconNetworks,
|
|
||||||
ethClient *ethclient.EthereumClient,
|
|
||||||
privateKey []byte,
|
|
||||||
) *Miner {
|
|
||||||
return &Miner{
|
|
||||||
address: address,
|
|
||||||
ethAddress: ethAddress,
|
|
||||||
beacon: beacon,
|
|
||||||
ethClient: ethClient,
|
|
||||||
privateKey: privateKey,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Miner) UpdateCurrentStakeInfo() error {
|
|
||||||
mStake, err := m.ethClient.GetMinerStake(m.ethAddress)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Warn("Can't get miner stake", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
nStake, err := m.ethClient.GetTotalStake()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Warn("Can't get miner stake", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
m.minerStake = *mStake
|
|
||||||
m.networkStake = *nStake
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Miner) GetStakeInfo(miner common.Address) (*types.BigInt, *types.BigInt, error) {
|
|
||||||
mStake, err := m.ethClient.GetMinerStake(miner)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Warn("Can't get miner stake", err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
nStake, err := m.ethClient.GetTotalStake()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logrus.Warn("Can't get miner stake", err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return mStake, nStake, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Miner) MineTask(ctx context.Context, event *dioneOracle.DioneOracleNewOracleRequest) (*types.DioneTask, error) {
|
|
||||||
beaconValues, err := beacon.BeaconEntriesForTask(ctx, m.beacon)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to get beacon entries: %w", err)
|
|
||||||
}
|
|
||||||
logrus.Debug("attempting to mine the task at epoch: ", beaconValues[1].Round)
|
|
||||||
|
|
||||||
randomBase := beaconValues[1]
|
|
||||||
|
|
||||||
if err := m.UpdateCurrentStakeInfo(); err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to update miner stake: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ticket, err := m.computeTicket(&randomBase)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("scratching ticket failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
winner, err := IsRoundWinner(
|
|
||||||
types.DrandRound(randomBase.Round),
|
|
||||||
m.address,
|
|
||||||
randomBase,
|
|
||||||
m.minerStake,
|
|
||||||
m.networkStake,
|
|
||||||
func(id peer.ID, bytes []byte) (*types.Signature, error) {
|
|
||||||
return sigs.Sign(types.SigTypeEd25519, m.privateKey, bytes)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to check if we win next round: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if winner == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
rpcMethod := rpc.GetRPCMethod(event.OriginChain, event.RequestType)
|
|
||||||
if rpcMethod == nil {
|
|
||||||
return nil, xerrors.Errorf("invalid rpc method name/type")
|
|
||||||
}
|
|
||||||
res, err := rpcMethod(event.RequestParams)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("couldn't do rpc request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &types.DioneTask{
|
|
||||||
OriginChain: event.OriginChain,
|
|
||||||
RequestType: event.RequestType,
|
|
||||||
RequestParams: event.RequestParams,
|
|
||||||
RequestID: event.ReqID.String(),
|
|
||||||
ConsensusID: event.ReqID.String(),
|
|
||||||
Miner: m.address,
|
|
||||||
MinerEth: m.ethAddress.Hex(),
|
|
||||||
Ticket: ticket,
|
|
||||||
ElectionProof: winner,
|
|
||||||
BeaconEntries: beaconValues,
|
|
||||||
Payload: res,
|
|
||||||
DrandRound: types.DrandRound(randomBase.Round),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Miner) computeTicket(brand *types.BeaconEntry) (*types.Ticket, error) {
|
|
||||||
buf, err := m.address.MarshalBinary()
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to marshal address: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
round := types.DrandRound(brand.Round)
|
|
||||||
|
|
||||||
input, err := DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, round-types.TicketRandomnessLookback, buf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
vrfOut, err := ComputeVRF(func(id peer.ID, bytes []byte) (*types.Signature, error) {
|
|
||||||
return sigs.Sign(types.SigTypeEd25519, m.privateKey, bytes)
|
|
||||||
}, m.address, input)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &types.Ticket{
|
|
||||||
VRFProof: vrfOut,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Miner) IsMinerEligibleToProposeTask(ethAddress common.Address) error {
|
|
||||||
mStake, err := m.ethClient.GetMinerStake(ethAddress)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
ok := mStake.GreaterThanEqual(big2.NewInt(ethclient.MinMinerStake))
|
|
||||||
if !ok {
|
|
||||||
return xerrors.Errorf("miner doesn't have enough staked tokens")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,42 +1,52 @@
|
|||||||
package consensus
|
package consensus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
types2 "github.com/Secured-Finance/dione/consensus/types"
|
types2 "github.com/Secured-Finance/dione/consensus/types"
|
||||||
mapset "github.com/Secured-Finance/golang-set"
|
mapset "github.com/Secured-Finance/golang-set"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MessageLog struct {
|
type ConsensusMessageLog struct {
|
||||||
messages mapset.Set
|
messages mapset.Set
|
||||||
maxLogSize int
|
|
||||||
validationFuncMap map[types2.MessageType]func(message types2.Message)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMessageLog() *MessageLog {
|
func NewConsensusMessageLog() *ConsensusMessageLog {
|
||||||
msgLog := &MessageLog{
|
msgLog := &ConsensusMessageLog{
|
||||||
messages: mapset.NewSet(),
|
messages: mapset.NewSet(),
|
||||||
maxLogSize: 0, // TODO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return msgLog
|
return msgLog
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ml *MessageLog) AddMessage(msg types2.Message) {
|
func (ml *ConsensusMessageLog) AddMessage(msg *types2.ConsensusMessage) bool {
|
||||||
ml.messages.Add(msg)
|
return ml.messages.Add(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ml *MessageLog) Exists(msg types2.Message) bool {
|
func (ml *ConsensusMessageLog) Exists(msg *types2.ConsensusMessage) bool {
|
||||||
return ml.messages.Contains(msg)
|
return ml.messages.Contains(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ml *MessageLog) GetMessagesByTypeAndConsensusID(typ types2.MessageType, consensusID string) []types2.Message {
|
func (ml *ConsensusMessageLog) Get(typ types2.ConsensusMessageType, blockhash []byte) []*types2.ConsensusMessage {
|
||||||
var result []types2.Message
|
var result []*types2.ConsensusMessage
|
||||||
|
|
||||||
for v := range ml.messages.Iter() {
|
for v := range ml.messages.Iter() {
|
||||||
msg := v.(types2.Message)
|
msg := v.(*types2.ConsensusMessage)
|
||||||
if msg.Type == typ && msg.Payload.Task.ConsensusID == consensusID {
|
if msg.Block != nil {
|
||||||
|
|
||||||
|
}
|
||||||
|
if msg.Type == typ {
|
||||||
|
var msgBlockHash []byte
|
||||||
|
if msg.Block != nil {
|
||||||
|
msgBlockHash = msg.Block.Header.Hash
|
||||||
|
} else {
|
||||||
|
msgBlockHash = msg.Blockhash
|
||||||
|
}
|
||||||
|
if bytes.Compare(msgBlockHash, blockhash) == 0 {
|
||||||
result = append(result, msg)
|
result = append(result, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
7
consensus/policy/policy.go
Normal file
7
consensus/policy/policy.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package policy
|
||||||
|
|
||||||
|
const (
|
||||||
|
BlockMaxTransactionCount = 100
|
||||||
|
MaxBlockCountForRetrieving = 500 // we do it just like in Bitcoin
|
||||||
|
MaxTransactionCountForRetrieving = 50000
|
||||||
|
)
|
25
consensus/types/consensus_message.go
Normal file
25
consensus/types/consensus_message.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
types3 "github.com/Secured-Finance/dione/blockchain/types"
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConsensusMessageType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
ConsensusMessageTypeUnknown = ConsensusMessageType(iota)
|
||||||
|
|
||||||
|
ConsensusMessageTypePrePrepare
|
||||||
|
ConsensusMessageTypePrepare
|
||||||
|
ConsensusMessageTypeCommit
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConsensusMessage is common struct for various consensus message types. It is stored in consensus message log.
|
||||||
|
type ConsensusMessage struct {
|
||||||
|
Type ConsensusMessageType
|
||||||
|
Blockhash []byte
|
||||||
|
Signature []byte
|
||||||
|
Block *types3.Block // it is optional, because not all message types have block included
|
||||||
|
From peer.ID
|
||||||
|
}
|
@ -1,26 +1,16 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/Secured-Finance/dione/types"
|
types2 "github.com/Secured-Finance/dione/blockchain/types"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type MessageType uint8
|
type PrePrepareMessage struct {
|
||||||
|
Block *types2.Block
|
||||||
const (
|
|
||||||
MessageTypeUnknown = MessageType(iota)
|
|
||||||
|
|
||||||
MessageTypePrePrepare
|
|
||||||
MessageTypePrepare
|
|
||||||
MessageTypeCommit
|
|
||||||
)
|
|
||||||
|
|
||||||
type ConsensusMessage struct {
|
|
||||||
Task types.DioneTask
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Message struct {
|
type PrepareMessage struct {
|
||||||
Type MessageType
|
Blockhash []byte
|
||||||
Payload ConsensusMessage
|
Signature []byte
|
||||||
From peer.ID `cbor:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CommitMessage PrepareMessage
|
||||||
|
@ -1,133 +1,70 @@
|
|||||||
package consensus
|
package consensus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/fxamacker/cbor/v2"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/pubsub"
|
||||||
|
|
||||||
types2 "github.com/Secured-Finance/dione/consensus/types"
|
types2 "github.com/Secured-Finance/dione/consensus/types"
|
||||||
|
|
||||||
"github.com/mitchellh/hashstructure/v2"
|
"github.com/libp2p/go-libp2p-core/crypto"
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/sigs"
|
|
||||||
"github.com/minio/blake2b-simd"
|
|
||||||
|
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/types"
|
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type SignFunc func(peer.ID, []byte) (*types.Signature, error)
|
func NewMessage(cmsg *types2.ConsensusMessage, privKey crypto.PrivKey) (*pubsub.PubSubMessage, error) {
|
||||||
|
var message pubsub.PubSubMessage
|
||||||
func ComputeVRF(sign SignFunc, worker peer.ID, sigInput []byte) ([]byte, error) {
|
switch cmsg.Type {
|
||||||
sig, err := sign(worker, sigInput)
|
case types2.ConsensusMessageTypePrePrepare:
|
||||||
|
{
|
||||||
|
message.Type = pubsub.PrePrepareMessageType
|
||||||
|
msg := types2.PrePrepareMessage{
|
||||||
|
Block: cmsg.Block,
|
||||||
|
}
|
||||||
|
data, err := cbor.Marshal(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to convert message to map: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
message.Payload = data
|
||||||
if sig.Type != types.SigTypeEd25519 {
|
break
|
||||||
return nil, fmt.Errorf("miner worker address was not a Ed25519 key")
|
|
||||||
}
|
}
|
||||||
|
case types2.ConsensusMessageTypePrepare:
|
||||||
return sig.Data, nil
|
{
|
||||||
}
|
message.Type = pubsub.PrepareMessageType
|
||||||
|
signature, err := privKey.Sign(cmsg.Blockhash)
|
||||||
func VerifyVRF(worker peer.ID, vrfBase, vrfproof []byte) error {
|
|
||||||
err := sigs.Verify(&types.Signature{Type: types.SigTypeEd25519, Data: vrfproof}, []byte(worker), vrfBase)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("vrf was invalid: %w", err)
|
return nil, fmt.Errorf("failed to create signature: %v", err)
|
||||||
}
|
}
|
||||||
|
pm := types2.PrepareMessage{
|
||||||
return nil
|
Blockhash: cmsg.Blockhash,
|
||||||
}
|
Signature: signature,
|
||||||
|
}
|
||||||
func IsRoundWinner(round types.DrandRound,
|
data, err := cbor.Marshal(pm)
|
||||||
worker peer.ID, brand types.BeaconEntry, minerStake, networkStake types.BigInt, sign SignFunc) (*types.ElectionProof, error) {
|
|
||||||
|
|
||||||
buf, err := worker.MarshalBinary()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to marshal address: %w", err)
|
return nil, fmt.Errorf("failed to convert message to map: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
message.Payload = data
|
||||||
electionRand, err := DrawRandomness(brand.Data, crypto.DomainSeparationTag_ElectionProofProduction, round, buf)
|
break
|
||||||
|
}
|
||||||
|
case types2.ConsensusMessageTypeCommit:
|
||||||
|
{
|
||||||
|
message.Type = pubsub.CommitMessageType
|
||||||
|
signature, err := privKey.Sign(cmsg.Blockhash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to draw randomness: %w", err)
|
return nil, fmt.Errorf("failed to create signature: %v", err)
|
||||||
}
|
}
|
||||||
|
pm := types2.CommitMessage{
|
||||||
vrfout, err := ComputeVRF(sign, worker, electionRand)
|
Blockhash: cmsg.Blockhash,
|
||||||
|
Signature: signature,
|
||||||
|
}
|
||||||
|
data, err := cbor.Marshal(pm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to compute VRF: %w", err)
|
return nil, fmt.Errorf("failed to convert message to map: %s", err.Error())
|
||||||
|
}
|
||||||
|
message.Payload = data
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ep := &types.ElectionProof{VRFProof: vrfout}
|
|
||||||
j := ep.ComputeWinCount(minerStake, networkStake)
|
|
||||||
ep.WinCount = j
|
|
||||||
if j < 1 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return ep, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round types.DrandRound, entropy []byte) ([]byte, error) {
|
|
||||||
h := blake2b.New256()
|
|
||||||
if err := binary.Write(h, binary.BigEndian, int64(pers)); err != nil {
|
|
||||||
return nil, xerrors.Errorf("deriving randomness: %v", err)
|
|
||||||
}
|
|
||||||
VRFDigest := blake2b.Sum256(rbase)
|
|
||||||
_, err := h.Write(VRFDigest[:])
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("hashing VRFDigest: %w", err)
|
|
||||||
}
|
|
||||||
if err := binary.Write(h, binary.BigEndian, round); err != nil {
|
|
||||||
return nil, xerrors.Errorf("deriving randomness: %v", err)
|
|
||||||
}
|
|
||||||
_, err = h.Write(entropy)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("hashing entropy: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return h.Sum(nil), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func VerifyTaskSignature(task types.DioneTask) error {
|
|
||||||
cHash, err := hashstructure.Hash(task, hashstructure.FormatV2, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = sigs.Verify(
|
|
||||||
&types.Signature{Type: types.SigTypeEd25519, Data: task.Signature},
|
|
||||||
[]byte(task.Miner),
|
|
||||||
[]byte(fmt.Sprintf("%v", cHash)),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMessage(msg *types2.Message, typ types2.MessageType) (types2.Message, error) {
|
|
||||||
var newMsg types2.Message
|
|
||||||
newMsg.Type = typ
|
|
||||||
newCMsg := msg.Payload
|
|
||||||
newMsg.Payload = newCMsg
|
|
||||||
return newMsg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreatePrePrepareWithTaskSignature(task *types.DioneTask, privateKey []byte) (*types2.Message, error) {
|
|
||||||
var message types2.Message
|
|
||||||
message.Type = types2.MessageTypePrePrepare
|
|
||||||
|
|
||||||
cHash, err := hashstructure.Hash(task, hashstructure.FormatV2, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
signature, err := sigs.Sign(types.SigTypeEd25519, privateKey, []byte(fmt.Sprintf("%v", cHash)))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
task.Signature = signature.Data
|
|
||||||
message.Payload = types2.ConsensusMessage{Task: *task}
|
|
||||||
return &message, nil
|
return &message, nil
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,40 @@
|
|||||||
package filecoin
|
package filecoin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"github.com/Secured-Finance/dione/types"
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/consensus/validation"
|
"github.com/Secured-Finance/dione/consensus/validation"
|
||||||
rtypes "github.com/Secured-Finance/dione/rpc/types"
|
rtypes "github.com/Secured-Finance/dione/rpc/types"
|
||||||
|
|
||||||
ftypes "github.com/Secured-Finance/dione/rpc/filecoin/types"
|
|
||||||
"github.com/Secured-Finance/dione/sigs"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"golang.org/x/xerrors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func ValidateGetTransaction(payload []byte) error {
|
func ValidateGetTransaction(task *types.DioneTask) error {
|
||||||
var msg ftypes.SignedMessage
|
//var msg ftypes.SignedMessage
|
||||||
if err := msg.UnmarshalCBOR(bytes.NewReader(payload)); err != nil {
|
//if err := msg.UnmarshalCBOR(bytes.NewReader(payload)); err != nil {
|
||||||
if err := msg.Message.UnmarshalCBOR(bytes.NewReader(payload)); err != nil {
|
// if err := msg.Message.UnmarshalCBOR(bytes.NewReader(payload)); err != nil {
|
||||||
return xerrors.Errorf("cannot unmarshal payload: %s", err.Error())
|
// return xerrors.Errorf("cannot unmarshal payload: %s", err.Error())
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
|
//if msg.Type == ftypes.MessageTypeSecp256k1 {
|
||||||
|
// if err := sigs.Verify(&msg.Signature, msg.Message.From.Bytes(), msg.Message.Cid().Bytes()); err != nil {
|
||||||
|
// logrus.Errorf("Couldn't verify transaction %v", err)
|
||||||
|
// return xerrors.Errorf("Couldn't verify transaction: %v")
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
//} else {
|
||||||
|
// // TODO: BLS Signature verification
|
||||||
|
// return nil
|
||||||
|
//}
|
||||||
|
return validation.VerifyExactMatching(task)
|
||||||
|
}
|
||||||
|
|
||||||
if msg.Type == ftypes.MessageTypeSecp256k1 {
|
func ValidateGetBlock(task *types.DioneTask) error {
|
||||||
if err := sigs.Verify(&msg.Signature, msg.Message.From.Bytes(), msg.Message.Cid().Bytes()); err != nil {
|
return validation.VerifyExactMatching(task)
|
||||||
logrus.Errorf("Couldn't verify transaction %v", err)
|
|
||||||
return xerrors.Errorf("Couldn't verify transaction: %v")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
// TODO: BLS Signature verification
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
validation.RegisterValidation(rtypes.RPCTypeFilecoin, map[string]func([]byte) error{
|
validation.RegisterValidation(rtypes.RPCTypeFilecoin, map[string]func(*types.DioneTask) error{
|
||||||
"getTransaction": ValidateGetTransaction,
|
"getTransaction": ValidateGetTransaction,
|
||||||
|
"getBlock": ValidateGetBlock,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
package validation
|
package validation
|
||||||
|
|
||||||
var validations = map[uint8]map[string]func([]byte) error{} // rpcType -> {rpcMethodName -> actual func var}
|
import "github.com/Secured-Finance/dione/types"
|
||||||
|
|
||||||
func RegisterValidation(typ uint8, methods map[string]func([]byte) error) {
|
var validations = map[uint8]map[string]func(*types.DioneTask) error{} // rpcType -> {rpcMethodName -> actual func var}
|
||||||
|
|
||||||
|
func RegisterValidation(typ uint8, methods map[string]func(*types.DioneTask) error) {
|
||||||
validations[typ] = methods
|
validations[typ] = methods
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetValidationMethod(typ uint8, methodName string) func([]byte) error {
|
func GetValidationMethod(typ uint8, methodName string) func(*types.DioneTask) error {
|
||||||
rpcMethods, ok := validations[typ]
|
rpcMethods, ok := validations[typ]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
|
17
consensus/validation/solana/solana.go
Normal file
17
consensus/validation/solana/solana.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package solana
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/Secured-Finance/dione/consensus/validation"
|
||||||
|
rtypes "github.com/Secured-Finance/dione/rpc/types"
|
||||||
|
"github.com/Secured-Finance/dione/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ValidateGetTransaction(task *types.DioneTask) error {
|
||||||
|
return validation.VerifyExactMatching(task)
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
validation.RegisterValidation(rtypes.RPCTypeSolana, map[string]func(*types.DioneTask) error{
|
||||||
|
"getTransaction": ValidateGetTransaction,
|
||||||
|
})
|
||||||
|
}
|
24
consensus/validation/utils.go
Normal file
24
consensus/validation/utils.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package validation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/rpc"
|
||||||
|
"github.com/Secured-Finance/dione/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func VerifyExactMatching(task *types.DioneTask) error {
|
||||||
|
rpcMethod := rpc.GetRPCMethod(task.OriginChain, task.RequestType)
|
||||||
|
if rpcMethod == nil {
|
||||||
|
return fmt.Errorf("invalid RPC method")
|
||||||
|
}
|
||||||
|
res, err := rpcMethod(task.RequestParams)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to invoke RPC method: %w", err)
|
||||||
|
}
|
||||||
|
if bytes.Compare(res, task.Payload) != 0 {
|
||||||
|
return fmt.Errorf("actual rpc response doesn't match with task's payload")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,23 +0,0 @@
|
|||||||
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")
|
|
||||||
}
|
|
1
eth-contracts/.gitignore
vendored
1
eth-contracts/.gitignore
vendored
@ -4,3 +4,4 @@ cache
|
|||||||
dist
|
dist
|
||||||
coverage
|
coverage
|
||||||
coverage.json
|
coverage.json
|
||||||
|
scripts/private
|
||||||
|
@ -85,7 +85,7 @@ contract DioneOracle {
|
|||||||
function submitOracleRequest(uint256 _reqID, bytes memory _data) public onlyPendingRequest(_reqID) returns (bool) {
|
function submitOracleRequest(uint256 _reqID, bytes memory _data) public onlyPendingRequest(_reqID) returns (bool) {
|
||||||
require(pendingRequests[_reqID].deadline - int256(block.timestamp) >= 0, "submission has exceeded the deadline");
|
require(pendingRequests[_reqID].deadline - int256(block.timestamp) >= 0, "submission has exceeded the deadline");
|
||||||
delete pendingRequests[_reqID];
|
delete pendingRequests[_reqID];
|
||||||
dioneStaking.mine(msg.sender);
|
dioneStaking.mineAndStake(msg.sender);
|
||||||
pendingRequests[_reqID].callbackAddress.call(abi.encodeWithSelector(pendingRequests[_reqID].callbackMethodID, _reqID, _data));
|
pendingRequests[_reqID].callbackAddress.call(abi.encodeWithSelector(pendingRequests[_reqID].callbackMethodID, _reqID, _data));
|
||||||
emit SubmittedOracleRequest(_reqID, _data);
|
emit SubmittedOracleRequest(_reqID, _data);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,30 +1,28 @@
|
|||||||
import { task } from "hardhat/config";
|
|
||||||
import "@nomiclabs/hardhat-ethers";
|
import "@nomiclabs/hardhat-ethers";
|
||||||
import "hardhat-tracer";
|
import "hardhat-tracer";
|
||||||
import "@nomiclabs/hardhat-waffle";
|
import "@nomiclabs/hardhat-waffle";
|
||||||
import "solidity-coverage";
|
import "solidity-coverage";
|
||||||
import "hardhat-gas-reporter";
|
import "hardhat-gas-reporter";
|
||||||
|
import * as secrets from "./secrets.json";
|
||||||
task("accounts", "Prints the list of accounts", async (args, hre) => {
|
import "./hardhat.tasks";
|
||||||
const accounts = await hre.ethers.getSigners();
|
import "@nomiclabs/hardhat-etherscan";
|
||||||
|
|
||||||
for (const account of accounts) {
|
|
||||||
console.log(await account.address);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
solidity: "0.8.3",
|
solidity: {
|
||||||
networks: {
|
version: "0.8.3",
|
||||||
geth: {
|
settings: {
|
||||||
url: `http://localhost:8545`,
|
optimizer: {
|
||||||
accounts: {
|
enabled: false,
|
||||||
mnemonic: "test test test test test test test test test test test junk"
|
runs: 200
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
networks: secrets.networks,
|
||||||
gasReporter: {
|
gasReporter: {
|
||||||
currency: 'USD',
|
currency: 'USD',
|
||||||
enabled: (process.env.REPORT_GAS) ? true : false
|
enabled: process.env.REPORT_GAS
|
||||||
|
},
|
||||||
|
etherscan: {
|
||||||
|
apiKey: secrets.etherscanApiKey
|
||||||
}
|
}
|
||||||
};
|
};
|
34
eth-contracts/hardhat.tasks.ts
Normal file
34
eth-contracts/hardhat.tasks.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { task } from "hardhat/config";
|
||||||
|
import "@nomiclabs/hardhat-ethers";
|
||||||
|
|
||||||
|
task("stake", "Prints an account's stake amount in DioneStaking contract")
|
||||||
|
.addParam("contract", "DioneStaking contract address")
|
||||||
|
.addParam("account", "The account's address")
|
||||||
|
.setAction(async (args, hre) => {
|
||||||
|
const DioneStaking = await hre.ethers.getContractFactory("DioneStaking");
|
||||||
|
const contract = DioneStaking.attach(args.contract);
|
||||||
|
const a = await contract.minerStake(args.account);
|
||||||
|
console.log("Stake amount:", a.div(hre.ethers.constants.WeiPerEther).toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
task("accounts", "Prints the list of accounts", async (args, hre) => {
|
||||||
|
const accounts = await hre.ethers.getSigners();
|
||||||
|
|
||||||
|
for (const account of accounts) {
|
||||||
|
console.log(await account.address);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
task("oracleRequest", "Makes oracle request to Mediator contract")
|
||||||
|
.addParam("contract", "Mediator contract address")
|
||||||
|
.addParam("chainid", "Chain ID from which need to request info")
|
||||||
|
.addParam("method", "Method name of requesting chain RPC")
|
||||||
|
.addParam("param", "Value of parameter for specified method")
|
||||||
|
.setAction(async (args, hre) => {
|
||||||
|
const Mediator = await hre.ethers.getContractFactory("Mediator");
|
||||||
|
const contract = Mediator.attach(args.contract);
|
||||||
|
const res = await contract.request(parseInt(args.chainid), args.method, args.param)
|
||||||
|
console.log("Request has successfully been sent.")
|
||||||
|
console.log("Transaction info:")
|
||||||
|
console.log(res)
|
||||||
|
})
|
696
eth-contracts/package-lock.json
generated
696
eth-contracts/package-lock.json
generated
@ -13,6 +13,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
||||||
|
"@nomiclabs/hardhat-etherscan": "^2.1.4",
|
||||||
"@nomiclabs/hardhat-waffle": "^2.0.1",
|
"@nomiclabs/hardhat-waffle": "^2.0.1",
|
||||||
"@types/chai": "^4.2.16",
|
"@types/chai": "^4.2.16",
|
||||||
"@types/mocha": "^8.2.2",
|
"@types/mocha": "^8.2.2",
|
||||||
@ -1278,6 +1279,421 @@
|
|||||||
"hardhat": "^2.0.0"
|
"hardhat": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan": {
|
||||||
|
"version": "2.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-2.1.4.tgz",
|
||||||
|
"integrity": "sha512-KgFNTQv9gpioiTpQ9UlTysCAFfkcBonmEn9rVPTT22A7DRENFM1VTsVeGWF3AzRhd0mrASBF+o0gvbH30pSe0Q==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/abi": "^5.1.2",
|
||||||
|
"@ethersproject/address": "^5.0.2",
|
||||||
|
"cbor": "^5.0.2",
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"fs-extra": "^7.0.1",
|
||||||
|
"node-fetch": "^2.6.0",
|
||||||
|
"semver": "^6.3.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"hardhat": "^2.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/abi": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-9gU2H+/yK1j2eVMdzm6xvHSnMxk8waIHQGYCZg5uvAyH0rsAzxkModzBSpbAkAuhKFEovC2S9hM4nPuLym8IZw==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/address": "^5.4.0",
|
||||||
|
"@ethersproject/bignumber": "^5.4.0",
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/constants": "^5.4.0",
|
||||||
|
"@ethersproject/hash": "^5.4.0",
|
||||||
|
"@ethersproject/keccak256": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/properties": "^5.4.0",
|
||||||
|
"@ethersproject/strings": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/abstract-provider": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-vPBR7HKUBY0lpdllIn7tLIzNN7DrVnhCLKSzY0l8WAwxz686m/aL7ASDzrVxV93GJtIub6N2t4dfZ29CkPOxgA==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/bignumber": "^5.4.0",
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/networks": "^5.4.0",
|
||||||
|
"@ethersproject/properties": "^5.4.0",
|
||||||
|
"@ethersproject/transactions": "^5.4.0",
|
||||||
|
"@ethersproject/web": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/abstract-signer": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-AieQAzt05HJZS2bMofpuxMEp81AHufA5D6M4ScKwtolj041nrfIbIi8ciNW7+F59VYxXq+V4c3d568Q6l2m8ew==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/abstract-provider": "^5.4.0",
|
||||||
|
"@ethersproject/bignumber": "^5.4.0",
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/properties": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/address": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-SD0VgOEkcACEG/C6xavlU1Hy3m5DGSXW3CUHkaaEHbAPPsgi0coP5oNPsxau8eTlZOk/bpa/hKeCNoK5IzVI2Q==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/bignumber": "^5.4.0",
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/keccak256": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/rlp": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/base64": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-CjQw6E17QDSSC5jiM9YpF7N1aSCHmYGMt9bWD8PWv6YPMxjsys2/Q8xLrROKI3IWJ7sFfZ8B3flKDTM5wlWuZQ==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/bytes": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/bignumber": {
|
||||||
|
"version": "5.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.4.1.tgz",
|
||||||
|
"integrity": "sha512-fJhdxqoQNuDOk6epfM7yD6J8Pol4NUCy1vkaGAkuujZm0+lNow//MKu1hLhRiYV4BsOHyBv5/lsTjF+7hWwhJg==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"bn.js": "^4.11.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/bytes": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-H60ceqgTHbhzOj4uRc/83SCN9d+BSUnOkrr2intevqdtEMO1JFVZ1XL84OEZV+QjV36OaZYxtnt4lGmxcGsPfA==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/logger": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/constants": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-tzjn6S7sj9+DIIeKTJLjK9WGN2Tj0P++Z8ONEIlZjyoTkBuODN+0VfhAyYksKi43l1Sx9tX2VlFfzjfmr5Wl3Q==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/bignumber": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/hash": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-xymAM9tmikKgbktOCjW60Z5sdouiIIurkZUr9oW5NOex5uwxrbsYG09kb5bMcNjlVeJD3yPivTNzViIs1GCbqA==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/abstract-signer": "^5.4.0",
|
||||||
|
"@ethersproject/address": "^5.4.0",
|
||||||
|
"@ethersproject/bignumber": "^5.4.0",
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/keccak256": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/properties": "^5.4.0",
|
||||||
|
"@ethersproject/strings": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/keccak256": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-FBI1plWet+dPUvAzPAeHzRKiPpETQzqSUWR1wXJGHVWi4i8bOSrpC3NwpkPjgeXG7MnugVc1B42VbfnQikyC/A==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"js-sha3": "0.5.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/logger": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-xYdWGGQ9P2cxBayt64d8LC8aPFJk6yWCawQi/4eJ4+oJdMMjEBMrIcIMZ9AxhwpPVmnBPrsB10PcXGmGAqgUEQ==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/networks": {
|
||||||
|
"version": "5.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.4.1.tgz",
|
||||||
|
"integrity": "sha512-8SvowCKz9Uf4xC5DTKI8+il8lWqOr78kmiqAVLYT9lzB8aSmJHQMD1GSuJI0CW4hMAnzocpGpZLgiMdzsNSPig==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/logger": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/properties": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-7jczalGVRAJ+XSRvNA6D5sAwT4gavLq3OXPuV/74o3Rd2wuzSL035IMpIMgei4CYyBdialJMrTqkOnzccLHn4A==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/logger": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/rlp": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-0I7MZKfi+T5+G8atId9QaQKHRvvasM/kqLyAH4XxBCBchAooH2EX5rL9kYZWwcm3awYV+XC7VF6nLhfeQFKVPg==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/signing-key": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-q8POUeywx6AKg2/jX9qBYZIAmKSB4ubGXdQ88l40hmATj29JnG5pp331nAWwwxPn2Qao4JpWHNZsQN+bPiSW9A==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/properties": "^5.4.0",
|
||||||
|
"bn.js": "^4.11.9",
|
||||||
|
"elliptic": "6.5.4",
|
||||||
|
"hash.js": "1.1.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/strings": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-k/9DkH5UGDhv7aReXLluFG5ExurwtIpUfnDNhQA29w896Dw3i4uDTz01Quaptbks1Uj9kI8wo9tmW73wcIEaWA==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/constants": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/transactions": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-s3EjZZt7xa4BkLknJZ98QGoIza94rVjaEed0rzZ/jB9WrIuu/1+tjvYCWzVrystXtDswy7TPBeIepyXwSYa4WQ==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/address": "^5.4.0",
|
||||||
|
"@ethersproject/bignumber": "^5.4.0",
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/constants": "^5.4.0",
|
||||||
|
"@ethersproject/keccak256": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/properties": "^5.4.0",
|
||||||
|
"@ethersproject/rlp": "^5.4.0",
|
||||||
|
"@ethersproject/signing-key": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/@ethersproject/web": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-1bUusGmcoRLYgMn6c1BLk1tOKUIFuTg8j+6N8lYlbMpDesnle+i3pGSagGNvwjaiLo4Y5gBibwctpPRmjrh4Og==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/base64": "^5.4.0",
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/properties": "^5.4.0",
|
||||||
|
"@ethersproject/strings": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/js-sha3": {
|
||||||
|
"version": "0.5.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz",
|
||||||
|
"integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@nomiclabs/hardhat-waffle": {
|
"node_modules/@nomiclabs/hardhat-waffle": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.1.tgz",
|
||||||
@ -2622,6 +3038,19 @@
|
|||||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
|
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/cbor": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"bignumber.js": "^9.0.1",
|
||||||
|
"nofilter": "^1.0.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/chai": {
|
"node_modules/chai": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz",
|
||||||
@ -17393,6 +17822,15 @@
|
|||||||
"node-gyp-build-test": "build-test.js"
|
"node-gyp-build-test": "build-test.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/nofilter": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/nopt": {
|
"node_modules/nopt": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
|
||||||
@ -21876,6 +22314,240 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
"@nomiclabs/hardhat-etherscan": {
|
||||||
|
"version": "2.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-2.1.4.tgz",
|
||||||
|
"integrity": "sha512-KgFNTQv9gpioiTpQ9UlTysCAFfkcBonmEn9rVPTT22A7DRENFM1VTsVeGWF3AzRhd0mrASBF+o0gvbH30pSe0Q==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/abi": "^5.1.2",
|
||||||
|
"@ethersproject/address": "^5.0.2",
|
||||||
|
"cbor": "^5.0.2",
|
||||||
|
"debug": "^4.1.1",
|
||||||
|
"fs-extra": "^7.0.1",
|
||||||
|
"node-fetch": "^2.6.0",
|
||||||
|
"semver": "^6.3.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/abi": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-9gU2H+/yK1j2eVMdzm6xvHSnMxk8waIHQGYCZg5uvAyH0rsAzxkModzBSpbAkAuhKFEovC2S9hM4nPuLym8IZw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/address": "^5.4.0",
|
||||||
|
"@ethersproject/bignumber": "^5.4.0",
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/constants": "^5.4.0",
|
||||||
|
"@ethersproject/hash": "^5.4.0",
|
||||||
|
"@ethersproject/keccak256": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/properties": "^5.4.0",
|
||||||
|
"@ethersproject/strings": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/abstract-provider": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-vPBR7HKUBY0lpdllIn7tLIzNN7DrVnhCLKSzY0l8WAwxz686m/aL7ASDzrVxV93GJtIub6N2t4dfZ29CkPOxgA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/bignumber": "^5.4.0",
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/networks": "^5.4.0",
|
||||||
|
"@ethersproject/properties": "^5.4.0",
|
||||||
|
"@ethersproject/transactions": "^5.4.0",
|
||||||
|
"@ethersproject/web": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/abstract-signer": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-AieQAzt05HJZS2bMofpuxMEp81AHufA5D6M4ScKwtolj041nrfIbIi8ciNW7+F59VYxXq+V4c3d568Q6l2m8ew==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/abstract-provider": "^5.4.0",
|
||||||
|
"@ethersproject/bignumber": "^5.4.0",
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/properties": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/address": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-SD0VgOEkcACEG/C6xavlU1Hy3m5DGSXW3CUHkaaEHbAPPsgi0coP5oNPsxau8eTlZOk/bpa/hKeCNoK5IzVI2Q==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/bignumber": "^5.4.0",
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/keccak256": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/rlp": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/base64": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-CjQw6E17QDSSC5jiM9YpF7N1aSCHmYGMt9bWD8PWv6YPMxjsys2/Q8xLrROKI3IWJ7sFfZ8B3flKDTM5wlWuZQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/bytes": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/bignumber": {
|
||||||
|
"version": "5.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.4.1.tgz",
|
||||||
|
"integrity": "sha512-fJhdxqoQNuDOk6epfM7yD6J8Pol4NUCy1vkaGAkuujZm0+lNow//MKu1hLhRiYV4BsOHyBv5/lsTjF+7hWwhJg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"bn.js": "^4.11.9"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/bytes": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-H60ceqgTHbhzOj4uRc/83SCN9d+BSUnOkrr2intevqdtEMO1JFVZ1XL84OEZV+QjV36OaZYxtnt4lGmxcGsPfA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/logger": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/constants": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-tzjn6S7sj9+DIIeKTJLjK9WGN2Tj0P++Z8ONEIlZjyoTkBuODN+0VfhAyYksKi43l1Sx9tX2VlFfzjfmr5Wl3Q==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/bignumber": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/hash": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-xymAM9tmikKgbktOCjW60Z5sdouiIIurkZUr9oW5NOex5uwxrbsYG09kb5bMcNjlVeJD3yPivTNzViIs1GCbqA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/abstract-signer": "^5.4.0",
|
||||||
|
"@ethersproject/address": "^5.4.0",
|
||||||
|
"@ethersproject/bignumber": "^5.4.0",
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/keccak256": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/properties": "^5.4.0",
|
||||||
|
"@ethersproject/strings": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/keccak256": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-FBI1plWet+dPUvAzPAeHzRKiPpETQzqSUWR1wXJGHVWi4i8bOSrpC3NwpkPjgeXG7MnugVc1B42VbfnQikyC/A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"js-sha3": "0.5.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/logger": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-xYdWGGQ9P2cxBayt64d8LC8aPFJk6yWCawQi/4eJ4+oJdMMjEBMrIcIMZ9AxhwpPVmnBPrsB10PcXGmGAqgUEQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@ethersproject/networks": {
|
||||||
|
"version": "5.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.4.1.tgz",
|
||||||
|
"integrity": "sha512-8SvowCKz9Uf4xC5DTKI8+il8lWqOr78kmiqAVLYT9lzB8aSmJHQMD1GSuJI0CW4hMAnzocpGpZLgiMdzsNSPig==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/logger": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/properties": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-7jczalGVRAJ+XSRvNA6D5sAwT4gavLq3OXPuV/74o3Rd2wuzSL035IMpIMgei4CYyBdialJMrTqkOnzccLHn4A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/logger": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/rlp": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-0I7MZKfi+T5+G8atId9QaQKHRvvasM/kqLyAH4XxBCBchAooH2EX5rL9kYZWwcm3awYV+XC7VF6nLhfeQFKVPg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/signing-key": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-q8POUeywx6AKg2/jX9qBYZIAmKSB4ubGXdQ88l40hmATj29JnG5pp331nAWwwxPn2Qao4JpWHNZsQN+bPiSW9A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/properties": "^5.4.0",
|
||||||
|
"bn.js": "^4.11.9",
|
||||||
|
"elliptic": "6.5.4",
|
||||||
|
"hash.js": "1.1.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/strings": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-k/9DkH5UGDhv7aReXLluFG5ExurwtIpUfnDNhQA29w896Dw3i4uDTz01Quaptbks1Uj9kI8wo9tmW73wcIEaWA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/constants": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/transactions": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-s3EjZZt7xa4BkLknJZ98QGoIza94rVjaEed0rzZ/jB9WrIuu/1+tjvYCWzVrystXtDswy7TPBeIepyXwSYa4WQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/address": "^5.4.0",
|
||||||
|
"@ethersproject/bignumber": "^5.4.0",
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/constants": "^5.4.0",
|
||||||
|
"@ethersproject/keccak256": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/properties": "^5.4.0",
|
||||||
|
"@ethersproject/rlp": "^5.4.0",
|
||||||
|
"@ethersproject/signing-key": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@ethersproject/web": {
|
||||||
|
"version": "5.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.4.0.tgz",
|
||||||
|
"integrity": "sha512-1bUusGmcoRLYgMn6c1BLk1tOKUIFuTg8j+6N8lYlbMpDesnle+i3pGSagGNvwjaiLo4Y5gBibwctpPRmjrh4Og==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@ethersproject/base64": "^5.4.0",
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/logger": "^5.4.0",
|
||||||
|
"@ethersproject/properties": "^5.4.0",
|
||||||
|
"@ethersproject/strings": "^5.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"js-sha3": {
|
||||||
|
"version": "0.5.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz",
|
||||||
|
"integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@nomiclabs/hardhat-waffle": {
|
"@nomiclabs/hardhat-waffle": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.1.tgz",
|
||||||
@ -22223,7 +22895,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-2.0.0.tgz",
|
||||||
"integrity": "sha512-0xdCkyGOzdqh4h5JSf+zoWx85IusEjDcPIwNEHP8mrWSnCae4rvrqB+/gtpdNfX7zjlFlZiMeePn2r63EI3Lrw==",
|
"integrity": "sha512-0xdCkyGOzdqh4h5JSf+zoWx85IusEjDcPIwNEHP8mrWSnCae4rvrqB+/gtpdNfX7zjlFlZiMeePn2r63EI3Lrw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"ethers": "^5.0.2"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"@types/bn.js": {
|
"@types/bn.js": {
|
||||||
"version": "4.11.6",
|
"version": "4.11.6",
|
||||||
@ -23064,6 +23738,16 @@
|
|||||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
|
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"cbor": {
|
||||||
|
"version": "5.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz",
|
||||||
|
"integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"bignumber.js": "^9.0.1",
|
||||||
|
"nofilter": "^1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"chai": {
|
"chai": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz",
|
||||||
@ -33148,7 +33832,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/hardhat-tracer/-/hardhat-tracer-1.0.0-alpha.5.tgz",
|
"resolved": "https://registry.npmjs.org/hardhat-tracer/-/hardhat-tracer-1.0.0-alpha.5.tgz",
|
||||||
"integrity": "sha512-25TZhzIrQgFyYs2oIZrdK6rU0XbK82nr759KYStyCzWklE6bxGlDO5niQugScAIo9aGAT/4vec/mxcJo1Ladpw==",
|
"integrity": "sha512-25TZhzIrQgFyYs2oIZrdK6rU0XbK82nr759KYStyCzWklE6bxGlDO5niQugScAIo9aGAT/4vec/mxcJo1Ladpw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"ethers": "^5.0.24"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"has": {
|
"has": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
@ -34565,6 +35251,12 @@
|
|||||||
"integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==",
|
"integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"nofilter": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"nopt": {
|
"nopt": {
|
||||||
"version": "3.0.6",
|
"version": "3.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
|
||||||
|
@ -7,12 +7,13 @@
|
|||||||
"test": "TS_NODE_FILES=true npx hardhat test",
|
"test": "TS_NODE_FILES=true npx hardhat test",
|
||||||
"test:reportGas": "REPORT_GAS=1 TS_NODE_FILES=true npx hardhat test",
|
"test:reportGas": "REPORT_GAS=1 TS_NODE_FILES=true npx hardhat test",
|
||||||
"coverage": "TS_NODE_FILES=true npx hardhat coverage",
|
"coverage": "TS_NODE_FILES=true npx hardhat coverage",
|
||||||
"deploy:local": "TS_NODE_FILES=true npx hardhat --network geth run scripts/deploy.ts"
|
"deploy:local": "TS_NODE_FILES=true npx hardhat --network local run scripts/deploy.ts"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
||||||
|
"@nomiclabs/hardhat-etherscan": "^2.1.4",
|
||||||
"@nomiclabs/hardhat-waffle": "^2.0.1",
|
"@nomiclabs/hardhat-waffle": "^2.0.1",
|
||||||
"@types/chai": "^4.2.16",
|
"@types/chai": "^4.2.16",
|
||||||
"@types/mocha": "^8.2.2",
|
"@types/mocha": "^8.2.2",
|
||||||
|
@ -5,7 +5,7 @@ import deploy from "../common/deployment";
|
|||||||
|
|
||||||
describe("DioneOracle", function () {
|
describe("DioneOracle", function () {
|
||||||
let dioneOracle: Contract;
|
let dioneOracle: Contract;
|
||||||
let dioneToken: Contract;
|
let dioneStaking: Contract;
|
||||||
|
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
const contracts = await deploy({
|
const contracts = await deploy({
|
||||||
@ -20,11 +20,11 @@ describe("DioneOracle", function () {
|
|||||||
minStakeForDisputeVotes: 100
|
minStakeForDisputeVotes: 100
|
||||||
});
|
});
|
||||||
dioneOracle = contracts.dioneOracle;
|
dioneOracle = contracts.dioneOracle;
|
||||||
dioneToken = contracts.dioneToken;
|
dioneStaking = contracts.dioneStaking;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create request and cancel it", async function () {
|
it("should create request and cancel it", async function () {
|
||||||
const timestamp = 1625097600;
|
const timestamp = new Date().getTime();
|
||||||
await ethers.provider.send("evm_setNextBlockTimestamp", [timestamp]);
|
await ethers.provider.send("evm_setNextBlockTimestamp", [timestamp]);
|
||||||
const requestDeadline = timestamp + 300;
|
const requestDeadline = timestamp + 300;
|
||||||
await expect(dioneOracle.requestOracles(1, "getTransaction", "bafy2bzaceaaab3kkoaocal2dzh3okzy4gscqpdt42hzrov3df6vjumalngc3g", "0x0000000000000000000000000000000000000000", "0x00000000"))
|
await expect(dioneOracle.requestOracles(1, "getTransaction", "bafy2bzaceaaab3kkoaocal2dzh3okzy4gscqpdt42hzrov3df6vjumalngc3g", "0x0000000000000000000000000000000000000000", "0x00000000"))
|
||||||
@ -50,8 +50,8 @@ describe("DioneOracle", function () {
|
|||||||
.withArgs(1, BigNumber.from(0x8da5cb5b));
|
.withArgs(1, BigNumber.from(0x8da5cb5b));
|
||||||
|
|
||||||
// check if miner has received the reward
|
// check if miner has received the reward
|
||||||
expect(await dioneToken.balanceOf(addr0.address))
|
expect(await dioneStaking.minerStake(addr0.address))
|
||||||
.to.be.equal(ethers.constants.WeiPerEther.mul(100));
|
.to.be.equal(ethers.constants.WeiPerEther.mul(9100));
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should fail submission after request deadline", async function () {
|
it("should fail submission after request deadline", async function () {
|
||||||
|
@ -4,7 +4,8 @@
|
|||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"outDir": "dist"
|
"outDir": "dist",
|
||||||
|
"resolveJsonModule": true
|
||||||
},
|
},
|
||||||
"include": ["./scripts", "./test", "./common"],
|
"include": ["./scripts", "./test", "./common"],
|
||||||
"files": ["./hardhat.config.ts"]
|
"files": ["./hardhat.config.ts"]
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package ethclient
|
package ethclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/Secured-Finance/dione/types"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -9,32 +10,22 @@ const (
|
|||||||
MinMinerStake = 1000
|
MinMinerStake = 1000
|
||||||
)
|
)
|
||||||
|
|
||||||
// Getting total stake in DioneStaking contract, this function could
|
// GetTotalStake for getting total stake in DioneStaking contract
|
||||||
// be used for storing the total stake and veryfing the stake tokens
|
func (c *EthereumClient) GetTotalStake() (*big.Int, error) {
|
||||||
// on new tasks
|
|
||||||
func (c *EthereumClient) GetTotalStake() (*types.BigInt, error) {
|
|
||||||
var b types.BigInt
|
|
||||||
totalStake, err := c.dioneStaking.TotalStake()
|
totalStake, err := c.dioneStaking.TotalStake()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
b.Int = totalStake
|
return totalStake, nil
|
||||||
return &b, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getting miner stake in DioneStaking contract, this function could
|
// GetMinerStake for getting specified miner stake in DioneStaking contract
|
||||||
// be used for storing the miner's stake and veryfing the stake tokens
|
func (c *EthereumClient) GetMinerStake(minerAddress common.Address) (*big.Int, error) {
|
||||||
// on new tasks
|
|
||||||
func (c *EthereumClient) GetMinerStake(minerAddress common.Address) (*types.BigInt, error) {
|
|
||||||
var b types.BigInt
|
|
||||||
minerStake, err := c.dioneStaking.MinerStake(minerAddress)
|
minerStake, err := c.dioneStaking.MinerStake(minerAddress)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
b.Int = minerStake
|
return minerStake, nil
|
||||||
return &b, nil
|
|
||||||
}
|
}
|
||||||
|
42
go.mod
42
go.mod
@ -1,13 +1,13 @@
|
|||||||
module github.com/Secured-Finance/dione
|
module github.com/Secured-Finance/dione
|
||||||
|
|
||||||
go 1.14
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Secured-Finance/go-libp2p-pex v1.1.0
|
github.com/Secured-Finance/go-libp2p-pex v1.1.2
|
||||||
github.com/Secured-Finance/golang-set v1.8.0
|
github.com/Secured-Finance/golang-set v1.8.0
|
||||||
github.com/VictoriaMetrics/fastcache v1.5.7
|
|
||||||
github.com/aristanetworks/goarista v0.0.0-20210308203447-b196d8410f1d // indirect
|
github.com/aristanetworks/goarista v0.0.0-20210308203447-b196d8410f1d // indirect
|
||||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect
|
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef
|
||||||
|
github.com/btcsuite/btcd v0.22.0-beta // indirect
|
||||||
github.com/cespare/cp v1.1.1 // indirect
|
github.com/cespare/cp v1.1.1 // indirect
|
||||||
github.com/deckarep/golang-set v1.7.1 // indirect
|
github.com/deckarep/golang-set v1.7.1 // indirect
|
||||||
github.com/dgrr/fastws v1.0.0
|
github.com/dgrr/fastws v1.0.0
|
||||||
@ -16,13 +16,11 @@ require (
|
|||||||
github.com/ethereum/go-ethereum v1.9.25
|
github.com/ethereum/go-ethereum v1.9.25
|
||||||
github.com/filecoin-project/go-address v0.0.5
|
github.com/filecoin-project/go-address v0.0.5
|
||||||
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03
|
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03
|
||||||
github.com/filecoin-project/go-state-types v0.1.0
|
|
||||||
github.com/filecoin-project/lotus v1.6.0
|
github.com/filecoin-project/lotus v1.6.0
|
||||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
|
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.2.0
|
github.com/fxamacker/cbor/v2 v2.3.0
|
||||||
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
|
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect
|
||||||
github.com/go-kit/kit v0.10.0
|
github.com/go-kit/kit v0.10.0
|
||||||
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible
|
|
||||||
github.com/go-redis/redis/v8 v8.7.0
|
github.com/go-redis/redis/v8 v8.7.0
|
||||||
github.com/gobwas/ws v1.0.4 // indirect
|
github.com/gobwas/ws v1.0.4 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
@ -30,20 +28,21 @@ require (
|
|||||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
|
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
|
||||||
github.com/huin/goupnp v1.0.1-0.20200620063722-49508fba0031 // indirect
|
github.com/huin/goupnp v1.0.1-0.20200620063722-49508fba0031 // indirect
|
||||||
github.com/ipfs/go-log v1.0.4
|
github.com/ipfs/go-log v1.0.4
|
||||||
github.com/jmoiron/sqlx v1.2.0
|
github.com/ipfs/go-log/v2 v2.1.3 // indirect
|
||||||
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 // indirect
|
github.com/karalabe/usb v0.0.0-20191104083709-911d15fe12a9 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.0.6 // indirect
|
github.com/klauspost/cpuid/v2 v2.0.8 // indirect
|
||||||
github.com/libp2p/go-libp2p v0.12.0
|
github.com/ledgerwatch/lmdb-go v1.17.8
|
||||||
github.com/libp2p/go-libp2p-core v0.7.0
|
github.com/libp2p/go-libp2p v0.13.0
|
||||||
|
github.com/libp2p/go-libp2p-core v0.8.5
|
||||||
|
github.com/libp2p/go-libp2p-gorpc v0.1.3
|
||||||
github.com/libp2p/go-libp2p-pubsub v0.4.2-0.20210212194758-6c1addf493eb
|
github.com/libp2p/go-libp2p-pubsub v0.4.2-0.20210212194758-6c1addf493eb
|
||||||
github.com/mattn/go-sqlite3 v1.11.0
|
|
||||||
github.com/miguelmota/go-ethereum-hdwallet v0.0.0-20210314074952-8dd49aa599b9
|
github.com/miguelmota/go-ethereum-hdwallet v0.0.0-20210314074952-8dd49aa599b9
|
||||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1
|
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1
|
||||||
github.com/mitchellh/hashstructure/v2 v2.0.1
|
|
||||||
github.com/mitchellh/mapstructure v1.3.3 // indirect
|
github.com/mitchellh/mapstructure v1.3.3 // indirect
|
||||||
github.com/multiformats/go-multiaddr v0.3.1
|
github.com/multiformats/go-multiaddr v0.3.3
|
||||||
github.com/multiformats/go-multihash v0.0.15 // indirect
|
github.com/multiformats/go-multihash v0.0.15 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.4 // indirect
|
github.com/olekukonko/tablewriter v0.0.4 // indirect
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
github.com/raulk/clock v1.1.0
|
github.com/raulk/clock v1.1.0
|
||||||
github.com/rjeczalik/notify v0.9.2 // indirect
|
github.com/rjeczalik/notify v0.9.2 // indirect
|
||||||
github.com/rs/cors v1.7.0 // indirect
|
github.com/rs/cors v1.7.0 // indirect
|
||||||
@ -52,17 +51,18 @@ require (
|
|||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/spf13/viper v1.7.1
|
github.com/spf13/viper v1.7.1
|
||||||
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 // indirect
|
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969 // indirect
|
||||||
github.com/stretchr/testify v1.7.0
|
|
||||||
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
|
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
|
||||||
|
github.com/ugorji/go v1.2.6 // indirect
|
||||||
github.com/valyala/fasthttp v1.17.0
|
github.com/valyala/fasthttp v1.17.0
|
||||||
|
github.com/wealdtech/go-merkletree v1.0.1-0.20190605192610-2bb163c2ea2a
|
||||||
github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2
|
github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2
|
||||||
github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542
|
go.uber.org/fx v1.13.1
|
||||||
go.uber.org/zap v1.16.0
|
go.uber.org/multierr v1.7.0 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b
|
go.uber.org/zap v1.17.0
|
||||||
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect
|
golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
|
||||||
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 // indirect
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3 // indirect
|
|
||||||
nhooyr.io/websocket v1.8.6 // indirect
|
nhooyr.io/websocket v1.8.6 // indirect
|
||||||
)
|
)
|
||||||
|
126
go.sum
126
go.sum
@ -44,6 +44,7 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt
|
|||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
|
github.com/CurtisLusmore/ghp v0.0.0-20190131093722-04a23b486a62/go.mod h1:+iVlyn4r8pVe5rgooNlrYjuzDayoXL5H/JBMhemDs/I=
|
||||||
github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||||
github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
|
github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
|
||||||
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||||
@ -56,8 +57,8 @@ github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go
|
|||||||
github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=
|
github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y=
|
||||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/Secured-Finance/go-libp2p-pex v1.1.0 h1:u+VQmzKmECZJTCkmUwQw0NGU1xHQIZjY7gYElLOxl0o=
|
github.com/Secured-Finance/go-libp2p-pex v1.1.2 h1:0T/Qd77exlim+5XBpWNj30anqIFzbdAMPHajyBWvcnM=
|
||||||
github.com/Secured-Finance/go-libp2p-pex v1.1.0/go.mod h1:pMq1xsaluhIIdY8dALk/U7NH5N+naUCo/1jRgh8YNsI=
|
github.com/Secured-Finance/go-libp2p-pex v1.1.2/go.mod h1:pMq1xsaluhIIdY8dALk/U7NH5N+naUCo/1jRgh8YNsI=
|
||||||
github.com/Secured-Finance/golang-set v1.8.0 h1:2z3Aymw/LtvPsfRIJbX2p6xiSIQFxByzmGd2xYU0H9E=
|
github.com/Secured-Finance/golang-set v1.8.0 h1:2z3Aymw/LtvPsfRIJbX2p6xiSIQFxByzmGd2xYU0H9E=
|
||||||
github.com/Secured-Finance/golang-set v1.8.0/go.mod h1:NLdE4DjG2Aw84FTUFyspBP33PcmrRMxfNrrd+Eo9vJI=
|
github.com/Secured-Finance/golang-set v1.8.0/go.mod h1:NLdE4DjG2Aw84FTUFyspBP33PcmrRMxfNrrd+Eo9vJI=
|
||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
@ -106,8 +107,8 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
|
|||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||||
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg=
|
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef h1:2JGTg6JapxP9/R33ZaagQtAM4EkkSYnIAlOG5EI8gkM=
|
||||||
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
|
github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef/go.mod h1:JS7hed4L1fj0hXcyEejnW57/7LCetXggd+vwrRnYeII=
|
||||||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||||
github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
@ -132,8 +133,9 @@ github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcug
|
|||||||
github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
|
github.com/btcsuite/btcd v0.0.0-20190605094302-a0d1e3e36d50/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
|
||||||
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
|
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
|
||||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||||
github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M=
|
|
||||||
github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94=
|
github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94=
|
||||||
|
github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo=
|
||||||
|
github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA=
|
||||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||||
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||||
@ -178,7 +180,6 @@ github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u9
|
|||||||
github.com/cockroachdb/pebble v0.0.0-20200916222308-4e219a90ba5b/go.mod h1:hU7vhtrqonEphNF+xt8/lHdaBprxmV1h8BOGrd9XwmQ=
|
github.com/cockroachdb/pebble v0.0.0-20200916222308-4e219a90ba5b/go.mod h1:hU7vhtrqonEphNF+xt8/lHdaBprxmV1h8BOGrd9XwmQ=
|
||||||
github.com/cockroachdb/pebble v0.0.0-20201001221639-879f3bfeef07/go.mod h1:hU7vhtrqonEphNF+xt8/lHdaBprxmV1h8BOGrd9XwmQ=
|
github.com/cockroachdb/pebble v0.0.0-20201001221639-879f3bfeef07/go.mod h1:hU7vhtrqonEphNF+xt8/lHdaBprxmV1h8BOGrd9XwmQ=
|
||||||
github.com/cockroachdb/redact v0.0.0-20200622112456-cd282804bbd3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
github.com/cockroachdb/redact v0.0.0-20200622112456-cd282804bbd3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
|
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||||
github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
|
github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
@ -381,8 +382,9 @@ github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM
|
|||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ=
|
|
||||||
github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
|
github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.3.0 h1:aM45YGMctNakddNNAezPxDUpv38j44Abh+hifNuqXik=
|
||||||
|
github.com/fxamacker/cbor/v2 v2.3.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
|
||||||
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
|
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
|
||||||
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
|
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
|
||||||
@ -392,9 +394,7 @@ github.com/gbrlsnchs/jwt/v3 v3.0.0-beta.1/go.mod h1:0eHX/BVySxPc6SE2mZRoppGq7qcE
|
|||||||
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
||||||
github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs=
|
github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
|
|
||||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
|
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
|
||||||
@ -413,21 +413,14 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
|
|||||||
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
||||||
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
|
||||||
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
|
||||||
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible h1:msy24VGS42fKO9K1vLz82/GeYW1cILu7Nuuj1N3BBkE=
|
|
||||||
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU=
|
|
||||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
|
||||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
|
||||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
|
||||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||||
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
|
|
||||||
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
|
||||||
github.com/go-redis/redis/v8 v8.7.0 h1:LJ8sFG5eNH1u3SxlptEZ3mEgm/5J9Qx6QhiTG3HhpCo=
|
github.com/go-redis/redis/v8 v8.7.0 h1:LJ8sFG5eNH1u3SxlptEZ3mEgm/5J9Qx6QhiTG3HhpCo=
|
||||||
github.com/go-redis/redis/v8 v8.7.0/go.mod h1:BRxHBWn3pO3CfjyX6vAoyeRmCquvxr6QG+2onGV2gYs=
|
github.com/go-redis/redis/v8 v8.7.0/go.mod h1:BRxHBWn3pO3CfjyX6vAoyeRmCquvxr6QG+2onGV2gYs=
|
||||||
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
|
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
|
||||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
|
||||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
@ -757,8 +750,9 @@ github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBW
|
|||||||
github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=
|
github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=
|
||||||
github.com/ipfs/go-log/v2 v2.0.8/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=
|
github.com/ipfs/go-log/v2 v2.0.8/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=
|
||||||
github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
|
github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
|
||||||
github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4 h1:3bijxqzQ1O9yg7gd7Aqk80oaEvsJ+uXw0zSvi2qR3Jw=
|
|
||||||
github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
|
github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
|
||||||
|
github.com/ipfs/go-log/v2 v2.1.3 h1:1iS3IU7aXRlbgUpN8yTTpJ53NXYjAe37vcI5+5nYrzk=
|
||||||
|
github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g=
|
||||||
github.com/ipfs/go-merkledag v0.0.3/go.mod h1:Oc5kIXLHokkE1hWGMBHw+oxehkAaTOqtEb7Zbh6BhLA=
|
github.com/ipfs/go-merkledag v0.0.3/go.mod h1:Oc5kIXLHokkE1hWGMBHw+oxehkAaTOqtEb7Zbh6BhLA=
|
||||||
github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto=
|
github.com/ipfs/go-merkledag v0.0.6/go.mod h1:QYPdnlvkOg7GnQRofu9XZimC5ZW5Wi3bKys/4GQQfto=
|
||||||
github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk=
|
github.com/ipfs/go-merkledag v0.2.3/go.mod h1:SQiXrtSts3KGNmgOzMICy5c0POOpUNQLvB3ClKnBAlk=
|
||||||
@ -836,8 +830,6 @@ github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGAR
|
|||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
|
||||||
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
|
|
||||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
|
||||||
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1 h1:qBCV/RLV02TSfQa7tFmxTihnG+u+7JXByOkhlkR5rmQ=
|
github.com/jonboulle/clockwork v0.1.1-0.20190114141812-62fb9bc030d1 h1:qBCV/RLV02TSfQa7tFmxTihnG+u+7JXByOkhlkR5rmQ=
|
||||||
@ -852,7 +844,6 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
|
|||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
|
||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
@ -862,7 +853,6 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
|
|||||||
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3 h1:Iy7Ifq2ysilWU4QlCx/97OoI4xT1IV7i8byT/EyIT/M=
|
|
||||||
github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3/go.mod h1:BYpt4ufZiIGv2nXn4gMxnfKV306n3mWXgNu/d2TqdTU=
|
github.com/kabukky/httpscerts v0.0.0-20150320125433-617593d7dcb3/go.mod h1:BYpt4ufZiIGv2nXn4gMxnfKV306n3mWXgNu/d2TqdTU=
|
||||||
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=
|
github.com/kami-zh/go-capturer v0.0.0-20171211120116-e492ea43421d/go.mod h1:P2viExyCEfeWGU259JnaQ34Inuec4R38JCyBx2edgD0=
|
||||||
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
|
||||||
@ -888,8 +878,8 @@ github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w
|
|||||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.2/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.2/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.6 h1:dQ5ueTiftKxp0gyjKSx5+8BtPWkyQbd95m8Gys/RarI=
|
github.com/klauspost/cpuid/v2 v2.0.8 h1:bhR2mgIlno/Sfk4oUbH4sPlc83z1yGrN9bvqiq3C33I=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.8/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
|
github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
|
||||||
github.com/klauspost/reedsolomon v1.9.11/go.mod h1:nLvuzNvy1ZDNQW30IuMc2ZWCbiqrJgdLoUS2X8HAUVg=
|
github.com/klauspost/reedsolomon v1.9.11/go.mod h1:nLvuzNvy1ZDNQW30IuMc2ZWCbiqrJgdLoUS2X8HAUVg=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
@ -908,10 +898,9 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
github.com/ledgerwatch/lmdb-go v1.17.8 h1:IQUVJ2MYIfSsrhz+o+QbugUqRQuqTXodt8pE6cuvQVg=
|
||||||
|
github.com/ledgerwatch/lmdb-go v1.17.8/go.mod h1:NKRpCxksoTQPyxsUcBiVOe0135uqnJsnf6cElxmOL0o=
|
||||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|
||||||
github.com/lib/pq v1.7.0 h1:h93mCPfUSkaul3Ka/VG8uZdmW1uMHDGxzu0NWHuJmHY=
|
|
||||||
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ=
|
github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ=
|
||||||
github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU=
|
github.com/libp2p/go-addr-util v0.0.2 h1:7cWK5cdA5x72jX0g8iLrQWm5TRJZ6CzGdPEhWj7plWU=
|
||||||
@ -949,8 +938,9 @@ github.com/libp2p/go-libp2p v0.8.3/go.mod h1:EsH1A+8yoWK+L4iKcbPYu6MPluZ+CHWI9El
|
|||||||
github.com/libp2p/go-libp2p v0.9.2/go.mod h1:cunHNLDVus66Ct9iXXcjKRLdmHdFdHVe1TAnbubJQqQ=
|
github.com/libp2p/go-libp2p v0.9.2/go.mod h1:cunHNLDVus66Ct9iXXcjKRLdmHdFdHVe1TAnbubJQqQ=
|
||||||
github.com/libp2p/go-libp2p v0.10.0/go.mod h1:yBJNpb+mGJdgrwbKAKrhPU0u3ogyNFTfjJ6bdM+Q/G8=
|
github.com/libp2p/go-libp2p v0.10.0/go.mod h1:yBJNpb+mGJdgrwbKAKrhPU0u3ogyNFTfjJ6bdM+Q/G8=
|
||||||
github.com/libp2p/go-libp2p v0.11.0/go.mod h1:3/ogJDXsbbepEfqtZKBR/DedzxJXCeK17t2Z9RE9bEE=
|
github.com/libp2p/go-libp2p v0.11.0/go.mod h1:3/ogJDXsbbepEfqtZKBR/DedzxJXCeK17t2Z9RE9bEE=
|
||||||
github.com/libp2p/go-libp2p v0.12.0 h1:+xai9RQnQ9l5elFOKvp5wRyjyWisSwEx+6nU2+onpUA=
|
|
||||||
github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0=
|
github.com/libp2p/go-libp2p v0.12.0/go.mod h1:FpHZrfC1q7nA8jitvdjKBDF31hguaC676g/nT9PgQM0=
|
||||||
|
github.com/libp2p/go-libp2p v0.13.0 h1:tDdrXARSghmusdm0nf1U/4M8aj8Rr0V2IzQOXmbzQ3s=
|
||||||
|
github.com/libp2p/go-libp2p v0.13.0/go.mod h1:pM0beYdACRfHO1WcJlp65WXyG2A6NqYM+t2DTVAJxMo=
|
||||||
github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo=
|
github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052/go.mod h1:nRMRTab+kZuk0LnKZpxhOVH/ndsdr2Nr//Zltc/vwgo=
|
||||||
github.com/libp2p/go-libp2p-autonat v0.0.2/go.mod h1:fs71q5Xk+pdnKU014o2iq1RhMs9/PMaG5zXRFNnIIT4=
|
github.com/libp2p/go-libp2p-autonat v0.0.2/go.mod h1:fs71q5Xk+pdnKU014o2iq1RhMs9/PMaG5zXRFNnIIT4=
|
||||||
github.com/libp2p/go-libp2p-autonat v0.0.6/go.mod h1:uZneLdOkZHro35xIhpbtTzLlgYturpu4J5+0cZK3MqE=
|
github.com/libp2p/go-libp2p-autonat v0.0.6/go.mod h1:uZneLdOkZHro35xIhpbtTzLlgYturpu4J5+0cZK3MqE=
|
||||||
@ -1010,8 +1000,8 @@ github.com/libp2p/go-libp2p-core v0.5.6/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX
|
|||||||
github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=
|
github.com/libp2p/go-libp2p-core v0.5.7/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=
|
||||||
github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=
|
github.com/libp2p/go-libp2p-core v0.6.0/go.mod h1:txwbVEhHEXikXn9gfC7/UDDw7rkxuX0bJvM49Ykaswo=
|
||||||
github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
|
github.com/libp2p/go-libp2p-core v0.6.1/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
|
||||||
github.com/libp2p/go-libp2p-core v0.7.0 h1:4a0TMjrWNTZlNvcqxZmrMRDi/NQWrhwO2pkTuLSQ/IQ=
|
|
||||||
github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
|
github.com/libp2p/go-libp2p-core v0.7.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
|
||||||
|
github.com/libp2p/go-libp2p-core v0.8.0/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
|
||||||
github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw=
|
github.com/libp2p/go-libp2p-core v0.8.5 h1:aEgbIcPGsKy6zYcC+5AJivYFedhYa4sW7mIpWpUaLKw=
|
||||||
github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
|
github.com/libp2p/go-libp2p-core v0.8.5/go.mod h1:FfewUH/YpvWbEB+ZY9AQRQ4TAD8sJBt/G1rVvhz5XT8=
|
||||||
github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE=
|
github.com/libp2p/go-libp2p-crypto v0.0.1/go.mod h1:yJkNyDmO341d5wwXxDUGO0LykUVT72ImHNUqh5D/dBE=
|
||||||
@ -1027,6 +1017,8 @@ github.com/libp2p/go-libp2p-discovery v0.3.0/go.mod h1:o03drFnz9BVAZdzC/QUQ+NeQO
|
|||||||
github.com/libp2p/go-libp2p-discovery v0.4.0/go.mod h1:bZ0aJSrFc/eX2llP0ryhb1kpgkPyTo23SJ5b7UQCMh4=
|
github.com/libp2p/go-libp2p-discovery v0.4.0/go.mod h1:bZ0aJSrFc/eX2llP0ryhb1kpgkPyTo23SJ5b7UQCMh4=
|
||||||
github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ=
|
github.com/libp2p/go-libp2p-discovery v0.5.0 h1:Qfl+e5+lfDgwdrXdu4YNCWyEo3fWuP+WgN9mN0iWviQ=
|
||||||
github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug=
|
github.com/libp2p/go-libp2p-discovery v0.5.0/go.mod h1:+srtPIU9gDaBNu//UHvcdliKBIcr4SfDcm0/PfPJLug=
|
||||||
|
github.com/libp2p/go-libp2p-gorpc v0.1.3 h1:b0bRXD4PEfqIvXbivDhNnaSQ8ERoaYd0vM7mDIDLQCQ=
|
||||||
|
github.com/libp2p/go-libp2p-gorpc v0.1.3/go.mod h1:ulZShaJCp3JHlBMHiA20efUmiqDECza+JvGFNXJyKdI=
|
||||||
github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go=
|
github.com/libp2p/go-libp2p-host v0.0.1/go.mod h1:qWd+H1yuU0m5CwzAkvbSjqKairayEHdR5MMl7Cwa7Go=
|
||||||
github.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8=
|
github.com/libp2p/go-libp2p-host v0.0.3/go.mod h1:Y/qPyA6C8j2coYyos1dfRm0I8+nvd4TGrDGt4tA7JR8=
|
||||||
github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k=
|
github.com/libp2p/go-libp2p-interface-connmgr v0.0.1/go.mod h1:GarlRLH0LdeWcLnYM/SaBykKFl9U5JFnbBGruAk/D5k=
|
||||||
@ -1047,8 +1039,10 @@ github.com/libp2p/go-libp2p-mplex v0.2.1/go.mod h1:SC99Rxs8Vuzrf/6WhmH41kNn13TiY
|
|||||||
github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo=
|
github.com/libp2p/go-libp2p-mplex v0.2.2/go.mod h1:74S9eum0tVQdAfFiKxAyKzNdSuLqw5oadDq7+L/FELo=
|
||||||
github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek=
|
github.com/libp2p/go-libp2p-mplex v0.2.3/go.mod h1:CK3p2+9qH9x+7ER/gWWDYJ3QW5ZxWDkm+dVvjfuG3ek=
|
||||||
github.com/libp2p/go-libp2p-mplex v0.2.4/go.mod h1:mI7iOezdWFOisvUwaYd3IDrJ4oVmgoXK8H331ui39CE=
|
github.com/libp2p/go-libp2p-mplex v0.2.4/go.mod h1:mI7iOezdWFOisvUwaYd3IDrJ4oVmgoXK8H331ui39CE=
|
||||||
github.com/libp2p/go-libp2p-mplex v0.3.0 h1:CZyqqKP0BSGQyPLvpRQougbfXaaaJZdGgzhCpJNuNSk=
|
|
||||||
github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs=
|
github.com/libp2p/go-libp2p-mplex v0.3.0/go.mod h1:l9QWxRbbb5/hQMECEb908GbS9Sm2UAR2KFZKUJEynEs=
|
||||||
|
github.com/libp2p/go-libp2p-mplex v0.4.0/go.mod h1:yCyWJE2sc6TBTnFpjvLuEJgTSw/u+MamvzILKdX7asw=
|
||||||
|
github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc=
|
||||||
|
github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g=
|
||||||
github.com/libp2p/go-libp2p-nat v0.0.2/go.mod h1:QrjXQSD5Dj4IJOdEcjHRkWTSomyxRo6HnUkf/TfQpLQ=
|
github.com/libp2p/go-libp2p-nat v0.0.2/go.mod h1:QrjXQSD5Dj4IJOdEcjHRkWTSomyxRo6HnUkf/TfQpLQ=
|
||||||
github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY=
|
github.com/libp2p/go-libp2p-nat v0.0.4/go.mod h1:N9Js/zVtAXqaeT99cXgTV9e75KpnWCvVOiGzlcHmBbY=
|
||||||
github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE=
|
github.com/libp2p/go-libp2p-nat v0.0.5/go.mod h1:1qubaE5bTZMJE+E/uu2URroMbzdubFz1ChgiN79yKPE=
|
||||||
@ -1114,8 +1108,9 @@ github.com/libp2p/go-libp2p-swarm v0.2.4/go.mod h1:/xIpHFPPh3wmSthtxdGbkHZ0OET1h
|
|||||||
github.com/libp2p/go-libp2p-swarm v0.2.7/go.mod h1:ZSJ0Q+oq/B1JgfPHJAT2HTall+xYRNYp1xs4S2FBWKA=
|
github.com/libp2p/go-libp2p-swarm v0.2.7/go.mod h1:ZSJ0Q+oq/B1JgfPHJAT2HTall+xYRNYp1xs4S2FBWKA=
|
||||||
github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM=
|
github.com/libp2p/go-libp2p-swarm v0.2.8/go.mod h1:JQKMGSth4SMqonruY0a8yjlPVIkb0mdNSwckW7OYziM=
|
||||||
github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk=
|
github.com/libp2p/go-libp2p-swarm v0.3.0/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk=
|
||||||
github.com/libp2p/go-libp2p-swarm v0.3.1 h1:UTobu+oQHGdXTOGpZ4RefuVqYoJXcT0EBtSR74m2LkI=
|
|
||||||
github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk=
|
github.com/libp2p/go-libp2p-swarm v0.3.1/go.mod h1:hdv95GWCTmzkgeJpP+GK/9D9puJegb7H57B5hWQR5Kk=
|
||||||
|
github.com/libp2p/go-libp2p-swarm v0.4.0 h1:hahq/ijRoeH6dgROOM8x7SeaKK5VgjjIr96vdrT+NUA=
|
||||||
|
github.com/libp2p/go-libp2p-swarm v0.4.0/go.mod h1:XVFcO52VoLoo0eitSxNQWYq4D6sydGOweTOAjJNraCw=
|
||||||
github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
|
github.com/libp2p/go-libp2p-testing v0.0.1/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
|
||||||
github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
|
github.com/libp2p/go-libp2p-testing v0.0.2/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
|
||||||
github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
|
github.com/libp2p/go-libp2p-testing v0.0.3/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MBLK8jM3V4Zghvmi+E=
|
||||||
@ -1123,8 +1118,9 @@ github.com/libp2p/go-libp2p-testing v0.0.4/go.mod h1:gvchhf3FQOtBdr+eFUABet5a4MB
|
|||||||
github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
|
github.com/libp2p/go-libp2p-testing v0.1.0/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
|
||||||
github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
|
github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
|
||||||
github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc=
|
github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc=
|
||||||
github.com/libp2p/go-libp2p-testing v0.3.0 h1:ZiBYstPamsi7y6NJZebRudUzsYmVkt998hltyLqf8+g=
|
|
||||||
github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g=
|
github.com/libp2p/go-libp2p-testing v0.3.0/go.mod h1:efZkql4UZ7OVsEfaxNHZPzIehtsBXMrXnCfJIgDti5g=
|
||||||
|
github.com/libp2p/go-libp2p-testing v0.4.0 h1:PrwHRi0IGqOwVQWR3xzgigSlhlLfxgfXgkHxr77EghQ=
|
||||||
|
github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0=
|
||||||
github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM=
|
github.com/libp2p/go-libp2p-tls v0.1.3 h1:twKMhMu44jQO+HgQK9X8NHO5HkeJu2QbhLzLJpa8oNM=
|
||||||
github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M=
|
github.com/libp2p/go-libp2p-tls v0.1.3/go.mod h1:wZfuewxOndz5RTnCAxFliGjvYSDA40sKitV4c50uI1M=
|
||||||
github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk=
|
github.com/libp2p/go-libp2p-transport v0.0.1/go.mod h1:UzbUs9X+PHOSw7S3ZmeOxfnwaQY5vGDzZmKPod3N3tk=
|
||||||
@ -1134,8 +1130,9 @@ github.com/libp2p/go-libp2p-transport-upgrader v0.0.1/go.mod h1:NJpUAgQab/8K6K0m
|
|||||||
github.com/libp2p/go-libp2p-transport-upgrader v0.0.4/go.mod h1:RGq+tupk+oj7PzL2kn/m1w6YXxcIAYJYeI90h6BGgUc=
|
github.com/libp2p/go-libp2p-transport-upgrader v0.0.4/go.mod h1:RGq+tupk+oj7PzL2kn/m1w6YXxcIAYJYeI90h6BGgUc=
|
||||||
github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA=
|
github.com/libp2p/go-libp2p-transport-upgrader v0.1.1/go.mod h1:IEtA6or8JUbsV07qPW4r01GnTenLW4oi3lOPbUMGJJA=
|
||||||
github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns=
|
github.com/libp2p/go-libp2p-transport-upgrader v0.2.0/go.mod h1:mQcrHj4asu6ArfSoMuyojOdjx73Q47cYD7s5+gZOlns=
|
||||||
github.com/libp2p/go-libp2p-transport-upgrader v0.3.0 h1:q3ULhsknEQ34eVDhv4YwKS8iet69ffs9+Fir6a7weN4=
|
|
||||||
github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o=
|
github.com/libp2p/go-libp2p-transport-upgrader v0.3.0/go.mod h1:i+SKzbRnvXdVbU3D1dwydnTmKRPXiAR/fyvi1dXuL4o=
|
||||||
|
github.com/libp2p/go-libp2p-transport-upgrader v0.4.0 h1:xwj4h3hJdBrxqMOyMUjwscjoVst0AASTsKtZiTChoHI=
|
||||||
|
github.com/libp2p/go-libp2p-transport-upgrader v0.4.0/go.mod h1:J4ko0ObtZSmgn5BX5AmegP+dK3CSnU2lMCKsSq/EY0s=
|
||||||
github.com/libp2p/go-libp2p-yamux v0.1.2/go.mod h1:xUoV/RmYkg6BW/qGxA9XJyg+HzXFYkeXbnhjmnYzKp8=
|
github.com/libp2p/go-libp2p-yamux v0.1.2/go.mod h1:xUoV/RmYkg6BW/qGxA9XJyg+HzXFYkeXbnhjmnYzKp8=
|
||||||
github.com/libp2p/go-libp2p-yamux v0.1.3/go.mod h1:VGSQVrqkh6y4nm0189qqxMtvyBft44MOYYPpYKXiVt4=
|
github.com/libp2p/go-libp2p-yamux v0.1.3/go.mod h1:VGSQVrqkh6y4nm0189qqxMtvyBft44MOYYPpYKXiVt4=
|
||||||
github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8=
|
github.com/libp2p/go-libp2p-yamux v0.2.0/go.mod h1:Db2gU+XfLpm6E4rG5uGCFX6uXA8MEXOxFcRoXUODaK8=
|
||||||
@ -1145,8 +1142,10 @@ github.com/libp2p/go-libp2p-yamux v0.2.5/go.mod h1:Zpgj6arbyQrmZ3wxSZxfBmbdnWtbZ
|
|||||||
github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU=
|
github.com/libp2p/go-libp2p-yamux v0.2.7/go.mod h1:X28ENrBMU/nm4I3Nx4sZ4dgjZ6VhLEn0XhIoZ5viCwU=
|
||||||
github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4=
|
github.com/libp2p/go-libp2p-yamux v0.2.8/go.mod h1:/t6tDqeuZf0INZMTgd0WxIRbtK2EzI2h7HbFm9eAKI4=
|
||||||
github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30=
|
github.com/libp2p/go-libp2p-yamux v0.4.0/go.mod h1:+DWDjtFMzoAwYLVkNZftoucn7PelNoy5nm3tZ3/Zw30=
|
||||||
github.com/libp2p/go-libp2p-yamux v0.4.1 h1:TJxRVPY9SjH7TNrNC80l1OJMBiWhs1qpKmeB+1Ug3xU=
|
|
||||||
github.com/libp2p/go-libp2p-yamux v0.4.1/go.mod h1:FA/NjRYRVNjqOzpGuGqcruH7jAU2mYIjtKBicVOL3dc=
|
github.com/libp2p/go-libp2p-yamux v0.4.1/go.mod h1:FA/NjRYRVNjqOzpGuGqcruH7jAU2mYIjtKBicVOL3dc=
|
||||||
|
github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po=
|
||||||
|
github.com/libp2p/go-libp2p-yamux v0.5.1 h1:sX4WQPHMhRxJE5UZTfjEuBvlQWXB5Bo3A2JK9ZJ9EM0=
|
||||||
|
github.com/libp2p/go-libp2p-yamux v0.5.1/go.mod h1:dowuvDu8CRWmr0iqySMiSxK+W0iL5cMVO9S94Y6gkv4=
|
||||||
github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=
|
github.com/libp2p/go-maddr-filter v0.0.1/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=
|
||||||
github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=
|
github.com/libp2p/go-maddr-filter v0.0.4/go.mod h1:6eT12kSQMA9x2pvFQa+xesMKUBlj9VImZbj3B9FBH/Q=
|
||||||
github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M=
|
github.com/libp2p/go-maddr-filter v0.0.5/go.mod h1:Jk+36PMfIqCJhAnaASRH83bdAvfDRp/w6ENFaC9bG+M=
|
||||||
@ -1157,8 +1156,9 @@ github.com/libp2p/go-mplex v0.0.4/go.mod h1:pK5yMLmOoBR1pNCqDlA2GQrdAVTMkqFalaTW
|
|||||||
github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU=
|
github.com/libp2p/go-mplex v0.1.0/go.mod h1:SXgmdki2kwCUlCCbfGLEgHjC4pFqhTp0ZoV6aiKgxDU=
|
||||||
github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=
|
github.com/libp2p/go-mplex v0.1.1/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=
|
||||||
github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=
|
github.com/libp2p/go-mplex v0.1.2/go.mod h1:Xgz2RDCi3co0LeZfgjm4OgUF15+sVR8SRcu3SFXI1lk=
|
||||||
github.com/libp2p/go-mplex v0.2.0 h1:Ov/D+8oBlbRkjBs1R1Iua8hJ8cUfbdiW8EOdZuxcgaI=
|
|
||||||
github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ=
|
github.com/libp2p/go-mplex v0.2.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ=
|
||||||
|
github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU=
|
||||||
|
github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ=
|
||||||
github.com/libp2p/go-msgio v0.0.1/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
|
github.com/libp2p/go-msgio v0.0.1/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
|
||||||
github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
|
github.com/libp2p/go-msgio v0.0.2/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
|
||||||
github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
|
github.com/libp2p/go-msgio v0.0.3/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
|
||||||
@ -1210,8 +1210,9 @@ github.com/libp2p/go-ws-transport v0.1.0/go.mod h1:rjw1MG1LU9YDC6gzmwObkPd/Sqwhw
|
|||||||
github.com/libp2p/go-ws-transport v0.1.2/go.mod h1:dsh2Ld8F+XNmzpkaAijmg5Is+e9l6/1tK/6VFOdN69Y=
|
github.com/libp2p/go-ws-transport v0.1.2/go.mod h1:dsh2Ld8F+XNmzpkaAijmg5Is+e9l6/1tK/6VFOdN69Y=
|
||||||
github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM=
|
github.com/libp2p/go-ws-transport v0.2.0/go.mod h1:9BHJz/4Q5A9ludYWKoGCFC5gUElzlHoKzu0yY9p/klM=
|
||||||
github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=
|
github.com/libp2p/go-ws-transport v0.3.0/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=
|
||||||
github.com/libp2p/go-ws-transport v0.3.1 h1:ZX5rWB8nhRRJVaPO6tmkGI/Xx8XNboYX20PW5hXIscw=
|
|
||||||
github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=
|
github.com/libp2p/go-ws-transport v0.3.1/go.mod h1:bpgTJmRZAvVHrgHybCVyqoBmyLQ1fiZuEaBYusP5zsk=
|
||||||
|
github.com/libp2p/go-ws-transport v0.4.0 h1:9tvtQ9xbws6cA5LvqdE6Ne3vcmGB4f1z9SByggk4s0k=
|
||||||
|
github.com/libp2p/go-ws-transport v0.4.0/go.mod h1:EcIEKqf/7GDjth6ksuS/6p7R49V4CBY6/E7R/iyhYUA=
|
||||||
github.com/libp2p/go-yamux v1.2.1/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
|
github.com/libp2p/go-yamux v1.2.1/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
|
||||||
github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
|
github.com/libp2p/go-yamux v1.2.2/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
|
||||||
github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
|
github.com/libp2p/go-yamux v1.2.3/go.mod h1:FGTiPvoV/3DVdgWpX+tM0OW3tsM+W5bSE3gZwqQTcow=
|
||||||
@ -1223,6 +1224,8 @@ github.com/libp2p/go-yamux v1.3.7/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/h
|
|||||||
github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=
|
github.com/libp2p/go-yamux v1.4.0/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=
|
||||||
github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI=
|
github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI=
|
||||||
github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=
|
github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=
|
||||||
|
github.com/libp2p/go-yamux/v2 v2.0.0 h1:vSGhAy5u6iHBq11ZDcyHH4Blcf9xlBhT4WQDoOE90LU=
|
||||||
|
github.com/libp2p/go-yamux/v2 v2.0.0/go.mod h1:NVWira5+sVUIU6tu1JWvaRn1dRnG+cawOJiflsAM+7U=
|
||||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||||
github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw=
|
github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw=
|
||||||
@ -1264,9 +1267,6 @@ github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
|
|||||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
|
||||||
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
|
|
||||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
|
||||||
github.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA=
|
github.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
@ -1308,10 +1308,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
|
|||||||
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
|
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
|
||||||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
||||||
github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
github.com/mr-tron/base58 v1.1.1/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
||||||
@ -1332,8 +1330,9 @@ github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y9
|
|||||||
github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE=
|
github.com/multiformats/go-multiaddr v0.2.1/go.mod h1:s/Apk6IyxfvMjDafnhJgJ3/46z7tZ04iMk5wP4QMGGE=
|
||||||
github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y=
|
github.com/multiformats/go-multiaddr v0.2.2/go.mod h1:NtfXiOtHvghW9KojvtySjH5y0u0xW5UouOmQQrn6a3Y=
|
||||||
github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI=
|
github.com/multiformats/go-multiaddr v0.3.0/go.mod h1:dF9kph9wfJ+3VLAaeBqo9Of8x4fJxp6ggJGteB8HQTI=
|
||||||
github.com/multiformats/go-multiaddr v0.3.1 h1:1bxa+W7j9wZKTZREySx1vPMs2TqrYWjVZ7zE6/XLG1I=
|
|
||||||
github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc=
|
github.com/multiformats/go-multiaddr v0.3.1/go.mod h1:uPbspcUPd5AfaP6ql3ujFY+QWzmBD8uLLL4bXW0XfGc=
|
||||||
|
github.com/multiformats/go-multiaddr v0.3.3 h1:vo2OTSAqnENB2rLk79pLtr+uhj+VAzSe3uef5q0lRSs=
|
||||||
|
github.com/multiformats/go-multiaddr v0.3.3/go.mod h1:lCKNGP1EQ1eZ35Za2wlqnabm9xQkib3fyB+nZXHLag0=
|
||||||
github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
|
github.com/multiformats/go-multiaddr-dns v0.0.1/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
|
||||||
github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
|
github.com/multiformats/go-multiaddr-dns v0.0.2/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
|
||||||
github.com/multiformats/go-multiaddr-dns v0.0.3/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
|
github.com/multiformats/go-multiaddr-dns v0.0.3/go.mod h1:9kWcqw/Pj6FwxAwW38n/9403szc57zJPs45fmnznu3Q=
|
||||||
@ -1453,6 +1452,8 @@ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh
|
|||||||
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||||
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
|
github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
|
||||||
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
|
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
|
||||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||||
@ -1645,7 +1646,6 @@ github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3
|
|||||||
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||||
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
@ -1682,11 +1682,15 @@ github.com/uber/jaeger-client-go v2.23.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMW
|
|||||||
github.com/uber/jaeger-lib v1.5.1-0.20181102163054-1fc5c315e03c/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
github.com/uber/jaeger-lib v1.5.1-0.20181102163054-1fc5c315e03c/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||||
github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw=
|
github.com/uber/jaeger-lib v2.2.0+incompatible h1:MxZXOiR2JuoANZ3J6DE/U0kSFv/eJ/GfSYVCjK7dyaw=
|
||||||
github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
github.com/uber/jaeger-lib v2.2.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
|
||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
|
github.com/ugorji/go v1.1.13/go.mod h1:jxau1n+/wyTGLQoCkjok9r5zFa/FxT6eI5HiHKQszjc=
|
||||||
|
github.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E=
|
||||||
|
github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
|
||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
|
github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU=
|
||||||
|
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
|
||||||
|
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
||||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
|
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
|
||||||
@ -1708,6 +1712,8 @@ github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvS
|
|||||||
github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
|
github.com/warpfork/go-wish v0.0.0-20190328234359-8b3e70f8e830/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
|
||||||
github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w=
|
github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w=
|
||||||
github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
|
github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
|
||||||
|
github.com/wealdtech/go-merkletree v1.0.1-0.20190605192610-2bb163c2ea2a h1:MwXxGlHLoTCM3/5nlvGJqSWhcmWtGuc6RBtUsTKJwvU=
|
||||||
|
github.com/wealdtech/go-merkletree v1.0.1-0.20190605192610-2bb163c2ea2a/go.mod h1:Q/vZYhXjtE/oLDRqlGLWwRrNKZJAwidHlVfwIkKEH2w=
|
||||||
github.com/weaveworks/common v0.0.0-20200512154658-384f10054ec5 h1:EYxr08r8x6r/5fLEAMMkida1BVgxVXE4LfZv/XV+znU=
|
github.com/weaveworks/common v0.0.0-20200512154658-384f10054ec5 h1:EYxr08r8x6r/5fLEAMMkida1BVgxVXE4LfZv/XV+znU=
|
||||||
github.com/weaveworks/common v0.0.0-20200512154658-384f10054ec5/go.mod h1:c98fKi5B9u8OsKGiWHLRKus6ToQ1Tubeow44ECO1uxY=
|
github.com/weaveworks/common v0.0.0-20200512154658-384f10054ec5/go.mod h1:c98fKi5B9u8OsKGiWHLRKus6ToQ1Tubeow44ECO1uxY=
|
||||||
github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZGz7M=
|
github.com/weaveworks/promrus v1.2.0 h1:jOLf6pe6/vss4qGHjXmGz4oDJQA+AOCqEL3FvvZGz7M=
|
||||||
@ -1778,7 +1784,6 @@ github.com/zondax/ledger-go v0.12.1/go.mod h1:KatxXrVDzgWwbssUWsF5+cOJHXPvzQ09YS
|
|||||||
go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs=
|
go.dedis.ch/fixbuf v1.0.3 h1:hGcV9Cd/znUxlusJ64eAlExS+5cJDIyTyEG+otu5wQs=
|
||||||
go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw=
|
go.dedis.ch/fixbuf v1.0.3/go.mod h1:yzJMt34Wa5xD37V5RTdmp38cz3QhMagdGoem9anUalw=
|
||||||
go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ=
|
go.dedis.ch/kyber/v3 v3.0.4/go.mod h1:OzvaEnPvKlyrWyp3kGXlFdp7ap1VC6RkZDTaPikqhsQ=
|
||||||
go.dedis.ch/kyber/v3 v3.0.9 h1:i0ZbOQocHUjfFasBiUql5zVeC7u/vahFd96DFA8UOWk=
|
|
||||||
go.dedis.ch/kyber/v3 v3.0.9/go.mod h1:rhNjUUg6ahf8HEg5HUvVBYoWY4boAafX8tYxX+PS+qg=
|
go.dedis.ch/kyber/v3 v3.0.9/go.mod h1:rhNjUUg6ahf8HEg5HUvVBYoWY4boAafX8tYxX+PS+qg=
|
||||||
go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo=
|
go.dedis.ch/protobuf v1.0.5/go.mod h1:eIV4wicvi6JK0q/QnfIEGeSFNG0ZeB24kzut5+HaRLo=
|
||||||
go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4=
|
go.dedis.ch/protobuf v1.0.7/go.mod h1:pv5ysfkDX/EawiPqcW3ikOxsL5t+BqnV6xHSmE79KI4=
|
||||||
@ -1815,25 +1820,30 @@ go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
|||||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/dig v1.10.0 h1:yLmDDj9/zuDjv3gz8GQGviXMs9TfysIUMUilCpgzUJY=
|
||||||
go.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw=
|
go.uber.org/dig v1.10.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw=
|
||||||
go.uber.org/fx v1.9.0/go.mod h1:mFdUyAUuJ3w4jAckiKSKbldsxy1ojpAMJ+dVZg5Y0Aw=
|
go.uber.org/fx v1.9.0/go.mod h1:mFdUyAUuJ3w4jAckiKSKbldsxy1ojpAMJ+dVZg5Y0Aw=
|
||||||
|
go.uber.org/fx v1.13.1 h1:CFNTr1oin5OJ0VCZ8EycL3wzF29Jz2g0xe55RFsf2a4=
|
||||||
|
go.uber.org/fx v1.13.1/go.mod h1:bREWhavnedxpJeTq9pQT53BbvwhUv7TcpsOqcH4a+3w=
|
||||||
|
go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI=
|
||||||
go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo=
|
go.uber.org/goleak v1.0.0 h1:qsup4IcBdlmsnGfqyLl4Ntn3C2XCCuKAE7DwHpScyUo=
|
||||||
go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
go.uber.org/goleak v1.0.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||||
go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
|
go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
|
||||||
|
go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||||
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||||
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
|
|
||||||
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
||||||
|
go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
|
||||||
|
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||||
go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU=
|
|
||||||
go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
|
go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg=
|
||||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
@ -1842,6 +1852,7 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf
|
|||||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
@ -1876,8 +1887,8 @@ golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPh
|
|||||||
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
|
||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@ -1969,8 +1980,8 @@ golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwY
|
|||||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
|
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
|
||||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
@ -2005,6 +2016,7 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@ -2073,8 +2085,9 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||||
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@ -2120,10 +2133,10 @@ golang.org/x/tools v0.0.0-20191030062658-86caa796c7ab/go.mod h1:b+2E5dAYhXwXZwtn
|
|||||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20191114200427-caa0b0f7d508/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
@ -2273,7 +2286,6 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
|
||||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
@ -2282,8 +2294,6 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
|
|||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
|
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
|
||||||
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
|
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
|
||||||
modernc.org/cc v1.0.0 h1:nPibNuDEx6tvYrUAtvDTTw98rx5juGsa5zuDnKwEEQQ=
|
modernc.org/cc v1.0.0 h1:nPibNuDEx6tvYrUAtvDTTw98rx5juGsa5zuDnKwEEQQ=
|
||||||
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
|
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
|
||||||
|
6
node/flags.go
Normal file
6
node/flags.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
type AppFlags struct {
|
||||||
|
ConfigPath string
|
||||||
|
Verbose bool
|
||||||
|
}
|
95
node/network_service.go
Normal file
95
node/network_service.go
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain"
|
||||||
|
|
||||||
|
gorpc "github.com/libp2p/go-libp2p-gorpc"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/consensus/policy"
|
||||||
|
"github.com/Secured-Finance/dione/node/wire"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain/pool"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NetworkService struct {
|
||||||
|
blockchain *blockchain.BlockChain
|
||||||
|
mempool *pool.Mempool
|
||||||
|
rpcClient *gorpc.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNetworkService(bc *blockchain.BlockChain, mp *pool.Mempool) *NetworkService {
|
||||||
|
return &NetworkService{
|
||||||
|
blockchain: bc,
|
||||||
|
mempool: mp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NetworkService) LastBlockHeight(ctx context.Context, arg struct{}, reply *wire.LastBlockHeightReply) error {
|
||||||
|
height, err := s.blockchain.GetLatestBlockHeight()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
reply.Height = height
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NetworkService) GetRangeOfBlocks(ctx context.Context, arg wire.GetRangeOfBlocksArg, reply *wire.GetRangeOfBlocksReply) error {
|
||||||
|
if arg.From > arg.To {
|
||||||
|
return fmt.Errorf("incorrect arguments: from > to")
|
||||||
|
}
|
||||||
|
if arg.To-arg.From > policy.MaxBlockCountForRetrieving {
|
||||||
|
return fmt.Errorf("incorrect arguments: count of block for retrieving is exceeded the limit")
|
||||||
|
}
|
||||||
|
for i := arg.From; i <= arg.To; i++ {
|
||||||
|
block, err := s.blockchain.FetchBlockByHeight(i)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("failed to retrieve block from blockpool with height %d", i)
|
||||||
|
reply.FailedBlockHeights = append(reply.FailedBlockHeights, i)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
reply.Blocks = append(reply.Blocks, *block)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NetworkService) Mempool(ctx context.Context, arg struct{}, reply *wire.InvMessage) error {
|
||||||
|
txs := s.mempool.GetAllTransactions()
|
||||||
|
|
||||||
|
// extract hashes of txs
|
||||||
|
for _, v := range txs {
|
||||||
|
reply.Inventory = append(reply.Inventory, wire.InvItem{
|
||||||
|
Type: wire.TxInvType,
|
||||||
|
Hash: v.Hash,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NetworkService) GetMempoolTxs(ctx context.Context, arg wire.GetMempoolTxsArg, reply *wire.GetMempoolTxsReply) error {
|
||||||
|
if len(arg.Items) > policy.MaxTransactionCountForRetrieving {
|
||||||
|
pid, _ := gorpc.GetRequestSender(ctx)
|
||||||
|
logrus.Warnf("Max tx count limit exceeded for GetMempoolTxs request of node %s", pid)
|
||||||
|
return fmt.Errorf("max tx count limit exceeded")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range arg.Items {
|
||||||
|
tx, err := s.mempool.GetTransaction(v)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, pool.ErrTxNotFound) {
|
||||||
|
reply.NotFoundTxs = append(reply.NotFoundTxs, v)
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reply.Transactions = append(reply.Transactions, *tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
468
node/node.go
468
node/node.go
@ -2,49 +2,37 @@ package node
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
pex "github.com/Secured-Finance/go-libp2p-pex"
|
"github.com/Secured-Finance/dione/blockchain"
|
||||||
|
|
||||||
|
drand2 "github.com/Secured-Finance/dione/beacon/drand"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/pubsub"
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/cache"
|
|
||||||
"github.com/Secured-Finance/dione/consensus"
|
"github.com/Secured-Finance/dione/consensus"
|
||||||
|
|
||||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
"github.com/Secured-Finance/dione/blockchain/sync"
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/drand"
|
"go.uber.org/fx"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/fxamacker/cbor/v2"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
|
||||||
|
"github.com/Secured-Finance/dione/types"
|
||||||
|
|
||||||
|
types2 "github.com/Secured-Finance/dione/blockchain/types"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain/pool"
|
||||||
|
|
||||||
"github.com/libp2p/go-libp2p-core/discovery"
|
"github.com/libp2p/go-libp2p-core/discovery"
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/rpc"
|
"github.com/Secured-Finance/dione/rpc"
|
||||||
rtypes "github.com/Secured-Finance/dione/rpc/types"
|
|
||||||
|
|
||||||
solana2 "github.com/Secured-Finance/dione/rpc/solana"
|
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/rpc/filecoin"
|
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/types"
|
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/wallet"
|
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/beacon"
|
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/config"
|
"github.com/Secured-Finance/dione/config"
|
||||||
"github.com/Secured-Finance/dione/ethclient"
|
"github.com/Secured-Finance/dione/ethclient"
|
||||||
pubsub2 "github.com/Secured-Finance/dione/pubsub"
|
|
||||||
"github.com/libp2p/go-libp2p"
|
|
||||||
crypto "github.com/libp2p/go-libp2p-core/crypto"
|
|
||||||
"github.com/libp2p/go-libp2p-core/host"
|
"github.com/libp2p/go-libp2p-core/host"
|
||||||
"github.com/multiformats/go-multiaddr"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -52,129 +40,58 @@ const (
|
|||||||
DefaultPEXUpdateTime = 6 * time.Second
|
DefaultPEXUpdateTime = 6 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
type Node struct {
|
func runNode(
|
||||||
Host host.Host
|
lc fx.Lifecycle,
|
||||||
PeerDiscovery discovery.Discovery
|
cfg *config.Config,
|
||||||
PubSubRouter *pubsub2.PubSubRouter
|
disco discovery.Discovery,
|
||||||
GlobalCtx context.Context
|
ethClient *ethclient.EthereumClient,
|
||||||
GlobalCtxCancel context.CancelFunc
|
h host.Host,
|
||||||
Config *config.Config
|
mp *pool.Mempool,
|
||||||
Ethereum *ethclient.EthereumClient
|
syncManager sync.SyncManager,
|
||||||
ConsensusManager *consensus.PBFTConsensusManager
|
consensusManager *consensus.PBFTConsensusManager,
|
||||||
Miner *consensus.Miner
|
pubSubRouter *pubsub.PubSubRouter,
|
||||||
Beacon beacon.BeaconNetworks
|
disputeManager *consensus.DisputeManager,
|
||||||
Wallet *wallet.LocalWallet
|
db *drand2.DrandBeacon,
|
||||||
EventCache cache.EventCache
|
) {
|
||||||
DisputeManager *consensus.DisputeManager
|
lc.Append(fx.Hook{
|
||||||
}
|
OnStart: func(ctx context.Context) error {
|
||||||
|
err := runLibp2pAsync(context.TODO(), h, cfg, disco)
|
||||||
func NewNode(config *config.Config, prvKey crypto.PrivKey, pexDiscoveryUpdateTime time.Duration) (*Node, error) {
|
|
||||||
n := &Node{
|
|
||||||
Config: config,
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize libp2p host
|
|
||||||
lhost, err := provideLibp2pHost(n.Config, prvKey, pexDiscoveryUpdateTime)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
n.Host = lhost
|
|
||||||
logrus.Info("Started up Libp2p host!")
|
|
||||||
|
|
||||||
// initialize ethereum client
|
err = db.Run(context.TODO())
|
||||||
ethClient, err := provideEthereumClient(n.Config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
return err
|
||||||
}
|
}
|
||||||
n.Ethereum = ethClient
|
|
||||||
logrus.Info("Started up Ethereum client!")
|
|
||||||
|
|
||||||
// initialize blockchain rpc clients
|
// Run pubsub router
|
||||||
err = n.setupRPCClients()
|
pubSubRouter.Run()
|
||||||
|
|
||||||
|
// Subscribe on new requests event channel from Ethereum
|
||||||
|
err = subscribeOnEthContractsAsync(context.TODO(), ethClient, mp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
return err
|
||||||
}
|
|
||||||
logrus.Info("RPC clients has successfully configured!")
|
|
||||||
|
|
||||||
// initialize pubsub subsystem
|
|
||||||
psb := providePubsubRouter(lhost, n.Config)
|
|
||||||
n.PubSubRouter = psb
|
|
||||||
logrus.Info("PubSub subsystem has initialized!")
|
|
||||||
|
|
||||||
// initialize peer discovery
|
|
||||||
peerDiscovery, err := providePeerDiscovery(n.Config, lhost, pexDiscoveryUpdateTime)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
n.PeerDiscovery = peerDiscovery
|
|
||||||
logrus.Info("Peer discovery subsystem has initialized!")
|
|
||||||
|
|
||||||
// get private key of libp2p host
|
|
||||||
rawPrivKey, err := prvKey.Raw()
|
|
||||||
if err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize random beacon network subsystem
|
// Run blockchain sync manager
|
||||||
randomBeaconNetwork, err := provideBeacon(psb.Pubsub)
|
syncManager.Run()
|
||||||
if err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
n.Beacon = randomBeaconNetwork
|
|
||||||
logrus.Info("Random beacon subsystem has initialized!")
|
|
||||||
|
|
||||||
// initialize mining subsystem
|
// Run dispute manager
|
||||||
miner := provideMiner(n.Host.ID(), *n.Ethereum.GetEthAddress(), n.Beacon, n.Ethereum, rawPrivKey)
|
disputeManager.Run(context.TODO())
|
||||||
n.Miner = miner
|
|
||||||
logrus.Info("Mining subsystem has initialized!")
|
|
||||||
|
|
||||||
// initialize event log cache subsystem
|
|
||||||
eventCache := provideEventCache(config)
|
|
||||||
n.EventCache = eventCache
|
|
||||||
logrus.Info("Event cache subsystem has initialized!")
|
|
||||||
|
|
||||||
// initialize consensus subsystem
|
|
||||||
cManager := provideConsensusManager(psb, miner, ethClient, rawPrivKey, n.Config.ConsensusMinApprovals, eventCache)
|
|
||||||
n.ConsensusManager = cManager
|
|
||||||
logrus.Info("Consensus subsystem has initialized!")
|
|
||||||
|
|
||||||
// initialize dispute subsystem
|
|
||||||
disputeManager, err := provideDisputeManager(context.TODO(), ethClient, cManager, config)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
n.DisputeManager = disputeManager
|
|
||||||
logrus.Info("Dispute subsystem has initialized!")
|
|
||||||
|
|
||||||
// initialize internal eth wallet
|
|
||||||
wallet, err := provideWallet(n.Host.ID(), rawPrivKey)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
n.Wallet = wallet
|
|
||||||
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Node) Run(ctx context.Context) error {
|
|
||||||
n.runLibp2pAsync(ctx)
|
|
||||||
n.subscribeOnEthContractsAsync(ctx)
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil
|
return nil
|
||||||
}
|
},
|
||||||
}
|
OnStop: func(ctx context.Context) error {
|
||||||
|
// TODO
|
||||||
// return nil
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) runLibp2pAsync(ctx context.Context) error {
|
func runLibp2pAsync(ctx context.Context, h host.Host, cfg *config.Config, disco discovery.Discovery) error {
|
||||||
logrus.Info(fmt.Sprintf("[*] Your Multiaddress Is: /ip4/%s/tcp/%d/p2p/%s", n.Config.ListenAddr, n.Config.ListenPort, n.Host.ID().Pretty()))
|
|
||||||
|
|
||||||
logrus.Info("Announcing ourselves...")
|
logrus.Info("Announcing ourselves...")
|
||||||
_, err := n.PeerDiscovery.Advertise(context.TODO(), n.Config.Rendezvous)
|
_, err := disco.Advertise(context.TODO(), cfg.Rendezvous)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to announce this node to the network: %v", err)
|
return xerrors.Errorf("failed to announce this node to the network: %v", err)
|
||||||
}
|
}
|
||||||
@ -182,7 +99,7 @@ func (n *Node) runLibp2pAsync(ctx context.Context) error {
|
|||||||
|
|
||||||
// Discover unbounded count of peers
|
// Discover unbounded count of peers
|
||||||
logrus.Info("Searching for other peers...")
|
logrus.Info("Searching for other peers...")
|
||||||
peerChan, err := n.PeerDiscovery.FindPeers(context.TODO(), n.Config.Rendezvous)
|
peerChan, err := disco.FindPeers(context.TODO(), cfg.Rendezvous)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to find new peers: %v", err)
|
return xerrors.Errorf("failed to find new peers: %v", err)
|
||||||
}
|
}
|
||||||
@ -197,15 +114,18 @@ func (n *Node) runLibp2pAsync(ctx context.Context) error {
|
|||||||
if len(newPeer.Addrs) == 0 {
|
if len(newPeer.Addrs) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if newPeer.ID.String() == n.Host.ID().String() {
|
if newPeer.ID.String() == h.ID().String() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
logrus.Infof("Found peer: %s", newPeer)
|
logrus.WithField("peer", newPeer.ID).Info("Discovered new peer, connecting...")
|
||||||
// Connect to the peer
|
// Connect to the peer
|
||||||
if err := n.Host.Connect(ctx, newPeer); err != nil {
|
if err := h.Connect(ctx, newPeer); err != nil {
|
||||||
logrus.Warn("Connection failed: ", err)
|
logrus.WithFields(logrus.Fields{
|
||||||
|
"peer": newPeer.ID,
|
||||||
|
"err": err.Error(),
|
||||||
|
}).Warn("Connection with newly discovered peer has been failed")
|
||||||
}
|
}
|
||||||
logrus.Info("Connected to newly discovered peer: ", newPeer)
|
logrus.WithField("peer", newPeer.ID).Info("Connected to newly discovered peer")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -213,10 +133,10 @@ func (n *Node) runLibp2pAsync(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) subscribeOnEthContractsAsync(ctx context.Context) {
|
func subscribeOnEthContractsAsync(ctx context.Context, ethClient *ethclient.EthereumClient, mp *pool.Mempool) error {
|
||||||
eventChan, subscription, err := n.Ethereum.SubscribeOnOracleEvents(ctx)
|
eventChan, subscription, err := ethClient.SubscribeOnOracleEvents(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal("Couldn't subscribe on ethereum contracts, exiting... ", err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -225,222 +145,78 @@ func (n *Node) subscribeOnEthContractsAsync(ctx context.Context) {
|
|||||||
select {
|
select {
|
||||||
case event := <-eventChan:
|
case event := <-eventChan:
|
||||||
{
|
{
|
||||||
err := n.EventCache.Store("request_"+event.ReqID.String(), event)
|
rpcMethod := rpc.GetRPCMethod(event.OriginChain, event.RequestType)
|
||||||
if err != nil {
|
if rpcMethod == nil {
|
||||||
logrus.Errorf("Failed to store new request event to event log cache: %v", err)
|
logrus.Errorf("Invalid RPC method name/type %d/%s for oracle request %s", event.OriginChain, event.RequestType, event.ReqID.String())
|
||||||
}
|
|
||||||
|
|
||||||
logrus.Info("Let's wait a little so that all nodes have time to receive the request and cache it")
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
|
|
||||||
task, err := n.Miner.MineTask(context.TODO(), event)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("Failed to mine task: %v", err)
|
|
||||||
}
|
|
||||||
if task == nil {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
logrus.Infof("Proposed new Dione task with ID: %s", event.ReqID.String())
|
res, err := rpcMethod(event.RequestParams)
|
||||||
err = n.ConsensusManager.Propose(*task)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Failed to propose task: %w", err)
|
logrus.Errorf("Failed to invoke RPC method for oracle request %s: %s", event.ReqID.String(), err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
task := &types.DioneTask{
|
||||||
|
OriginChain: event.OriginChain,
|
||||||
|
RequestType: event.RequestType,
|
||||||
|
RequestParams: event.RequestParams,
|
||||||
|
Payload: res,
|
||||||
|
RequestID: event.ReqID.String(),
|
||||||
|
}
|
||||||
|
data, err := cbor.Marshal(task)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("Failed to marshal RPC response for oracle request %s: %s", event.ReqID.String(), err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tx := types2.CreateTransaction(data)
|
||||||
|
err = mp.StoreTx(tx)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("Failed to store tx in mempool: %s", err.Error())
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
break EventLoop
|
break EventLoop
|
||||||
case <-subscription.Err():
|
case err := <-subscription.Err():
|
||||||
logrus.Fatal("Error with ethereum subscription, exiting... ", err)
|
logrus.Fatalf("Error has occurred in subscription to Ethereum event channel: %s", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
|
||||||
|
|
||||||
func provideEventCache(config *config.Config) cache.EventCache {
|
|
||||||
var backend cache.EventCache
|
|
||||||
switch config.CacheType {
|
|
||||||
case "in-memory":
|
|
||||||
backend = cache.NewEventLogCache()
|
|
||||||
case "redis":
|
|
||||||
backend = cache.NewEventRedisCache(config)
|
|
||||||
default:
|
|
||||||
backend = cache.NewEventLogCache()
|
|
||||||
}
|
|
||||||
return backend
|
|
||||||
}
|
|
||||||
|
|
||||||
func provideDisputeManager(ctx context.Context, ethClient *ethclient.EthereumClient, pcm *consensus.PBFTConsensusManager, cfg *config.Config) (*consensus.DisputeManager, error) {
|
|
||||||
return consensus.NewDisputeManager(ctx, ethClient, pcm, cfg.Ethereum.DisputeVoteWindow)
|
|
||||||
}
|
|
||||||
|
|
||||||
func provideMiner(peerID peer.ID, ethAddress common.Address, beacon beacon.BeaconNetworks, ethClient *ethclient.EthereumClient, privateKey []byte) *consensus.Miner {
|
|
||||||
return consensus.NewMiner(peerID, ethAddress, beacon, ethClient, privateKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func provideBeacon(ps *pubsub.PubSub) (beacon.BeaconNetworks, error) {
|
|
||||||
networks := beacon.BeaconNetworks{}
|
|
||||||
bc, err := drand.NewDrandBeacon(config.ChainGenesis, config.TaskEpochInterval, ps)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to setup drand beacon: %w", err)
|
|
||||||
}
|
|
||||||
networks = append(networks, beacon.BeaconNetwork{Start: types.DrandRound(config.ChainGenesis), Beacon: bc})
|
|
||||||
// NOTE: currently we use only one network
|
|
||||||
return networks, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: do we really need this?
|
|
||||||
func provideWallet(peerID peer.ID, privKey []byte) (*wallet.LocalWallet, error) {
|
|
||||||
// TODO make persistent keystore
|
|
||||||
kstore := wallet.NewMemKeyStore()
|
|
||||||
keyInfo := types.KeyInfo{
|
|
||||||
Type: types.KTEd25519,
|
|
||||||
PrivateKey: privKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
kstore.Put(wallet.KNamePrefix+peerID.String(), keyInfo)
|
|
||||||
w, err := wallet.NewWallet(kstore)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to setup wallet: %w", err)
|
|
||||||
}
|
|
||||||
return w, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func provideEthereumClient(config *config.Config) (*ethclient.EthereumClient, error) {
|
|
||||||
ethereum := ethclient.NewEthereumClient()
|
|
||||||
err := ethereum.Initialize(&config.Ethereum)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to initialize ethereum client: %v", err)
|
|
||||||
}
|
|
||||||
return ethereum, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *Node) setupRPCClients() error {
|
|
||||||
fc := filecoin.NewLotusClient()
|
|
||||||
rpc.RegisterRPC(rtypes.RPCTypeFilecoin, map[string]func(string) ([]byte, error){
|
|
||||||
"getTransaction": fc.GetTransaction,
|
|
||||||
"getBlock": fc.GetBlock,
|
|
||||||
})
|
|
||||||
|
|
||||||
sl := solana2.NewSolanaClient()
|
|
||||||
rpc.RegisterRPC(rtypes.RPCTypeSolana, map[string]func(string) ([]byte, error){
|
|
||||||
"getTransaction": sl.GetTransaction,
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func providePubsubRouter(lhost host.Host, config *config.Config) *pubsub2.PubSubRouter {
|
|
||||||
return pubsub2.NewPubSubRouter(lhost, config.PubSub.ServiceTopicName, config.IsBootstrap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func provideConsensusManager(psb *pubsub2.PubSubRouter, miner *consensus.Miner, ethClient *ethclient.EthereumClient, privateKey []byte, minApprovals int, evc cache.EventCache) *consensus.PBFTConsensusManager {
|
|
||||||
return consensus.NewPBFTConsensusManager(psb, minApprovals, privateKey, ethClient, miner, evc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func provideLibp2pHost(config *config.Config, privateKey crypto.PrivKey, pexDiscoveryUpdateTime time.Duration) (host.Host, error) {
|
|
||||||
listenMultiAddr, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", config.ListenAddr, config.ListenPort))
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to parse multiaddress: %v", err)
|
|
||||||
}
|
|
||||||
host, err := libp2p.New(
|
|
||||||
context.TODO(),
|
|
||||||
libp2p.ListenAddrs(listenMultiAddr),
|
|
||||||
libp2p.Identity(privateKey),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to setup libp2p host: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return host, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func providePeerDiscovery(config *config.Config, h host.Host, pexDiscoveryUpdateTime time.Duration) (discovery.Discovery, error) {
|
|
||||||
var bootstrapMaddrs []multiaddr.Multiaddr
|
|
||||||
for _, a := range config.BootstrapNodes {
|
|
||||||
maddr, err := multiaddr.NewMultiaddr(a)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("invalid multiaddress of bootstrap node: %v", err)
|
|
||||||
}
|
|
||||||
bootstrapMaddrs = append(bootstrapMaddrs, maddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.IsBootstrap {
|
|
||||||
bootstrapMaddrs = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
pexDiscovery, err := pex.NewPEXDiscovery(h, bootstrapMaddrs, pexDiscoveryUpdateTime)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to setup pex pexDiscovery: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pexDiscovery, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Start() {
|
func Start() {
|
||||||
configPath := flag.String("config", "", "Path to config")
|
fx.New(
|
||||||
verbose := flag.Bool("verbose", false, "Verbose logging")
|
fx.Provide(
|
||||||
flag.Parse()
|
provideEventBus,
|
||||||
|
provideAppFlags,
|
||||||
if *configPath == "" {
|
provideConfig,
|
||||||
logrus.Fatal("no config path provided")
|
providePrivateKey,
|
||||||
}
|
provideLibp2pHost,
|
||||||
cfg, err := config.NewConfig(*configPath)
|
provideEthereumClient,
|
||||||
if err != nil {
|
providePubsubRouter,
|
||||||
logrus.Fatalf("failed to load config: %v", err)
|
provideBootstrapAddrs,
|
||||||
}
|
providePeerDiscovery,
|
||||||
|
provideDrandBeacon,
|
||||||
var privateKey crypto.PrivKey
|
provideMempool,
|
||||||
|
blockchain.NewMiner,
|
||||||
if cfg.IsBootstrap {
|
provideBlockChain,
|
||||||
if _, err := os.Stat(".bootstrap_privkey"); os.IsNotExist(err) {
|
provideBlockPool,
|
||||||
privateKey, err = generatePrivateKey()
|
provideSyncManager,
|
||||||
if err != nil {
|
provideNetworkRPCHost,
|
||||||
logrus.Fatal(err)
|
provideNetworkService,
|
||||||
}
|
provideDirectRPCClient,
|
||||||
|
provideConsensusManager,
|
||||||
f, _ := os.Create(".bootstrap_privkey")
|
provideDisputeManager,
|
||||||
r, _ := privateKey.Raw()
|
),
|
||||||
f.Write(r)
|
fx.Invoke(
|
||||||
} else {
|
configureLogger,
|
||||||
pkey, _ := ioutil.ReadFile(".bootstrap_privkey")
|
configureDirectRPC,
|
||||||
privateKey, _ = crypto.UnmarshalEd25519PrivateKey(pkey)
|
configureForeignBlockchainRPC,
|
||||||
}
|
initializeBlockchain,
|
||||||
} else {
|
configureMiner,
|
||||||
privateKey, err = generatePrivateKey()
|
runNode,
|
||||||
if err != nil {
|
),
|
||||||
logrus.Fatal(err)
|
fx.NopLogger,
|
||||||
}
|
).Run()
|
||||||
}
|
|
||||||
|
|
||||||
node, err := NewNode(cfg, privateKey, DefaultPEXUpdateTime)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// log
|
|
||||||
if *verbose {
|
|
||||||
logrus.SetLevel(logrus.DebugLevel)
|
|
||||||
} else {
|
|
||||||
logrus.SetLevel(logrus.DebugLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
//log.SetDebugLogging()
|
|
||||||
|
|
||||||
//ctx, ctxCancel := context.WithCancel(context.Background())
|
|
||||||
//node.GlobalCtx = ctx
|
|
||||||
//node.GlobalCtxCancel = ctxCancel
|
|
||||||
|
|
||||||
err = node.Run(context.TODO())
|
|
||||||
if err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func generatePrivateKey() (crypto.PrivKey, error) {
|
|
||||||
r := rand.Reader
|
|
||||||
// Creates a new RSA key pair for this host.
|
|
||||||
prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return prvKey, nil
|
|
||||||
}
|
}
|
||||||
|
413
node/node_dep_providers.go
Normal file
413
node/node_dep_providers.go
Normal file
@ -0,0 +1,413 @@
|
|||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
types2 "github.com/Secured-Finance/dione/blockchain/types"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/rpc"
|
||||||
|
"github.com/Secured-Finance/dione/rpc/filecoin"
|
||||||
|
solana2 "github.com/Secured-Finance/dione/rpc/solana"
|
||||||
|
rtypes "github.com/Secured-Finance/dione/rpc/types"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/asaskevich/EventBus"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain"
|
||||||
|
|
||||||
|
drand2 "github.com/Secured-Finance/dione/beacon/drand"
|
||||||
|
|
||||||
|
"github.com/libp2p/go-libp2p-core/protocol"
|
||||||
|
|
||||||
|
gorpc "github.com/libp2p/go-libp2p-gorpc"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain/sync"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/blockchain/pool"
|
||||||
|
|
||||||
|
"github.com/Secured-Finance/dione/cache"
|
||||||
|
"github.com/Secured-Finance/dione/config"
|
||||||
|
"github.com/Secured-Finance/dione/consensus"
|
||||||
|
"github.com/Secured-Finance/dione/ethclient"
|
||||||
|
"github.com/Secured-Finance/dione/pubsub"
|
||||||
|
"github.com/Secured-Finance/dione/types"
|
||||||
|
"github.com/Secured-Finance/dione/wallet"
|
||||||
|
pex "github.com/Secured-Finance/go-libp2p-pex"
|
||||||
|
"github.com/libp2p/go-libp2p"
|
||||||
|
"github.com/libp2p/go-libp2p-core/crypto"
|
||||||
|
"github.com/libp2p/go-libp2p-core/discovery"
|
||||||
|
"github.com/libp2p/go-libp2p-core/host"
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
"github.com/multiformats/go-multiaddr"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DioneProtocolID = protocol.ID("/dione/1.0")
|
||||||
|
)
|
||||||
|
|
||||||
|
func provideCache(config *config.Config) cache.Cache {
|
||||||
|
var backend cache.Cache
|
||||||
|
switch config.CacheType {
|
||||||
|
case "in-memory":
|
||||||
|
backend = cache.NewInMemoryCache()
|
||||||
|
case "redis":
|
||||||
|
backend = cache.NewRedisCache(config)
|
||||||
|
default:
|
||||||
|
backend = cache.NewInMemoryCache()
|
||||||
|
}
|
||||||
|
return backend
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideDisputeManager(ethClient *ethclient.EthereumClient, pcm *consensus.PBFTConsensusManager, cfg *config.Config, bc *blockchain.BlockChain) *consensus.DisputeManager {
|
||||||
|
dm, err := consensus.NewDisputeManager(context.TODO(), ethClient, pcm, cfg.Ethereum.DisputeVoteWindow, bc)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Info("Dispute subsystem has been initialized!")
|
||||||
|
|
||||||
|
return dm
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideDrandBeacon(ps *pubsub.PubSubRouter, bus EventBus.Bus) *drand2.DrandBeacon {
|
||||||
|
db, err := drand2.NewDrandBeacon(ps.Pubsub, bus)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatalf("Failed to setup drand beacon: %s", err)
|
||||||
|
}
|
||||||
|
logrus.Info("DRAND beacon subsystem has been initialized!")
|
||||||
|
return db
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: do we really need this?
|
||||||
|
func provideWallet(peerID peer.ID, privKey []byte) (*wallet.LocalWallet, error) {
|
||||||
|
// TODO make persistent keystore
|
||||||
|
kstore := wallet.NewMemKeyStore()
|
||||||
|
keyInfo := types.KeyInfo{
|
||||||
|
Type: types.KTEd25519,
|
||||||
|
PrivateKey: privKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
kstore.Put(wallet.KNamePrefix+peerID.String(), keyInfo)
|
||||||
|
w, err := wallet.NewWallet(kstore)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to setup wallet: %w", err)
|
||||||
|
}
|
||||||
|
return w, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideEthereumClient(config *config.Config) *ethclient.EthereumClient {
|
||||||
|
ethereum := ethclient.NewEthereumClient()
|
||||||
|
err := ethereum.Initialize(&config.Ethereum)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithField("ethAddress", ethereum.GetEthAddress().Hex()).Info("Ethereum client has been initialized!")
|
||||||
|
|
||||||
|
return ethereum
|
||||||
|
}
|
||||||
|
|
||||||
|
func providePubsubRouter(lhost host.Host, config *config.Config) *pubsub.PubSubRouter {
|
||||||
|
psb := pubsub.NewPubSubRouter(lhost, config.PubSub.ServiceTopicName, config.IsBootstrap)
|
||||||
|
logrus.Info("PubSub subsystem has been initialized!")
|
||||||
|
return psb
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideConsensusManager(
|
||||||
|
h host.Host,
|
||||||
|
bus EventBus.Bus,
|
||||||
|
psb *pubsub.PubSubRouter,
|
||||||
|
miner *blockchain.Miner,
|
||||||
|
bc *blockchain.BlockChain,
|
||||||
|
ethClient *ethclient.EthereumClient,
|
||||||
|
privateKey crypto.PrivKey,
|
||||||
|
bp *consensus.ConsensusStatePool,
|
||||||
|
db *drand2.DrandBeacon,
|
||||||
|
mp *pool.Mempool,
|
||||||
|
) *consensus.PBFTConsensusManager {
|
||||||
|
c := consensus.NewPBFTConsensusManager(
|
||||||
|
bus,
|
||||||
|
psb,
|
||||||
|
privateKey,
|
||||||
|
ethClient,
|
||||||
|
miner,
|
||||||
|
bc,
|
||||||
|
bp,
|
||||||
|
db,
|
||||||
|
mp,
|
||||||
|
h.ID(),
|
||||||
|
)
|
||||||
|
logrus.Info("Consensus subsystem has been initialized!")
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideLibp2pHost(config *config.Config, privateKey crypto.PrivKey) host.Host {
|
||||||
|
listenMultiAddr, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", config.ListenAddr, config.ListenPort))
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatalf("Failed to parse multiaddress: %s", err.Error())
|
||||||
|
}
|
||||||
|
libp2pHost, err := libp2p.New(
|
||||||
|
context.TODO(),
|
||||||
|
libp2p.ListenAddrs(listenMultiAddr),
|
||||||
|
libp2p.Identity(privateKey),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.WithField(
|
||||||
|
"multiaddress",
|
||||||
|
fmt.Sprintf("/ip4/%s/tcp/%d/p2p/%s",
|
||||||
|
config.ListenAddr,
|
||||||
|
config.ListenPort,
|
||||||
|
libp2pHost.ID().Pretty(),
|
||||||
|
)).Info("Libp2p host has been initialized!")
|
||||||
|
|
||||||
|
return libp2pHost
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideNetworkRPCHost(h host.Host) *gorpc.Server {
|
||||||
|
return gorpc.NewServer(h, DioneProtocolID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideBootstrapAddrs(c *config.Config) []multiaddr.Multiaddr {
|
||||||
|
if c.IsBootstrap {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var bootstrapMaddrs []multiaddr.Multiaddr
|
||||||
|
for _, a := range c.BootstrapNodes {
|
||||||
|
maddr, err := multiaddr.NewMultiaddr(a)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatalf("Invalid multiaddress of bootstrap node: %v", err)
|
||||||
|
}
|
||||||
|
bootstrapMaddrs = append(bootstrapMaddrs, maddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bootstrapMaddrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func providePeerDiscovery(baddrs []multiaddr.Multiaddr, h host.Host) discovery.Discovery {
|
||||||
|
pexDiscovery, err := pex.NewPEXDiscovery(h, baddrs, DefaultPEXUpdateTime)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatalf("Failed to setup libp2p PEX discovery: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Info("Peer discovery subsystem has been initialized!")
|
||||||
|
|
||||||
|
return pexDiscovery
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideBlockChain(config *config.Config, bus EventBus.Bus, miner *blockchain.Miner, db *drand2.DrandBeacon) *blockchain.BlockChain {
|
||||||
|
bc, err := blockchain.NewBlockChain(config.Blockchain.DatabasePath, bus, miner, db)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatalf("Failed to initialize blockchain storage: %s", err.Error())
|
||||||
|
}
|
||||||
|
logrus.Info("Blockchain storage has been successfully initialized!")
|
||||||
|
|
||||||
|
return bc
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideMempool(bus EventBus.Bus) *pool.Mempool {
|
||||||
|
mp, err := pool.NewMempool(bus)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatalf("Failed to initialize mempool: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Info("Mempool has been successfully initialized!")
|
||||||
|
|
||||||
|
return mp
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideSyncManager(
|
||||||
|
bus EventBus.Bus,
|
||||||
|
bp *blockchain.BlockChain,
|
||||||
|
mp *pool.Mempool,
|
||||||
|
c *gorpc.Client,
|
||||||
|
bootstrapAddresses []multiaddr.Multiaddr,
|
||||||
|
psb *pubsub.PubSubRouter,
|
||||||
|
) sync.SyncManager {
|
||||||
|
bootstrapPeerID := peer.ID("")
|
||||||
|
|
||||||
|
if bootstrapAddresses != nil {
|
||||||
|
addr, err := peer.AddrInfoFromP2pAddr(bootstrapAddresses[0]) // FIXME
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
bootstrapPeerID = addr.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
sm := sync.NewSyncManager(bus, bp, mp, c, bootstrapPeerID, psb)
|
||||||
|
logrus.Info("Blockchain sync subsystem has been successfully initialized!")
|
||||||
|
|
||||||
|
return sm
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideDirectRPCClient(h host.Host) *gorpc.Client {
|
||||||
|
return gorpc.NewClient(h, DioneProtocolID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideNetworkService(bp *blockchain.BlockChain, mp *pool.Mempool) *NetworkService {
|
||||||
|
ns := NewNetworkService(bp, mp)
|
||||||
|
logrus.Info("Direct RPC has been successfully initialized!")
|
||||||
|
return ns
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideBlockPool(mp *pool.Mempool, bus EventBus.Bus, config *config.Config) *consensus.ConsensusStatePool {
|
||||||
|
bp, err := consensus.NewConsensusRoundPool(mp, bus, config.ConsensusMinApprovals)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatalf("Failed to initialize blockpool: %s", err.Error())
|
||||||
|
}
|
||||||
|
logrus.Info("Consensus state pool has been successfully initialized!")
|
||||||
|
return bp
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideEventBus() EventBus.Bus {
|
||||||
|
return EventBus.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideAppFlags() *AppFlags {
|
||||||
|
var flags AppFlags
|
||||||
|
|
||||||
|
flag.StringVar(&flags.ConfigPath, "config", "", "Path to config")
|
||||||
|
flag.BoolVar(&flags.Verbose, "verbose", false, "Verbose logging")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
return &flags
|
||||||
|
}
|
||||||
|
|
||||||
|
func provideConfig(flags *AppFlags) *config.Config {
|
||||||
|
if flags.ConfigPath == "" {
|
||||||
|
logrus.Fatal("no config path provided")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg, err := config.NewConfig(flags.ConfigPath)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatalf("failed to load config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func providePrivateKey(cfg *config.Config) crypto.PrivKey {
|
||||||
|
var privateKey crypto.PrivKey
|
||||||
|
|
||||||
|
if _, err := os.Stat(cfg.PrivateKeyPath); os.IsNotExist(err) {
|
||||||
|
privateKey, err = generatePrivateKey()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dirName := filepath.Dir(cfg.PrivateKeyPath)
|
||||||
|
if _, err := os.Stat(dirName); os.IsNotExist(err) {
|
||||||
|
err := os.MkdirAll(dirName, 0755)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatalf("Cannot create private key file: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Create(cfg.PrivateKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatalf("Cannot create private key file: %s, ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := privateKey.Raw()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = f.Write(r)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pkey, err := ioutil.ReadFile(cfg.PrivateKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
privateKey, err = crypto.UnmarshalEd25519PrivateKey(pkey)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return privateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func generatePrivateKey() (crypto.PrivKey, error) {
|
||||||
|
r := rand.Reader
|
||||||
|
// Creates a new RSA key pair for this host.
|
||||||
|
prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.Ed25519, 2048, r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return prvKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureDirectRPC(rpcServer *gorpc.Server, ns *NetworkService) {
|
||||||
|
err := rpcServer.Register(ns)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureLogger(flags *AppFlags) {
|
||||||
|
logrus.SetReportCaller(true)
|
||||||
|
logrus.SetFormatter(&logrus.TextFormatter{
|
||||||
|
FullTimestamp: true,
|
||||||
|
CallerPrettyfier: func(f *runtime.Frame) (string, string) {
|
||||||
|
filename := path.Base(f.File)
|
||||||
|
return "", fmt.Sprintf("%s:%d:", filename, f.Line)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if flags.Verbose {
|
||||||
|
logrus.SetLevel(logrus.DebugLevel)
|
||||||
|
} else {
|
||||||
|
logrus.SetLevel(logrus.InfoLevel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureForeignBlockchainRPC() {
|
||||||
|
fc := filecoin.NewLotusClient()
|
||||||
|
rpc.RegisterRPC(rtypes.RPCTypeFilecoin, map[string]func(string) ([]byte, error){
|
||||||
|
"getTransaction": fc.GetTransaction,
|
||||||
|
"getBlock": fc.GetBlock,
|
||||||
|
})
|
||||||
|
|
||||||
|
sl := solana2.NewSolanaClient()
|
||||||
|
rpc.RegisterRPC(rtypes.RPCTypeSolana, map[string]func(string) ([]byte, error){
|
||||||
|
"getTransaction": sl.GetTransaction,
|
||||||
|
})
|
||||||
|
|
||||||
|
logrus.Info("Foreign Blockchain RPC clients has been successfully configured!")
|
||||||
|
}
|
||||||
|
|
||||||
|
func configureMiner(m *blockchain.Miner, b *blockchain.BlockChain) {
|
||||||
|
m.SetBlockchainInstance(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initializeBlockchain(bc *blockchain.BlockChain) {
|
||||||
|
_, err := bc.GetLatestBlockHeight()
|
||||||
|
if err == blockchain.ErrLatestHeightNil {
|
||||||
|
gBlock := types2.GenesisBlock()
|
||||||
|
err = bc.StoreBlock(gBlock) // commit genesis block
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
logrus.Info("Committed genesis block")
|
||||||
|
}
|
||||||
|
}
|
12
node/wire/get_mempool_tx.go
Normal file
12
node/wire/get_mempool_tx.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package wire
|
||||||
|
|
||||||
|
import "github.com/Secured-Finance/dione/blockchain/types"
|
||||||
|
|
||||||
|
type GetMempoolTxsArg struct {
|
||||||
|
Items [][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetMempoolTxsReply struct {
|
||||||
|
Transactions []types.Transaction
|
||||||
|
NotFoundTxs [][]byte
|
||||||
|
}
|
13
node/wire/get_range_of_blocks.go
Normal file
13
node/wire/get_range_of_blocks.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package wire
|
||||||
|
|
||||||
|
import "github.com/Secured-Finance/dione/blockchain/types"
|
||||||
|
|
||||||
|
type GetRangeOfBlocksArg struct {
|
||||||
|
From uint64
|
||||||
|
To uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetRangeOfBlocksReply struct {
|
||||||
|
Blocks []types.Block
|
||||||
|
FailedBlockHeights []uint64 // list of block heights the node was unable to retrieve
|
||||||
|
}
|
17
node/wire/inv.go
Normal file
17
node/wire/inv.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package wire
|
||||||
|
|
||||||
|
type InvType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
InvalidInvType = iota
|
||||||
|
TxInvType
|
||||||
|
)
|
||||||
|
|
||||||
|
type InvMessage struct {
|
||||||
|
Inventory []InvItem
|
||||||
|
}
|
||||||
|
|
||||||
|
type InvItem struct {
|
||||||
|
Type InvType
|
||||||
|
Hash []byte
|
||||||
|
}
|
5
node/wire/last_block_height.go
Normal file
5
node/wire/last_block_height.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package wire
|
||||||
|
|
||||||
|
type LastBlockHeightReply struct {
|
||||||
|
Height uint64
|
||||||
|
}
|
@ -1,7 +0,0 @@
|
|||||||
package pubsub
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/Secured-Finance/dione/consensus/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Handler func(message *types.Message)
|
|
20
pubsub/message.go
Normal file
20
pubsub/message.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package pubsub
|
||||||
|
|
||||||
|
import "github.com/libp2p/go-libp2p-core/peer"
|
||||||
|
|
||||||
|
type PubSubMessageType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
UnknownMessageType = iota
|
||||||
|
PrePrepareMessageType
|
||||||
|
PrepareMessageType
|
||||||
|
CommitMessageType
|
||||||
|
NewTxMessageType
|
||||||
|
NewBlockMessageType
|
||||||
|
)
|
||||||
|
|
||||||
|
type PubSubMessage struct {
|
||||||
|
Type PubSubMessageType
|
||||||
|
From peer.ID `cbor:"-"`
|
||||||
|
Payload []byte
|
||||||
|
}
|
@ -2,14 +2,11 @@ package pubsub
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/fxamacker/cbor/v2"
|
"github.com/fxamacker/cbor/v2"
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/consensus/types"
|
"github.com/libp2p/go-libp2p-core/host"
|
||||||
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
host "github.com/libp2p/go-libp2p-core/host"
|
|
||||||
peer "github.com/libp2p/go-libp2p-core/peer"
|
|
||||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -20,11 +17,13 @@ type PubSubRouter struct {
|
|||||||
context context.Context
|
context context.Context
|
||||||
contextCancel context.CancelFunc
|
contextCancel context.CancelFunc
|
||||||
serviceSubscription *pubsub.Subscription
|
serviceSubscription *pubsub.Subscription
|
||||||
handlers map[types.MessageType][]Handler
|
handlers map[PubSubMessageType][]Handler
|
||||||
oracleTopicName string
|
oracleTopicName string
|
||||||
oracleTopic *pubsub.Topic
|
oracleTopic *pubsub.Topic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Handler func(message *PubSubMessage)
|
||||||
|
|
||||||
func NewPubSubRouter(h host.Host, oracleTopic string, isBootstrap bool) *PubSubRouter {
|
func NewPubSubRouter(h host.Host, oracleTopic string, isBootstrap bool) *PubSubRouter {
|
||||||
ctx, ctxCancel := context.WithCancel(context.Background())
|
ctx, ctxCancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
@ -32,26 +31,27 @@ func NewPubSubRouter(h host.Host, oracleTopic string, isBootstrap bool) *PubSubR
|
|||||||
node: h,
|
node: h,
|
||||||
context: ctx,
|
context: ctx,
|
||||||
contextCancel: ctxCancel,
|
contextCancel: ctxCancel,
|
||||||
handlers: make(map[types.MessageType][]Handler),
|
handlers: make(map[PubSubMessageType][]Handler),
|
||||||
|
oracleTopicName: oracleTopic,
|
||||||
}
|
}
|
||||||
|
|
||||||
var pbOptions []pubsub.Option
|
var pbOptions []pubsub.Option
|
||||||
|
|
||||||
if isBootstrap {
|
if isBootstrap {
|
||||||
// turn off the mesh in bootstrappers -- only do gossip and PX
|
// turn off the mesh in bootstrappers -- only do gossip and PX
|
||||||
pubsub.GossipSubD = 0
|
//pubsub.GossipSubD = 0
|
||||||
pubsub.GossipSubDscore = 0
|
//pubsub.GossipSubDscore = 0
|
||||||
pubsub.GossipSubDlo = 0
|
//pubsub.GossipSubDlo = 0
|
||||||
pubsub.GossipSubDhi = 0
|
//pubsub.GossipSubDhi = 0
|
||||||
pubsub.GossipSubDout = 0
|
//pubsub.GossipSubDout = 0
|
||||||
pubsub.GossipSubDlazy = 64
|
//pubsub.GossipSubDlazy = 64
|
||||||
pubsub.GossipSubGossipFactor = 0.25
|
//pubsub.GossipSubGossipFactor = 0.25
|
||||||
pubsub.GossipSubPruneBackoff = 5 * time.Minute
|
//pubsub.GossipSubPruneBackoff = 5 * time.Minute
|
||||||
// turn on PX
|
// turn on PX
|
||||||
pbOptions = append(pbOptions, pubsub.WithPeerExchange(true))
|
//pbOptions = append(pbOptions, pubsub.WithPeerExchange(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
pb, err := pubsub.NewGossipSub(
|
pb, err := pubsub.NewFloodSub(
|
||||||
context.TODO(),
|
context.TODO(),
|
||||||
psr.node,
|
psr.node,
|
||||||
pbOptions...,
|
pbOptions...,
|
||||||
@ -61,7 +61,6 @@ func NewPubSubRouter(h host.Host, oracleTopic string, isBootstrap bool) *PubSubR
|
|||||||
logrus.Fatalf("Error occurred when initializing PubSub subsystem: %v", err)
|
logrus.Fatalf("Error occurred when initializing PubSub subsystem: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
psr.oracleTopicName = oracleTopic
|
|
||||||
topic, err := pb.Join(oracleTopic)
|
topic, err := pb.Join(oracleTopic)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatalf("Error occurred when subscribing to service topic: %v", err)
|
logrus.Fatalf("Error occurred when subscribing to service topic: %v", err)
|
||||||
@ -72,6 +71,10 @@ func NewPubSubRouter(h host.Host, oracleTopic string, isBootstrap bool) *PubSubR
|
|||||||
psr.Pubsub = pb
|
psr.Pubsub = pb
|
||||||
psr.oracleTopic = topic
|
psr.oracleTopic = topic
|
||||||
|
|
||||||
|
return psr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (psr *PubSubRouter) Run() {
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@ -79,7 +82,7 @@ func NewPubSubRouter(h host.Host, oracleTopic string, isBootstrap bool) *PubSubR
|
|||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
msg, err := subscription.Next(psr.context)
|
msg, err := psr.serviceSubscription.Next(psr.context)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Warnf("Failed to receive pubsub message: %v", err)
|
logrus.Warnf("Failed to receive pubsub message: %v", err)
|
||||||
}
|
}
|
||||||
@ -88,8 +91,6 @@ func NewPubSubRouter(h host.Host, oracleTopic string, isBootstrap bool) *PubSubR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return psr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (psr *PubSubRouter) handleMessage(p *pubsub.Message) {
|
func (psr *PubSubRouter) handleMessage(p *pubsub.Message) {
|
||||||
@ -102,16 +103,16 @@ func (psr *PubSubRouter) handleMessage(p *pubsub.Message) {
|
|||||||
if senderPeerID == psr.node.ID() {
|
if senderPeerID == psr.node.ID() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var message types.Message
|
var message PubSubMessage
|
||||||
err = cbor.Unmarshal(p.Data, &message)
|
err = cbor.Unmarshal(p.Data, &message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Warn("Unable to decode message data! " + err.Error())
|
logrus.Warn("Unable to decode pubsub message data! " + err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
message.From = senderPeerID
|
message.From = senderPeerID
|
||||||
handlers, ok := psr.handlers[message.Type]
|
handlers, ok := psr.handlers[message.Type]
|
||||||
if !ok {
|
if !ok {
|
||||||
logrus.Warn("Dropping message " + string(message.Type) + " because we don't have any handlers!")
|
logrus.Warnf("Dropping pubsub message with type %d because we don't have any handlers!", message.Type)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, v := range handlers {
|
for _, v := range handlers {
|
||||||
@ -119,7 +120,7 @@ func (psr *PubSubRouter) handleMessage(p *pubsub.Message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (psr *PubSubRouter) Hook(messageType types.MessageType, handler Handler) {
|
func (psr *PubSubRouter) Hook(messageType PubSubMessageType, handler Handler) {
|
||||||
_, ok := psr.handlers[messageType]
|
_, ok := psr.handlers[messageType]
|
||||||
if !ok {
|
if !ok {
|
||||||
psr.handlers[messageType] = []Handler{}
|
psr.handlers[messageType] = []Handler{}
|
||||||
@ -127,7 +128,7 @@ func (psr *PubSubRouter) Hook(messageType types.MessageType, handler Handler) {
|
|||||||
psr.handlers[messageType] = append(psr.handlers[messageType], handler)
|
psr.handlers[messageType] = append(psr.handlers[messageType], handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (psr *PubSubRouter) BroadcastToServiceTopic(msg *types.Message) error {
|
func (psr *PubSubRouter) BroadcastToServiceTopic(msg *PubSubMessage) error {
|
||||||
data, err := cbor.Marshal(msg)
|
data, err := cbor.Marshal(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -114,6 +114,6 @@ func (c *LotusClient) HandleRequest(method string, params []interface{}) ([]byte
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
bodyBytes := resp.Body()
|
bodyBytes := resp.Body()
|
||||||
logrus.Debugf("Filecoin RPC reply: %v", string(bodyBytes))
|
logrus.Tracef("Filecoin RPC reply: %v", string(bodyBytes))
|
||||||
return bodyBytes, nil
|
return bodyBytes, nil
|
||||||
}
|
}
|
||||||
|
@ -1,96 +0,0 @@
|
|||||||
package store
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/ethclient"
|
|
||||||
"github.com/Secured-Finance/dione/lib"
|
|
||||||
"github.com/Secured-Finance/dione/types"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
validation "github.com/go-ozzo/ozzo-validation"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DioneStakeInfo struct {
|
|
||||||
ID int
|
|
||||||
MinerStake *types.BigInt
|
|
||||||
TotalStake *types.BigInt
|
|
||||||
MinerAddress string
|
|
||||||
MinerEthWallet string
|
|
||||||
Timestamp time.Time
|
|
||||||
Ethereum *ethclient.EthereumClient
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDioneStakeInfo(minerStake, totalStake *types.BigInt, minerWallet, minerEthWallet string, ethereumClient *ethclient.EthereumClient) *DioneStakeInfo {
|
|
||||||
return &DioneStakeInfo{
|
|
||||||
MinerStake: minerStake,
|
|
||||||
TotalStake: totalStake,
|
|
||||||
MinerAddress: minerWallet,
|
|
||||||
MinerEthWallet: minerEthWallet,
|
|
||||||
Ethereum: ethereumClient,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DioneStakeInfo) UpdateMinerStake(minerEthAddress common.Address) error {
|
|
||||||
minerStake, err := d.Ethereum.GetMinerStake(minerEthAddress)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d.MinerStake = minerStake
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DioneStakeInfo) UpdateTotalStake() error {
|
|
||||||
totalStake, err := d.Ethereum.GetTotalStake()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d.TotalStake = totalStake
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put miner's staking information into the database
|
|
||||||
func (s *Store) CreateDioneStakeInfo(stakeStore *DioneStakeInfo) error {
|
|
||||||
|
|
||||||
if err := stakeStore.Validate(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
now := lib.Clock.Now()
|
|
||||||
|
|
||||||
return s.db.QueryRow(
|
|
||||||
"INSERT INTO staking (miner_stake, total_stake, miner_address, miner_eth_wallet, timestamp) VALUES ($1, $2, $3, $4, $5) RETURNING id",
|
|
||||||
stakeStore.MinerStake,
|
|
||||||
stakeStore.TotalStake,
|
|
||||||
stakeStore.MinerAddress,
|
|
||||||
stakeStore.MinerEthWallet,
|
|
||||||
now,
|
|
||||||
).Scan(&stakeStore.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Store) GetLastStakeInfo(wallet, ethWallet string) (*DioneStakeInfo, error) {
|
|
||||||
var stake *DioneStakeInfo
|
|
||||||
if err := s.db.Select(&stake,
|
|
||||||
`SELECT miner_stake, total_stake, miner_address, miner_eth_wallet, timestamp FROM staking ORDER BY TIMESTAMP DESC LIMIT 1 WHERE miner_address=$1, miner_eth_wallet=$2`,
|
|
||||||
wallet,
|
|
||||||
ethWallet,
|
|
||||||
); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return stake, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Before puting the data into the database validating all required fields
|
|
||||||
func (s *DioneStakeInfo) Validate() error {
|
|
||||||
return validation.ValidateStruct(
|
|
||||||
s,
|
|
||||||
validation.Field(&s.MinerStake, validation.Required, validation.By(types.ValidateBigInt(s.MinerStake.Int))),
|
|
||||||
validation.Field(&s.TotalStake, validation.Required, validation.By(types.ValidateBigInt(s.TotalStake.Int))),
|
|
||||||
validation.Field(&s.MinerAddress, validation.Required),
|
|
||||||
validation.Field(&s.MinerEthWallet, validation.Required),
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,46 +1,44 @@
|
|||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
//import (
|
||||||
"github.com/Secured-Finance/dione/node"
|
// "github.com/Secured-Finance/dione/node"
|
||||||
"github.com/jmoiron/sqlx"
|
// "github.com/jmoiron/sqlx"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
// _ "github.com/mattn/go-sqlite3"
|
||||||
)
|
//)
|
||||||
|
//
|
||||||
type Store struct {
|
//type Store struct {
|
||||||
db *sqlx.DB
|
// db *sqlx.DB
|
||||||
node *node.Node
|
// node *node.Node
|
||||||
genesisTs uint64
|
// genesisTs uint64
|
||||||
StakeStorage DioneStakeInfo
|
//}
|
||||||
// genesisTask *types.DioneTask
|
//
|
||||||
}
|
//func NewStore(node *node.Node, genesisTs uint64) (*Store, error) {
|
||||||
|
// db, err := newDB(node.Config.Store.DatabaseURL)
|
||||||
func NewStore(node *node.Node, genesisTs uint64) (*Store, error) {
|
// if err != nil {
|
||||||
db, err := newDB(node.Config.Store.DatabaseURL)
|
// return nil, err
|
||||||
if err != nil {
|
// }
|
||||||
return nil, err
|
//
|
||||||
}
|
// defer db.Close()
|
||||||
|
//
|
||||||
defer db.Close()
|
// return &Store{
|
||||||
|
// db: db,
|
||||||
return &Store{
|
// node: node,
|
||||||
db: db,
|
// genesisTs: genesisTs,
|
||||||
node: node,
|
// }, nil
|
||||||
genesisTs: genesisTs,
|
//}
|
||||||
}, nil
|
//
|
||||||
}
|
//func newDB(databaseURL string) (*sqlx.DB, error) {
|
||||||
|
// db, err := sqlx.Connect("sqlite3", databaseURL)
|
||||||
func newDB(databaseURL string) (*sqlx.DB, error) {
|
// if err != nil {
|
||||||
db, err := sqlx.Connect("sqlite3", databaseURL)
|
// return nil, err
|
||||||
if err != nil {
|
// }
|
||||||
return nil, err
|
//
|
||||||
}
|
// if err := db.Ping(); err != nil {
|
||||||
|
// return nil, err
|
||||||
if err := db.Ping(); err != nil {
|
// }
|
||||||
return nil, err
|
//
|
||||||
}
|
// return db, nil
|
||||||
|
//}
|
||||||
return db, nil
|
//
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Discuss with ChronosX88 about using custom database to decrease I/O bound
|
// TODO: Discuss with ChronosX88 about using custom database to decrease I/O bound
|
||||||
// specify the migrations for stake storage;
|
// specify the migrations for stake storage;
|
||||||
|
@ -3,13 +3,13 @@ package types
|
|||||||
type BeaconEntry struct {
|
type BeaconEntry struct {
|
||||||
Round uint64
|
Round uint64
|
||||||
Data []byte
|
Data []byte
|
||||||
|
Metadata map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Randomness []byte
|
func NewBeaconEntry(round uint64, data []byte, metadata map[string]interface{}) BeaconEntry {
|
||||||
|
|
||||||
func NewBeaconEntry(round uint64, data []byte) BeaconEntry {
|
|
||||||
return BeaconEntry{
|
return BeaconEntry{
|
||||||
Round: round,
|
Round: round,
|
||||||
Data: data,
|
Data: data,
|
||||||
|
Metadata: metadata,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
big2 "github.com/filecoin-project/go-state-types/big"
|
|
||||||
validation "github.com/go-ozzo/ozzo-validation"
|
|
||||||
)
|
|
||||||
|
|
||||||
var EmptyInt = BigInt{}
|
|
||||||
|
|
||||||
type BigInt = big2.Int
|
|
||||||
|
|
||||||
func NewInt(i uint64) BigInt {
|
|
||||||
return BigInt{Int: big.NewInt(0).SetUint64(i)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BigFromBytes(b []byte) BigInt {
|
|
||||||
i := big.NewInt(0).SetBytes(b)
|
|
||||||
return BigInt{Int: i}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ValidateBigInt(i *big.Int) validation.RuleFunc {
|
|
||||||
return func(value interface{}) error {
|
|
||||||
bigInt := i.IsInt64()
|
|
||||||
if !bigInt {
|
|
||||||
return errors.New("expected big integer")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,6 +10,7 @@ import (
|
|||||||
type ElectionProof struct {
|
type ElectionProof struct {
|
||||||
WinCount int64
|
WinCount int64
|
||||||
VRFProof []byte
|
VRFProof []byte
|
||||||
|
RandomnessRound uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
const precision = 256
|
const precision = 256
|
||||||
@ -99,13 +100,13 @@ func polyval(p []*big.Int, x *big.Int) *big.Int {
|
|||||||
|
|
||||||
// computes lambda in Q.256
|
// computes lambda in Q.256
|
||||||
func lambda(power, totalPower *big.Int) *big.Int {
|
func lambda(power, totalPower *big.Int) *big.Int {
|
||||||
lam := new(big.Int).Mul(power, tasksPerEpoch.Int) // Q.0
|
lam := new(big.Int).Mul(power, config.ExpectedLeadersPerEpoch) // Q.0
|
||||||
lam = lam.Lsh(lam, precision) // Q.256
|
lam = lam.Lsh(lam, precision) // Q.256
|
||||||
lam = lam.Div(lam /* Q.256 */, totalPower /* Q.0 */) // Q.256
|
lam = lam.Div(lam /* Q.256 */, totalPower /* Q.0 */) // Q.256
|
||||||
return lam
|
return lam
|
||||||
}
|
}
|
||||||
|
|
||||||
var MaxWinCount = 3 * int64(config.TasksPerEpoch)
|
var MaxWinCount = 10 * config.ExpectedLeadersPerEpoch.Int64()
|
||||||
|
|
||||||
type poiss struct {
|
type poiss struct {
|
||||||
lam *big.Int
|
lam *big.Int
|
||||||
@ -175,10 +176,10 @@ func (p *poiss) next() *big.Int {
|
|||||||
// ComputeWinCount uses VRFProof to compute number of wins
|
// ComputeWinCount uses VRFProof to compute number of wins
|
||||||
// The algorithm is based on Algorand's Sortition with Binomial distribution
|
// The algorithm is based on Algorand's Sortition with Binomial distribution
|
||||||
// replaced by Poisson distribution.
|
// replaced by Poisson distribution.
|
||||||
func (ep *ElectionProof) ComputeWinCount(power BigInt, totalPower BigInt) int64 {
|
func (ep *ElectionProof) ComputeWinCount(power *big.Int, totalPower *big.Int) int64 {
|
||||||
h := blake2b.Sum256(ep.VRFProof)
|
h := blake2b.Sum256(ep.VRFProof)
|
||||||
|
|
||||||
lhs := BigFromBytes(h[:]).Int // 256bits, assume Q.256 so [0, 1)
|
lhs := big.NewInt(0).SetBytes(h[:]) // 256bits, assume Q.256 so [0, 1)
|
||||||
|
|
||||||
// We are calculating upside-down CDF of Poisson distribution with
|
// We are calculating upside-down CDF of Poisson distribution with
|
||||||
// rate λ=power*E/totalPower
|
// rate λ=power*E/totalPower
|
||||||
@ -191,7 +192,7 @@ func (ep *ElectionProof) ComputeWinCount(power BigInt, totalPower BigInt) int64
|
|||||||
// rhs = 1 - pmf
|
// rhs = 1 - pmf
|
||||||
// for h(vrf) < rhs: j++; pmf = pmf * lam / j; rhs = rhs - pmf
|
// for h(vrf) < rhs: j++; pmf = pmf * lam / j; rhs = rhs - pmf
|
||||||
|
|
||||||
lam := lambda(power.Int, totalPower.Int) // Q.256
|
lam := lambda(power, totalPower) // Q.256
|
||||||
|
|
||||||
p, rhs := newPoiss(lam)
|
p, rhs := newPoiss(lam)
|
||||||
|
|
||||||
|
@ -1,145 +0,0 @@
|
|||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"math/big"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/xorcare/golden"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPoissonFunction(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
lambdaBase uint64
|
|
||||||
lambdaShift uint
|
|
||||||
}{
|
|
||||||
{10, 10}, // 0.0097
|
|
||||||
{209714, 20}, // 0.19999885
|
|
||||||
{1036915, 20}, // 0.9888792038
|
|
||||||
{1706, 10}, // 1.6660
|
|
||||||
{2, 0}, // 2
|
|
||||||
{5242879, 20}, //4.9999990
|
|
||||||
{5, 0}, // 5
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
test := test
|
|
||||||
t.Run(fmt.Sprintf("lam-%d-%d", test.lambdaBase, test.lambdaShift), func(t *testing.T) {
|
|
||||||
b := &bytes.Buffer{}
|
|
||||||
b.WriteString("icdf\n")
|
|
||||||
|
|
||||||
lam := new(big.Int).SetUint64(test.lambdaBase)
|
|
||||||
lam = lam.Lsh(lam, precision-test.lambdaShift)
|
|
||||||
p, icdf := newPoiss(lam)
|
|
||||||
|
|
||||||
b.WriteString(icdf.String())
|
|
||||||
b.WriteRune('\n')
|
|
||||||
|
|
||||||
for i := 0; i < 15; i++ {
|
|
||||||
b.WriteString(p.next().String())
|
|
||||||
b.WriteRune('\n')
|
|
||||||
}
|
|
||||||
golden.Assert(t, b.Bytes())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestLambdaFunction(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
power string
|
|
||||||
totalPower string
|
|
||||||
target float64
|
|
||||||
}{
|
|
||||||
{"10", "100", .1 * 5.},
|
|
||||||
{"1024", "2048", 0.5 * 5.},
|
|
||||||
{"2000000000000000", "100000000000000000", 0.02 * 5.},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
test := test
|
|
||||||
t.Run(fmt.Sprintf("%s-%s", test.power, test.totalPower), func(t *testing.T) {
|
|
||||||
pow, ok := new(big.Int).SetString(test.power, 10)
|
|
||||||
assert.True(t, ok)
|
|
||||||
total, ok := new(big.Int).SetString(test.totalPower, 10)
|
|
||||||
assert.True(t, ok)
|
|
||||||
lam := lambda(pow, total)
|
|
||||||
assert.Equal(t, test.target, q256ToF(lam))
|
|
||||||
golden.Assert(t, []byte(lam.String()))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExpFunction(t *testing.T) {
|
|
||||||
const N = 256
|
|
||||||
|
|
||||||
step := big.NewInt(5)
|
|
||||||
step = step.Lsh(step, 256) // Q.256
|
|
||||||
step = step.Div(step, big.NewInt(N-1))
|
|
||||||
|
|
||||||
x := big.NewInt(0)
|
|
||||||
b := &bytes.Buffer{}
|
|
||||||
|
|
||||||
b.WriteString("x, y\n")
|
|
||||||
for i := 0; i < N; i++ {
|
|
||||||
y := expneg(x)
|
|
||||||
fmt.Fprintf(b, "%s,%s\n", x, y)
|
|
||||||
x = x.Add(x, step)
|
|
||||||
}
|
|
||||||
|
|
||||||
golden.Assert(t, b.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
func q256ToF(x *big.Int) float64 {
|
|
||||||
deno := big.NewInt(1)
|
|
||||||
deno = deno.Lsh(deno, 256)
|
|
||||||
rat := new(big.Rat).SetFrac(x, deno)
|
|
||||||
f, _ := rat.Float64()
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestElectionLam(t *testing.T) {
|
|
||||||
p := big.NewInt(64)
|
|
||||||
tot := big.NewInt(128)
|
|
||||||
lam := lambda(p, tot)
|
|
||||||
target := 64. * 5. / 128.
|
|
||||||
if q256ToF(lam) != target {
|
|
||||||
t.Fatalf("wrong lambda: %f, should be: %f", q256ToF(lam), target)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var Res int64
|
|
||||||
|
|
||||||
func BenchmarkWinCounts(b *testing.B) {
|
|
||||||
totalPower := NewInt(100)
|
|
||||||
power := NewInt(100)
|
|
||||||
ep := &ElectionProof{VRFProof: nil}
|
|
||||||
var res int64
|
|
||||||
|
|
||||||
b.ResetTimer()
|
|
||||||
b.ReportAllocs()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
ep.VRFProof = []byte{byte(i), byte(i >> 8), byte(i >> 16), byte(i >> 24), byte(i >> 32)}
|
|
||||||
j := ep.ComputeWinCount(power, totalPower)
|
|
||||||
res += j
|
|
||||||
}
|
|
||||||
Res += res
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWinCounts(t *testing.T) {
|
|
||||||
t.SkipNow()
|
|
||||||
totalPower := NewInt(100)
|
|
||||||
power := NewInt(30)
|
|
||||||
|
|
||||||
f, _ := os.Create("output.wins")
|
|
||||||
fmt.Fprintf(f, "wins\n")
|
|
||||||
ep := &ElectionProof{VRFProof: nil}
|
|
||||||
for i := uint64(0); i < 1000000; i++ {
|
|
||||||
i := i + 1000000
|
|
||||||
ep.VRFProof = []byte{byte(i), byte(i >> 8), byte(i >> 16), byte(i >> 24), byte(i >> 32)}
|
|
||||||
j := ep.ComputeWinCount(power, totalPower)
|
|
||||||
fmt.Fprintf(f, "%d\n", j)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,63 +1,12 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
const TicketRandomnessLookback = 1
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
|
||||||
|
|
||||||
"github.com/Secured-Finance/dione/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DrandRound represents the round number in DRAND
|
|
||||||
type DrandRound int64
|
|
||||||
|
|
||||||
const TicketRandomnessLookback = DrandRound(1)
|
|
||||||
|
|
||||||
func (e DrandRound) String() string {
|
|
||||||
return strconv.FormatInt(int64(e), 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DioneTask represents the values of task computation
|
// DioneTask represents the values of task computation
|
||||||
type DioneTask struct {
|
type DioneTask struct {
|
||||||
OriginChain uint8
|
OriginChain uint8
|
||||||
RequestType string
|
RequestType string
|
||||||
RequestParams string
|
RequestParams string
|
||||||
Miner peer.ID
|
|
||||||
MinerEth string
|
|
||||||
Ticket *Ticket
|
|
||||||
ElectionProof *ElectionProof
|
|
||||||
BeaconEntries []BeaconEntry
|
|
||||||
DrandRound DrandRound
|
|
||||||
Payload []byte
|
Payload []byte
|
||||||
RequestID string
|
RequestID string
|
||||||
ConsensusID string
|
|
||||||
Signature []byte `hash:"-"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDioneTask(
|
|
||||||
originChain uint8,
|
|
||||||
requestType string,
|
|
||||||
requestParams string,
|
|
||||||
miner peer.ID,
|
|
||||||
ticket *Ticket,
|
|
||||||
electionProof *ElectionProof,
|
|
||||||
beacon []BeaconEntry,
|
|
||||||
drand DrandRound,
|
|
||||||
payload []byte,
|
|
||||||
) *DioneTask {
|
|
||||||
return &DioneTask{
|
|
||||||
OriginChain: originChain,
|
|
||||||
RequestType: requestType,
|
|
||||||
RequestParams: requestParams,
|
|
||||||
Miner: miner,
|
|
||||||
Ticket: ticket,
|
|
||||||
ElectionProof: electionProof,
|
|
||||||
BeaconEntries: beacon,
|
|
||||||
DrandRound: drand,
|
|
||||||
Payload: payload,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var tasksPerEpoch = NewInt(config.TasksPerEpoch)
|
|
||||||
|
|
||||||
const sha256bits = 256
|
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/minio/blake2b-simd"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Ticket struct {
|
|
||||||
VRFProof []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Ticket) Quality() float64 {
|
|
||||||
ticketHash := blake2b.Sum256(t.VRFProof)
|
|
||||||
ticketNum := BigFromBytes(ticketHash[:]).Int
|
|
||||||
ticketDenu := big.NewInt(1)
|
|
||||||
ticketDenu.Lsh(ticketDenu, 256)
|
|
||||||
tv, _ := new(big.Rat).SetFrac(ticketNum, ticketDenu).Float64()
|
|
||||||
tq := 1 - tv
|
|
||||||
return tq
|
|
||||||
}
|
|
@ -50,7 +50,7 @@ func KeyWallet(keys ...*Key) *LocalWallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *LocalWallet) WalletSign(ctx context.Context, addr peer.ID, msg []byte) (*types.Signature, error) {
|
func (w *LocalWallet) Sign(addr peer.ID, msg []byte) (*types.Signature, error) {
|
||||||
ki, err := w.findKey(addr)
|
ki, err := w.findKey(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -143,7 +143,7 @@ func (w *LocalWallet) GetDefault() (peer.ID, error) {
|
|||||||
return k.Address, nil
|
return k.Address, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *LocalWallet) WalletNew(ctx context.Context, typ types.KeyType) (peer.ID, error) {
|
func (w *LocalWallet) NewKey(typ types.KeyType) (peer.ID, error) {
|
||||||
w.lk.Lock()
|
w.lk.Lock()
|
||||||
defer w.lk.Unlock()
|
defer w.lk.Unlock()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user