dione/beacon/beacon.go

148 lines
4.2 KiB
Go

package beacon
import (
"context"
"fmt"
"github.com/Secured-Finance/dione/lib"
"github.com/sirupsen/logrus"
"github.com/Secured-Finance/dione/types"
)
type BeaconResult struct {
Entry types.BeaconEntry
Err error
}
type BeaconNetworks []BeaconNetwork
func (bn BeaconNetworks) BeaconNetworkForRound(e types.DrandRound) BeaconAPI {
for i := len(bn) - 1; i >= 0; i-- {
bp := bn[i]
if e >= bp.Start {
return bp.Beacon
}
}
return bn[0].Beacon
}
type BeaconNetwork struct {
Start types.DrandRound
Beacon BeaconAPI
}
// BeaconAPI represents a system that provides randomness.
// Other components interrogate the BeaconAPI to acquire randomness that's
// valid for a specific chain epoch. Also to verify beacon entries that have
// been posted on chain.
type BeaconAPI interface {
Entry(context.Context, uint64) <-chan BeaconResult
VerifyEntry(types.BeaconEntry, types.BeaconEntry) error
LatestBeaconRound() uint64
}
func ValidateTaskBeacons(beaconNetworks BeaconNetworks, t *types.DioneTask, prevEpoch types.DrandRound, prevEntry types.BeaconEntry) error {
parentBeacon := beaconNetworks.BeaconNetworkForRound(prevEpoch)
currBeacon := beaconNetworks.BeaconNetworkForRound(t.DrandRound)
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
bNetwork := beaconNetworks.BeaconNetworkForRound(t.DrandRound)
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
}
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]
}
}