more wiring up of drandomness

This commit is contained in:
Jeromy 2020-04-08 08:11:42 -07:00
parent 056284c00b
commit 8e0ca306d2
14 changed files with 171 additions and 151 deletions

View File

@ -22,43 +22,40 @@ type Response struct {
}
type DrandBeacon interface {
RoundTime() time.Duration
//RoundTime() uint64
//StartTime() uint64
LastEntry() (types.BeaconEntry, error)
Entry(context.Context, uint64) <-chan Response
VerifyEntry(types.BeaconEntry) (bool, error)
BeaconIndexesForEpoch(abi.ChainEpoch, int) []uint64
VerifyEntry(types.BeaconEntry, types.BeaconEntry) error
BeaconRoundsForEpoch(abi.ChainEpoch, types.BeaconEntry) []uint64
IsEntryForEpoch(e types.BeaconEntry, epoch abi.ChainEpoch, nulls int) (bool, error)
}
func ValidateBlockValues(b DrandBeacon, h *types.BlockHeader, nulls int) error {
for i, be := range h.BeaconEntries {
if ok, err := b.IsEntryForEpoch(be, h.Height, nulls); err != nil {
return xerrors.Errorf("failed to check if beacon belongs: %w")
} else if !ok {
return xerrors.Errorf("beacon does not belong in this block: %d", i)
}
if ok, err := b.VerifyEntry(be); err != nil {
return xerrors.Errorf("failed to verify beacon entry %d: %w", i, err)
} else if !ok {
return xerrors.Errorf("beacon entry %d was invalid", i)
}
func ValidateBlockValues(b DrandBeacon, h *types.BlockHeader, prevEntry types.BeaconEntry) error {
rounds := b.BeaconRoundsForEpoch(h.Height, prevEntry)
if len(rounds) != len(h.BeaconEntries) {
return xerrors.Errorf("mismatch in number of expected beacon entries (exp %d, got %d)", len(rounds), len(h.BeaconEntries))
}
// validate that block contains entry for its own epoch
should := b.BeaconIndexesForEpoch(h.Height, 0)
if should[len(should)-1] != h.BeaconEntries[len(h.BeaconEntries)-1].Index {
return xerrors.Errorf("missing beacon entry for this block")
for i, e := range h.BeaconEntries {
if e.Round != rounds[i] {
return xerrors.Errorf("entry at index %d did not match expected round (exp %d, got %d)", i, rounds[i], e.Round)
}
if err := b.VerifyEntry(e, prevEntry); err != nil {
return xerrors.Errorf("beacon entry %d was invalid: %w", i, err)
}
prevEntry = e
}
return nil
}
func BeaconEntriesForBlock(ctx context.Context, beacon DrandBeacon, round abi.ChainEpoch, nulls int) ([]types.BeaconEntry, error) {
func BeaconEntriesForBlock(ctx context.Context, beacon DrandBeacon, round abi.ChainEpoch, prev types.BeaconEntry) ([]types.BeaconEntry, error) {
start := time.Now()
var out []types.BeaconEntry
for _, ei := range beacon.BeaconIndexesForEpoch(round, nulls) {
for _, ei := range beacon.BeaconRoundsForEpoch(round, prev) {
rch := beacon.Entry(ctx, ei)
select {
case resp := <-rch:
@ -76,6 +73,7 @@ func BeaconEntriesForBlock(ctx context.Context, beacon DrandBeacon, round abi.Ch
return out, nil
}
// Mock beacon assumes that filecoin rounds are 1:1 mapped with the beacon rounds
type mockBeacon struct {
interval time.Duration
}
@ -99,7 +97,7 @@ func (mb *mockBeacon) entryForIndex(index uint64) types.BeaconEntry {
binary.BigEndian.PutUint64(buf, index)
rval := blake2b.Sum256(buf)
return types.BeaconEntry{
Index: index,
Round: index,
Data: rval[:],
}
}
@ -111,22 +109,24 @@ func (mb *mockBeacon) Entry(ctx context.Context, index uint64) <-chan Response {
return out
}
func (mb *mockBeacon) VerifyEntry(e types.BeaconEntry) (bool, error) {
func (mb *mockBeacon) VerifyEntry(from types.BeaconEntry, to types.BeaconEntry) error {
// TODO: cache this, especially for bls
oe := mb.entryForIndex(e.Index)
return bytes.Equal(e.Data, oe.Data), nil
oe := mb.entryForIndex(from.Round)
if !bytes.Equal(from.Data, oe.Data) {
return xerrors.Errorf("mock beacon entry was invalid!")
}
return nil
}
func (mb *mockBeacon) IsEntryForEpoch(e types.BeaconEntry, epoch abi.ChainEpoch, nulls int) (bool, error) {
return int64(e.Index) <= int64(epoch) && int64(epoch)-int64(nulls) >= int64(e.Index), nil
return int64(e.Round) <= int64(epoch) && int64(epoch)-int64(nulls) >= int64(e.Round), nil
}
func (mb *mockBeacon) BeaconIndexesForEpoch(epoch abi.ChainEpoch, nulls int) []uint64 {
func (mb *mockBeacon) BeaconRoundsForEpoch(epoch abi.ChainEpoch, prevEntry types.BeaconEntry) []uint64 {
var out []uint64
for i := nulls; i > 0; i-- {
out = append(out, uint64(epoch)-uint64(i))
for i := prevEntry.Round + 1; i < uint64(epoch); i++ {
out = append(out, i)
}
out = append(out, uint64(epoch))
return out
}

View File

@ -277,7 +277,7 @@ func CarWalkFunc(nd format.Node) (out []*format.Link, err error) {
return out, nil
}
func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m address.Address, round int64) (*types.EPostProof, *types.Ticket, error) {
func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m address.Address, round abi.ChainEpoch) ([]types.BeaconEntry, *types.Ticket, error) {
mc := &mca{w: cg.w, sm: cg.sm}
buf := new(bytes.Buffer)
@ -306,20 +306,28 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
VRFProof: vrfout,
}
// TODO beacon
eproofin, err := IsRoundWinner(ctx, pts, round, m, cg.eppProvs[m], types.BeaconEntry{}, mc)
prev, err := cg.cs.GetLatestBeaconEntry(pts)
if err != nil {
return nil, nil, xerrors.Errorf("getLatestBeaconEntry: %w", err)
}
entries, err := beacon.BeaconEntriesForBlock(ctx, cg.beacon, abi.ChainEpoch(round), *prev)
if err != nil {
return nil, nil, xerrors.Errorf("get beacon entries for block: %w", err)
}
rbase := *prev
if len(entries) > 0 {
rbase = entries[len(entries)-1]
}
// TODO winning post return?
_, err = IsRoundWinner(ctx, pts, round, m, rbase, mc)
if err != nil {
return nil, nil, xerrors.Errorf("checking round winner failed: %w", err)
}
if eproofin == nil {
return nil, tick, nil
}
eproof, err := ComputeProof(ctx, cg.eppProvs[m], eproofin)
if err != nil {
return nil, nil, xerrors.Errorf("computing proof: %w", err)
}
return eproof, tick, nil
return entries, tick, nil
}
type MinedTipSet struct {
@ -345,21 +353,16 @@ func (cg *ChainGen) NextTipSetFromMiners(base *types.TipSet, miners []address.Ad
return nil, xerrors.Errorf("get random messages: %w", err)
}
for round := int64(base.Height() + 1); len(blks) == 0; round++ {
for round := base.Height() + 1; len(blks) == 0; round++ {
for _, m := range miners {
proof, t, err := cg.nextBlockProof(context.TODO(), base, m, round)
bvals, t, err := cg.nextBlockProof(context.TODO(), base, m, round)
if err != nil {
return nil, xerrors.Errorf("next block proof: %w", err)
}
if proof != nil {
nulls := int(round) - int(base.Height()+1)
bvals, err := beacon.BeaconEntriesForBlock(context.TODO(), cg.beacon, abi.ChainEpoch(round), nulls)
if err != nil {
return nil, xerrors.Errorf("failed to get beacon entries: %w", err)
}
fblk, err := cg.makeBlock(base, m, proof, t, bvals, abi.ChainEpoch(round), msgs)
if t != nil {
// TODO: winning post proof
fblk, err := cg.makeBlock(base, m, nil, t, bvals, abi.ChainEpoch(round), msgs)
if err != nil {
return nil, xerrors.Errorf("making a block for next tipset failed: %w", err)
}
@ -475,7 +478,7 @@ func (mca mca) ChainGetRandomness(ctx context.Context, tsk types.TipSetKey, pers
return nil, xerrors.Errorf("loading tipset key: %w", err)
}
return mca.sm.ChainStore().GetRandomness(ctx, pts.Cids(), personalization, int64(randEpoch), entropy)
return mca.sm.ChainStore().GetRandomness(ctx, pts.Cids(), personalization, randEpoch, entropy)
}
func (mca mca) MinerGetBaseInfo(ctx context.Context, maddr address.Address, tsk types.TipSetKey) (*api.MiningBaseInfo, error) {
@ -521,83 +524,36 @@ type ProofInput struct {
vrfout []byte
}
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64,
miner address.Address, epp ElectionPoStProver, brand types.BeaconEntry, a MiningCheckAPI) (*ProofInput, error) {
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
miner address.Address, brand types.BeaconEntry, a MiningCheckAPI) (bool, error) {
buf := new(bytes.Buffer)
_, _ = buf.Write(brand.Data) // a bit hacky, would be better if it was insidce ChainGetRanomness,
// but chain has no idea about the block we are in progress of producing
if err := miner.MarshalCBOR(buf); err != nil {
return nil, xerrors.Errorf("failed to cbor marshal address: %w")
return false, xerrors.Errorf("failed to cbor marshal address: %w")
}
epostRand, err := a.ChainGetRandomness(ctx, ts.Key(), crypto.DomainSeparationTag_ElectionPoStChallengeSeed, abi.ChainEpoch(round-build.EcRandomnessLookback), buf.Bytes())
electionRand, err := store.DrawRandomness(brand.Data, 17, round, buf.Bytes())
if err != nil {
return nil, xerrors.Errorf("chain get randomness: %w", err)
return false, xerrors.Errorf("failed to draw randomness: %w", err)
}
mbi, err := a.MinerGetBaseInfo(ctx, miner, ts.Key())
if err != nil {
return nil, xerrors.Errorf("failed to get mining base info: %w", err)
return false, xerrors.Errorf("failed to get mining base info: %w", err)
}
vrfout, err := ComputeVRF(ctx, a.WalletSign, mbi.Worker, epostRand)
vrfout, err := ComputeVRF(ctx, a.WalletSign, mbi.Worker, electionRand)
if err != nil {
return nil, xerrors.Errorf("failed to compute VRF: %w", err)
return false, xerrors.Errorf("failed to compute VRF: %w", err)
}
/*
if len(mbi.Sectors) == 0 {
return nil, nil
}
var sinfos []abi.SectorInfo
for _, s := range mbi.Sectors {
if s.Info.Info.RegisteredProof == 0 {
return nil, xerrors.Errorf("sector %d in proving set had registered type of zero", s.ID)
}
sinfos = append(sinfos, abi.SectorInfo{
SectorNumber: s.ID,
SealedCID: s.Info.Info.SealedCID,
RegisteredProof: s.Info.Info.RegisteredProof,
})
}
hvrf := blake2b.Sum256(vrfout)
candidates, err := epp.GenerateCandidates(ctx, sinfos, hvrf[:])
if err != nil {
return nil, xerrors.Errorf("failed to generate electionPoSt candidates: %w", err)
}
var winners []storage.PoStCandidateWithTicket
for _, c := range candidates {
if types.IsTicketWinner(c.Candidate.PartialTicket, mbi.SectorSize, uint64(len(sinfos)), mbi.NetworkPower) {
winners = append(winners, c)
}
}
// no winners, sad
if len(winners) == 0 {
return nil, nil
}
*/
// TODO: wire in real power
myPower := types.BigMul(types.NewInt(uint64(len(mbi.Sectors))), types.NewInt(uint64(mbi.SectorSize)))
if types.IsTicketWinner(vrfout, myPower, mbi.NetworkPower) {
panic("TODO what to do when we win")
// yey winner
if !types.IsTicketWinner(vrfout, myPower, mbi.NetworkPower) {
return false, nil
}
/*
return &ProofInput{
sectors: sinfos,
hvrf: hvrf[:],
winners: winners,
vrfout: vrfout,
}, nil
*/
return nil, nil
return true, nil
}
func ComputeProof(ctx context.Context, epp ElectionPoStProver, pi *ProofInput) (*types.EPostProof, error) {

View File

@ -266,6 +266,12 @@ func MakeGenesisBlock(ctx context.Context, bs bstore.Blockstore, sys runtime.Sys
BLSAggregate: nil,
BlockSig: nil,
Timestamp: template.Timestamp,
BeaconEntries: []types.BeaconEntry{
types.BeaconEntry{
Round: 0,
Data: make([]byte, 32),
},
},
}
sb, err := b.ToStorageBlock()

View File

@ -264,8 +264,8 @@ func SetupStorageMiners(ctx context.Context, cs *store.ChainStore, sroot cid.Cid
// TODO: copied from actors test harness, deduplicate or remove from here
type fakeRand struct{}
func (fr *fakeRand) GetRandomness(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch int64, entropy []byte) ([]byte, error) {
func (fr *fakeRand) GetRandomness(ctx context.Context, personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) ([]byte, error) {
out := make([]byte, 32)
rand.New(rand.NewSource(randEpoch)).Read(out)
rand.New(rand.NewSource(int64(randEpoch))).Read(out)
return out, nil
}

View File

@ -34,13 +34,13 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
}
next := &types.BlockHeader{
Miner: miner,
Parents: parents.Cids(),
Ticket: ticket,
BeaconEntries: bvals,
Height: height,
Timestamp: timestamp,
EPostProof: *proof,
Miner: miner,
Parents: parents.Cids(),
Ticket: ticket,
BeaconEntries: bvals,
Height: height,
Timestamp: timestamp,
//EPostProof: *proof,
ParentStateRoot: st,
ParentMessageReceipts: recpts,
}

View File

@ -189,7 +189,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
Miner: b.Miner,
Penalty: penalty,
GasReward: gasReward,
TicketCount: b.TicketCount,
TicketCount: 1, // TODO: no longer need ticket count here.
})
if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err)

View File

@ -892,12 +892,12 @@ func (cs *ChainStore) TryFillTipSet(ts *types.TipSet) (*FullTipSet, error) {
return NewFullTipSet(out), nil
}
func drawRandomness(t *types.Ticket, pers crypto.DomainSeparationTag, round int64, entropy []byte) ([]byte, error) {
func DrawRandomness(rbase []byte, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
h := blake2b.New256()
if err := binary.Write(h, binary.BigEndian, int64(pers)); err != nil {
return nil, xerrors.Errorf("deriving randomness: %w", err)
}
VRFDigest := blake2b.Sum256(t.VRFProof)
VRFDigest := blake2b.Sum256(rbase)
h.Write(VRFDigest[:])
if err := binary.Write(h, binary.BigEndian, round); err != nil {
return nil, xerrors.Errorf("deriving randomness: %w", err)
@ -907,10 +907,10 @@ func drawRandomness(t *types.Ticket, pers crypto.DomainSeparationTag, round int6
return h.Sum(nil), nil
}
func (cs *ChainStore) GetRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round int64, entropy []byte) (out []byte, err error) {
func (cs *ChainStore) GetRandomness(ctx context.Context, blks []cid.Cid, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) (out []byte, err error) {
_, span := trace.StartSpan(ctx, "store.GetRandomness")
defer span.End()
span.AddAttributes(trace.Int64Attribute("round", round))
span.AddAttributes(trace.Int64Attribute("round", int64(round)))
/*
defer func() {
@ -927,8 +927,8 @@ func (cs *ChainStore) GetRandomness(ctx context.Context, blks []cid.Cid, pers cr
// if at (or just past -- for null epochs) appropriate epoch
// or at genesis (works for negative epochs)
if int64(nts.Height()) <= round || mtb.Height == 0 {
return drawRandomness(nts.MinTicketBlock().Ticket, pers, round, entropy)
if nts.Height() <= round || mtb.Height == 0 {
return DrawRandomness(nts.MinTicketBlock().Ticket.VRFProof, pers, round, entropy)
}
blks = mtb.Parents
@ -1090,6 +1090,28 @@ func (cs *ChainStore) Import(r io.Reader) (*types.TipSet, error) {
return root, nil
}
func (cs *ChainStore) GetLatestBeaconEntry(ts *types.TipSet) (*types.BeaconEntry, error) {
cur := ts
for i := 0; i < 20; i++ {
cbe := cur.Blocks()[0].BeaconEntries
if len(cbe) > 0 {
return &cbe[len(cbe)-1], nil
}
if cur.Height() == 0 {
return nil, xerrors.Errorf("made it back to genesis block without finding beacon entry")
}
next, err := cs.LoadTipSet(cur.Parents())
if err != nil {
return nil, xerrors.Errorf("failed to load parents when searching back for latest beacon entry: %w", err)
}
cur = next
}
return nil, xerrors.Errorf("found NO beacon entries in the 20 blocks prior to given tipset")
}
type chainRand struct {
cs *ChainStore
blks []cid.Cid
@ -1104,7 +1126,7 @@ func NewChainRand(cs *ChainStore, blks []cid.Cid, bheight abi.ChainEpoch) vm.Ran
}
}
func (cr *chainRand) GetRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round int64, entropy []byte) ([]byte, error) {
func (cr *chainRand) GetRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
return cr.cs.GetRandomness(ctx, cr.blks, pers, round, entropy)
}

View File

@ -627,16 +627,22 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
return xerrors.Errorf("failed to marshal miner address to cbor: %w", err)
}
vrfBase, err := syncer.sm.ChainStore().GetRandomness(ctx, baseTs.Cids(), crypto.DomainSeparationTag_TicketProduction, int64(h.Height)-1, buf.Bytes())
if err != nil {
return xerrors.Errorf("failed to get randomness for verifying election proof: %w", err)
}
baseBeacon := prevBeacon
if len(h.BeaconEntries) > 0 {
baseBeacon = h.BeaconEntries[len(h.BeaconEntries)-1]
}
buf := new(bytes.Buffer)
if err := h.Miner.MarshalCBOR(buf); err != nil {
return xerrors.Errorf("failed to marshal miner address to cbor: %w", err)
}
// TODO: use real DST from specs actors when it lands
vrfBase, err := store.DrawRandomness(baseBeacon.Data, 17, int64(h.Height), buf.Bytes())
if err != nil {
return xerrors.Errorf("failed to compute vrf base for ticket: %w", err)
}
err = gen.VerifyVRF(ctx, waddr, vrfBase, h.Ticket.VRFProof)
if err != nil {
return xerrors.Errorf("validating block tickets failed: %w", err)

View File

@ -35,7 +35,7 @@ type EPostProof struct {
}
type BeaconEntry struct {
Index uint64
Round uint64
Data []byte
}

View File

@ -1508,7 +1508,7 @@ func (t *BeaconEntry) MarshalCBOR(w io.Writer) error {
// t.Index (uint64) (uint64)
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Index))); err != nil {
if _, err := w.Write(cbg.CborEncodeMajorType(cbg.MajUnsignedInt, uint64(t.Round))); err != nil {
return err
}
@ -1552,7 +1552,7 @@ func (t *BeaconEntry) UnmarshalCBOR(r io.Reader) error {
if maj != cbg.MajUnsignedInt {
return fmt.Errorf("wrong type for uint64 field")
}
t.Index = uint64(extra)
t.Round = uint64(extra)
}
// t.Data ([]uint8) (slice)

View File

@ -2,6 +2,7 @@ package validation
import (
"context"
"golang.org/x/xerrors"
"github.com/filecoin-project/specs-actors/actors/abi"
@ -101,15 +102,15 @@ type randWrapper struct {
rnd vstate.RandomnessSource
}
func (w *randWrapper) GetRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round int64, entropy []byte) ([]byte, error) {
return w.rnd.Randomness(ctx, pers, abi.ChainEpoch(round), entropy)
func (w *randWrapper) GetRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
return w.rnd.Randomness(ctx, pers, round, entropy)
}
type vmRand struct {
eCtx *vtypes.ExecutionContext
}
func (*vmRand) GetRandomness(ctx context.Context, dst crypto.DomainSeparationTag, h int64, input []byte) ([]byte, error) {
func (*vmRand) GetRandomness(ctx context.Context, dst crypto.DomainSeparationTag, h abi.ChainEpoch, input []byte) ([]byte, error) {
panic("implement me")
}

View File

@ -151,7 +151,7 @@ func (rs *Runtime) GetActorCodeCID(addr address.Address) (ret cid.Cid, ok bool)
}
func (rt *Runtime) GetRandomness(personalization crypto.DomainSeparationTag, randEpoch abi.ChainEpoch, entropy []byte) abi.Randomness {
res, err := rt.vm.rand.GetRandomness(rt.ctx, personalization, int64(randEpoch), entropy)
res, err := rt.vm.rand.GetRandomness(rt.ctx, personalization, randEpoch, entropy)
if err != nil {
panic(aerrors.Fatalf("could not get randomness: %s", err))
}

View File

@ -188,7 +188,7 @@ func NewVM(base cid.Cid, height abi.ChainEpoch, r Rand, maddr address.Address, c
}
type Rand interface {
GetRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round int64, entropy []byte) ([]byte, error)
GetRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error)
}
type ApplyRet struct {

View File

@ -290,12 +290,40 @@ func (m *Miner) hasPower(ctx context.Context, addr address.Address, ts *types.Ti
return !power.MinerPower.Equals(types.NewInt(0)), nil
}
// Note: copied from the chainstore method. Maybe we should expose this over the api?
func (m *Miner) getLatestBeaconEntry(ctx context.Context, ts *types.TipSet) (*types.BeaconEntry, error) {
cur := ts
for i := 0; i < 20; i++ {
cbe := cur.Blocks()[0].BeaconEntries
if len(cbe) > 0 {
return &cbe[len(cbe)-1], nil
}
if cur.Height() == 0 {
return nil, xerrors.Errorf("made it back to genesis block without finding beacon entry")
}
next, err := m.api.ChainGetTipSet(ctx, cur.Parents())
if err != nil {
return nil, xerrors.Errorf("failed to load parents when searching back for latest beacon entry: %w", err)
}
cur = next
}
return nil, xerrors.Errorf("found NO beacon entries in the 20 blocks prior to given tipset")
}
func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningBase) (*types.BlockMsg, error) {
log.Debugw("attempting to mine a block", "tipset", types.LogCids(base.ts.Cids()))
start := time.Now()
beaconPrev, err := m.getLatestBeaconEntry(ctx, base.ts)
if err != nil {
return nil, xerrors.Errorf("getLatestBeaconEntry: %w", err)
}
round := base.ts.Height() + base.nullRounds + 1
bvals, err := beacon.BeaconEntriesForBlock(ctx, m.beacon, round, int(base.nullRounds))
bvals, err := beacon.BeaconEntriesForBlock(ctx, m.beacon, round, *beaconPrev)
if err != nil {
return nil, xerrors.Errorf("get beacon entries failed: %w", err)
}
@ -317,12 +345,17 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB
return nil, xerrors.Errorf("scratching ticket failed: %w", err)
}
proofin, err := gen.IsRoundWinner(ctx, base.ts, int64(round), addr, m.epp, bvals[len(bvals)-1], m.api)
rbase := *beaconPrev
if len(bvals) > 0 {
rbase = bvals[len(bvals)-1]
}
winner, err := gen.IsRoundWinner(ctx, base.ts, round, addr, rbase, m.api)
if err != nil {
return nil, xerrors.Errorf("failed to check if we win next round: %w", err)
}
if proofin == nil {
if !winner {
base.nullRounds++
return nil, nil
}
@ -333,12 +366,8 @@ func (m *Miner) mineOne(ctx context.Context, addr address.Address, base *MiningB
return nil, xerrors.Errorf("failed to get pending messages: %w", err)
}
proof, err := gen.ComputeProof(ctx, m.epp, proofin)
if err != nil {
return nil, xerrors.Errorf("computing election proof: %w", err)
}
b, err := m.createBlock(base, addr, ticket, proof, bvals, pending)
// TODO: winning post proof
b, err := m.createBlock(base, addr, ticket, nil, bvals, pending)
if err != nil {
return nil, xerrors.Errorf("failed to create block: %w", err)
}