diff --git a/chain/beacon/beacon.go b/chain/beacon/beacon.go index 5f8a18951..0932c0c2a 100644 --- a/chain/beacon/beacon.go +++ b/chain/beacon/beacon.go @@ -18,6 +18,23 @@ type Response struct { Err error } +type Schedule []BeaconPoint + +func (bs Schedule) BeaconForEpoch(e abi.ChainEpoch) RandomBeacon { + for i := len(bs) - 1; i >= 0; i-- { + bp := bs[i] + if e > bp.Start { + return bp.Beacon + } + } + return bs[0].Beacon +} + +type BeaconPoint struct { + Start abi.ChainEpoch + Beacon RandomBeacon +} + // RandomBeacon represents a system that provides randomness to Lotus. // Other components interrogate the RandomBeacon to acquire randomness that's // valid for a specific chain epoch. Also to verify beacon entries that have @@ -28,7 +45,11 @@ type RandomBeacon interface { MaxBeaconRoundForEpoch(abi.ChainEpoch, types.BeaconEntry) uint64 } -func ValidateBlockValues(b RandomBeacon, h *types.BlockHeader, prevEntry types.BeaconEntry) error { +func ValidateBlockValues(bSchedule Schedule, h *types.BlockHeader, parentEpoch abi.ChainEpoch, + prevEntry types.BeaconEntry) error { + + // TODO: fork logic + b := bSchedule.BeaconForEpoch(h.Height) maxRound := b.MaxBeaconRoundForEpoch(h.Height, prevEntry) if maxRound == prevEntry.Round { if len(h.BeaconEntries) != 0 { @@ -56,10 +77,13 @@ func ValidateBlockValues(b RandomBeacon, h *types.BlockHeader, prevEntry types.B return nil } -func BeaconEntriesForBlock(ctx context.Context, beacon RandomBeacon, round abi.ChainEpoch, prev types.BeaconEntry) ([]types.BeaconEntry, error) { +func BeaconEntriesForBlock(ctx context.Context, bSchedule Schedule, epoch abi.ChainEpoch, parentEpoch abi.ChainEpoch, prev types.BeaconEntry) ([]types.BeaconEntry, error) { + // TODO: fork logic + beacon := bSchedule.BeaconForEpoch(epoch) + start := build.Clock.Now() - maxRound := beacon.MaxBeaconRoundForEpoch(round, prev) + maxRound := beacon.MaxBeaconRoundForEpoch(epoch, prev) if maxRound == prev.Round { return nil, nil } @@ -82,7 +106,7 @@ func BeaconEntriesForBlock(ctx context.Context, beacon RandomBeacon, round abi.C out = append(out, resp.Entry) cur = resp.Entry.Round - 1 case <-ctx.Done(): - return nil, xerrors.Errorf("context timed out waiting on beacon entry to come back for round %d: %w", round, ctx.Err()) + return nil, xerrors.Errorf("context timed out waiting on beacon entry to come back for epoch %d: %w", epoch, ctx.Err()) } } diff --git a/chain/gen/gen.go b/chain/gen/gen.go index e6127508e..5f755b2ae 100644 --- a/chain/gen/gen.go +++ b/chain/gen/gen.go @@ -59,7 +59,7 @@ type ChainGen struct { cs *store.ChainStore - beacon beacon.RandomBeacon + beacon beacon.Schedule sm *stmgr.StateManager @@ -252,7 +252,7 @@ func NewGeneratorWithSectors(numSectors int) (*ChainGen, error) { miners := []address.Address{maddr1, maddr2} - beac := beacon.NewMockBeacon(time.Second) + beac := beacon.Schedule{{Start: 0, Beacon: beacon.NewMockBeacon(time.Second)}} //beac, err := drand.NewDrandBeacon(tpl.Timestamp, build.BlockDelaySecs) //if err != nil { //return nil, xerrors.Errorf("creating drand beacon: %w", err) @@ -338,7 +338,7 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add prev := mbi.PrevBeaconEntry - entries, err := beacon.BeaconEntriesForBlock(ctx, cg.beacon, round, prev) + entries, err := beacon.BeaconEntriesForBlock(ctx, cg.beacon, round, pts.Height(), prev) if err != nil { return nil, nil, nil, xerrors.Errorf("get beacon entries for block: %w", err) } @@ -559,7 +559,7 @@ type mca struct { w *wallet.Wallet sm *stmgr.StateManager pv ffiwrapper.Verifier - bcn beacon.RandomBeacon + bcn beacon.Schedule } func (mca mca) ChainGetRandomnessFromTickets(ctx context.Context, tsk types.TipSetKey, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) (abi.Randomness, error) { diff --git a/chain/stmgr/utils.go b/chain/stmgr/utils.go index b21400da6..0cfc0e432 100644 --- a/chain/stmgr/utils.go +++ b/chain/stmgr/utils.go @@ -502,7 +502,7 @@ func GetLookbackTipSetForRound(ctx context.Context, sm *StateManager, ts *types. return lbts, nil } -func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBeacon, tsk types.TipSetKey, round abi.ChainEpoch, maddr address.Address, pv ffiwrapper.Verifier) (*api.MiningBaseInfo, error) { +func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule, tsk types.TipSetKey, round abi.ChainEpoch, maddr address.Address, pv ffiwrapper.Verifier) (*api.MiningBaseInfo, error) { ts, err := sm.ChainStore().LoadTipSet(tsk) if err != nil { return nil, xerrors.Errorf("failed to load tipset for mining base: %w", err) @@ -517,7 +517,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcn beacon.RandomBe prev = &types.BeaconEntry{} } - entries, err := beacon.BeaconEntriesForBlock(ctx, bcn, round, *prev) + entries, err := beacon.BeaconEntriesForBlock(ctx, bcs, round, ts.Height(), *prev) if err != nil { return nil, err } diff --git a/chain/sync.go b/chain/sync.go index d64e68055..7cea20f9d 100644 --- a/chain/sync.go +++ b/chain/sync.go @@ -103,7 +103,7 @@ type Syncer struct { store *store.ChainStore // handle to the random beacon for verification - beacon beacon.RandomBeacon + beacon beacon.Schedule // the state manager handles making state queries sm *stmgr.StateManager @@ -141,7 +141,7 @@ type Syncer struct { } // NewSyncer creates a new Syncer object. -func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*Syncer, error) { +func NewSyncer(ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, connmgr connmgr.ConnManager, self peer.ID, beacon beacon.Schedule, verifier ffiwrapper.Verifier) (*Syncer, error) { gen, err := sm.ChainStore().GetGenesis() if err != nil { return nil, xerrors.Errorf("getting genesis block: %w", err) @@ -879,7 +879,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) (er return nil } - if err := beacon.ValidateBlockValues(syncer.beacon, h, *prevBeacon); err != nil { + if err := beacon.ValidateBlockValues(syncer.beacon, h, baseTs.Height(), *prevBeacon); err != nil { return xerrors.Errorf("failed to validate blocks random beacon values: %w", err) } return nil diff --git a/node/impl/full/state.go b/node/impl/full/state.go index 1cef5eaee..43f8fd4e0 100644 --- a/node/impl/full/state.go +++ b/node/impl/full/state.go @@ -53,7 +53,7 @@ type StateAPI struct { ProofVerifier ffiwrapper.Verifier StateManager *stmgr.StateManager Chain *store.ChainStore - Beacon beacon.RandomBeacon + Beacon beacon.Schedule } func (a *StateAPI) StateNetworkName(ctx context.Context) (dtypes.NetworkName, error) { diff --git a/node/modules/chain.go b/node/modules/chain.go index cc86156b6..7b7e03e44 100644 --- a/node/modules/chain.go +++ b/node/modules/chain.go @@ -163,7 +163,7 @@ func NetworkName(mctx helpers.MetricsCtx, lc fx.Lifecycle, cs *store.ChainStore, return netName, err } -func NewSyncer(lc fx.Lifecycle, ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, h host.Host, beacon beacon.RandomBeacon, verifier ffiwrapper.Verifier) (*chain.Syncer, error) { +func NewSyncer(lc fx.Lifecycle, ds dtypes.MetadataDS, sm *stmgr.StateManager, exchange exchange.Client, h host.Host, beacon beacon.Schedule, verifier ffiwrapper.Verifier) (*chain.Syncer, error) { syncer, err := chain.NewSyncer(ds, sm, exchange, h.ConnManager(), h.ID(), beacon, verifier) if err != nil { return nil, err