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

View File

@ -277,7 +277,7 @@ func CarWalkFunc(nd format.Node) (out []*format.Link, err error) {
return out, nil 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} mc := &mca{w: cg.w, sm: cg.sm}
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
@ -306,20 +306,28 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
VRFProof: vrfout, VRFProof: vrfout,
} }
// TODO beacon prev, err := cg.cs.GetLatestBeaconEntry(pts)
eproofin, err := IsRoundWinner(ctx, pts, round, m, cg.eppProvs[m], types.BeaconEntry{}, mc) 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 { if err != nil {
return nil, nil, xerrors.Errorf("checking round winner failed: %w", err) 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 { 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) 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 { 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 { if err != nil {
return nil, xerrors.Errorf("next block proof: %w", err) return nil, xerrors.Errorf("next block proof: %w", err)
} }
if proof != nil { if t != nil {
nulls := int(round) - int(base.Height()+1) // TODO: winning post proof
bvals, err := beacon.BeaconEntriesForBlock(context.TODO(), cg.beacon, abi.ChainEpoch(round), nulls) fblk, err := cg.makeBlock(base, m, nil, t, bvals, abi.ChainEpoch(round), msgs)
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 err != nil { if err != nil {
return nil, xerrors.Errorf("making a block for next tipset failed: %w", err) 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 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) { 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 vrfout []byte
} }
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
miner address.Address, epp ElectionPoStProver, brand types.BeaconEntry, a MiningCheckAPI) (*ProofInput, error) { miner address.Address, brand types.BeaconEntry, a MiningCheckAPI) (bool, error) {
buf := new(bytes.Buffer) 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 { 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 { 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()) mbi, err := a.MinerGetBaseInfo(ctx, miner, ts.Key())
if err != nil { 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 { 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 // TODO: wire in real power
myPower := types.BigMul(types.NewInt(uint64(len(mbi.Sectors))), types.NewInt(uint64(mbi.SectorSize))) myPower := types.BigMul(types.NewInt(uint64(len(mbi.Sectors))), types.NewInt(uint64(mbi.SectorSize)))
if types.IsTicketWinner(vrfout, myPower, mbi.NetworkPower) { if !types.IsTicketWinner(vrfout, myPower, mbi.NetworkPower) {
panic("TODO what to do when we win") return false, nil
// yey winner
} }
/* return true, nil
return &ProofInput{
sectors: sinfos,
hvrf: hvrf[:],
winners: winners,
vrfout: vrfout,
}, nil
*/
return nil, nil
} }
func ComputeProof(ctx context.Context, epp ElectionPoStProver, pi *ProofInput) (*types.EPostProof, error) { 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, BLSAggregate: nil,
BlockSig: nil, BlockSig: nil,
Timestamp: template.Timestamp, Timestamp: template.Timestamp,
BeaconEntries: []types.BeaconEntry{
types.BeaconEntry{
Round: 0,
Data: make([]byte, 32),
},
},
} }
sb, err := b.ToStorageBlock() 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 // TODO: copied from actors test harness, deduplicate or remove from here
type fakeRand struct{} 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) out := make([]byte, 32)
rand.New(rand.NewSource(randEpoch)).Read(out) rand.New(rand.NewSource(int64(randEpoch))).Read(out)
return out, nil return out, nil
} }

View File

@ -40,7 +40,7 @@ func MinerCreateBlock(ctx context.Context, sm *stmgr.StateManager, w *wallet.Wal
BeaconEntries: bvals, BeaconEntries: bvals,
Height: height, Height: height,
Timestamp: timestamp, Timestamp: timestamp,
EPostProof: *proof, //EPostProof: *proof,
ParentStateRoot: st, ParentStateRoot: st,
ParentMessageReceipts: recpts, ParentMessageReceipts: recpts,
} }

View File

@ -189,7 +189,7 @@ func (sm *StateManager) ApplyBlocks(ctx context.Context, pstate cid.Cid, bms []B
Miner: b.Miner, Miner: b.Miner,
Penalty: penalty, Penalty: penalty,
GasReward: gasReward, GasReward: gasReward,
TicketCount: b.TicketCount, TicketCount: 1, // TODO: no longer need ticket count here.
}) })
if err != nil { if err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("failed to serialize award params: %w", err) 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 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() h := blake2b.New256()
if err := binary.Write(h, binary.BigEndian, int64(pers)); err != nil { if err := binary.Write(h, binary.BigEndian, int64(pers)); err != nil {
return nil, xerrors.Errorf("deriving randomness: %w", err) return nil, xerrors.Errorf("deriving randomness: %w", err)
} }
VRFDigest := blake2b.Sum256(t.VRFProof) VRFDigest := blake2b.Sum256(rbase)
h.Write(VRFDigest[:]) h.Write(VRFDigest[:])
if err := binary.Write(h, binary.BigEndian, round); err != nil { if err := binary.Write(h, binary.BigEndian, round); err != nil {
return nil, xerrors.Errorf("deriving randomness: %w", err) 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 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") _, span := trace.StartSpan(ctx, "store.GetRandomness")
defer span.End() defer span.End()
span.AddAttributes(trace.Int64Attribute("round", round)) span.AddAttributes(trace.Int64Attribute("round", int64(round)))
/* /*
defer func() { 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 // if at (or just past -- for null epochs) appropriate epoch
// or at genesis (works for negative epochs) // or at genesis (works for negative epochs)
if int64(nts.Height()) <= round || mtb.Height == 0 { if nts.Height() <= round || mtb.Height == 0 {
return drawRandomness(nts.MinTicketBlock().Ticket, pers, round, entropy) return DrawRandomness(nts.MinTicketBlock().Ticket.VRFProof, pers, round, entropy)
} }
blks = mtb.Parents blks = mtb.Parents
@ -1090,6 +1090,28 @@ func (cs *ChainStore) Import(r io.Reader) (*types.TipSet, error) {
return root, nil 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 { type chainRand struct {
cs *ChainStore cs *ChainStore
blks []cid.Cid 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) 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) 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 baseBeacon := prevBeacon
if len(h.BeaconEntries) > 0 { if len(h.BeaconEntries) > 0 {
baseBeacon = h.BeaconEntries[len(h.BeaconEntries)-1] 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) err = gen.VerifyVRF(ctx, waddr, vrfBase, h.Ticket.VRFProof)
if err != nil { if err != nil {
return xerrors.Errorf("validating block tickets failed: %w", err) return xerrors.Errorf("validating block tickets failed: %w", err)

View File

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

View File

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

View File

@ -2,6 +2,7 @@ package validation
import ( import (
"context" "context"
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/specs-actors/actors/abi" "github.com/filecoin-project/specs-actors/actors/abi"
@ -101,15 +102,15 @@ type randWrapper struct {
rnd vstate.RandomnessSource rnd vstate.RandomnessSource
} }
func (w *randWrapper) GetRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round int64, entropy []byte) ([]byte, error) { func (w *randWrapper) GetRandomness(ctx context.Context, pers crypto.DomainSeparationTag, round abi.ChainEpoch, entropy []byte) ([]byte, error) {
return w.rnd.Randomness(ctx, pers, abi.ChainEpoch(round), entropy) return w.rnd.Randomness(ctx, pers, round, entropy)
} }
type vmRand struct { type vmRand struct {
eCtx *vtypes.ExecutionContext 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") 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 { 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 { if err != nil {
panic(aerrors.Fatalf("could not get randomness: %s", err)) 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 { 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 { 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 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) { 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())) log.Debugw("attempting to mine a block", "tipset", types.LogCids(base.ts.Cids()))
start := time.Now() 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 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 { if err != nil {
return nil, xerrors.Errorf("get beacon entries failed: %w", err) 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) 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 { if err != nil {
return nil, xerrors.Errorf("failed to check if we win next round: %w", err) return nil, xerrors.Errorf("failed to check if we win next round: %w", err)
} }
if proofin == nil { if !winner {
base.nullRounds++ base.nullRounds++
return nil, nil 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) return nil, xerrors.Errorf("failed to get pending messages: %w", err)
} }
proof, err := gen.ComputeProof(ctx, m.epp, proofin) // TODO: winning post proof
if err != nil { b, err := m.createBlock(base, addr, ticket, nil, bvals, pending)
return nil, xerrors.Errorf("computing election proof: %w", err)
}
b, err := m.createBlock(base, addr, ticket, proof, bvals, pending)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to create block: %w", err) return nil, xerrors.Errorf("failed to create block: %w", err)
} }