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