more wiring up of drandomness
This commit is contained in:
parent
056284c00b
commit
8e0ca306d2
@ -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
|
||||
}
|
||||
|
||||
|
118
chain/gen/gen.go
118
chain/gen/gen.go
@ -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) {
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -35,7 +35,7 @@ type EPostProof struct {
|
||||
}
|
||||
|
||||
type BeaconEntry struct {
|
||||
Index uint64
|
||||
Round uint64
|
||||
Data []byte
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user