Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
This commit is contained in:
Jakub Sztandera 2020-04-07 20:23:16 +02:00 committed by Jeromy
parent afdb1db529
commit 9c250f24fa
6 changed files with 81 additions and 81 deletions

View File

@ -45,6 +45,12 @@ func ValidateBlockValues(b DrandBeacon, h *types.BlockHeader, nulls int) error {
}
}
// 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")
}
return nil
}
@ -117,10 +123,10 @@ func (mb *mockBeacon) IsEntryForEpoch(e types.BeaconEntry, epoch abi.ChainEpoch,
func (mb *mockBeacon) BeaconIndexesForEpoch(epoch abi.ChainEpoch, nulls int) []uint64 {
var out []uint64
out = append(out, uint64(epoch))
for i := 0; i < nulls; i++ {
for i := nulls; i > 0; i-- {
out = append(out, uint64(epoch)-uint64(i))
}
out = append(out, uint64(epoch))
return out
}

View File

@ -22,7 +22,6 @@ import (
format "github.com/ipfs/go-ipld-format"
logging "github.com/ipfs/go-log/v2"
"github.com/ipfs/go-merkledag"
"github.com/minio/blake2b-simd"
"go.opencensus.io/trace"
"golang.org/x/xerrors"
@ -307,7 +306,8 @@ func (cg *ChainGen) nextBlockProof(ctx context.Context, pts *types.TipSet, m add
VRFProof: vrfout,
}
eproofin, err := IsRoundWinner(ctx, pts, round, m, cg.eppProvs[m], mc)
// TODO beacon
eproofin, err := IsRoundWinner(ctx, pts, round, m, cg.eppProvs[m], types.BeaconEntry{}, mc)
if err != nil {
return nil, nil, xerrors.Errorf("checking round winner failed: %w", err)
}
@ -521,11 +521,17 @@ type ProofInput struct {
vrfout []byte
}
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner address.Address, epp ElectionPoStProver, a MiningCheckAPI) (*ProofInput, error) {
func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64,
miner address.Address, epp ElectionPoStProver, brand types.BeaconEntry, a MiningCheckAPI) (*ProofInput, 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")
}
epostRand, err := a.ChainGetRandomness(ctx, ts.Key(), crypto.DomainSeparationTag_ElectionPoStChallengeSeed, abi.ChainEpoch(round-build.EcRandomnessLookback), buf.Bytes())
if err != nil {
return nil, xerrors.Errorf("chain get randomness: %w", err)
@ -541,46 +547,57 @@ func IsRoundWinner(ctx context.Context, ts *types.TipSet, round int64, miner add
return nil, 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)
/*
if len(mbi.Sectors) == 0 {
return nil, nil
}
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)
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
}
// no winners, sad
if len(winners) == 0 {
return nil, nil
}
return &ProofInput{
sectors: sinfos,
hvrf: hvrf[:],
winners: winners,
vrfout: vrfout,
}, 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) {

View File

@ -892,7 +892,7 @@ func (cs *ChainStore) TryFillTipSet(ts *types.TipSet) (*FullTipSet, error) {
return NewFullTipSet(out), nil
}
func drawRandomness(t *types.Ticket, pers crypto.DomainSeparationTag, round int64, drandRng []byte, entropy []byte) ([]byte, error) {
func drawRandomness(t *types.Ticket, pers crypto.DomainSeparationTag, round int64, 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)
@ -902,7 +902,6 @@ func drawRandomness(t *types.Ticket, pers crypto.DomainSeparationTag, round int6
if err := binary.Write(h, binary.BigEndian, round); err != nil {
return nil, xerrors.Errorf("deriving randomness: %w", err)
}
h.Write(drandRng)
h.Write(entropy)
return h.Sum(nil), nil
@ -918,17 +917,6 @@ func (cs *ChainStore) GetRandomness(ctx context.Context, blks []cid.Cid, pers cr
log.Infof("getRand %v %d %d %x -> %x", blks, pers, round, entropy, out)
}()
*/
var drandRng []byte
if pers == crypto.DomainSeparationTag_ElectionPoStChallengeSeed {
// special case, use lates beacon
nts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
if err != nil {
return nil, err
}
drandRng = nts.Blocks()[0].BeaconEntries[0].Data
}
for {
nts, err := cs.LoadTipSet(types.NewTipSetKey(blks...))
if err != nil {
@ -940,10 +928,7 @@ 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 {
if len(drandRng) == 0 {
drandRng = nts.Blocks()[0].BeaconEntries[0].Data
}
return drawRandomness(nts.MinTicketBlock().Ticket, pers, round, drandRng, entropy)
return drawRandomness(nts.MinTicketBlock().Ticket, pers, round, entropy)
}
blks = mtb.Parents

View File

@ -628,6 +628,7 @@ func (syncer *Syncer) ValidateBlock(ctx context.Context, b *types.FullBlock) err
if err := beacon.ValidateBlockValues(syncer.beacon, h, int(nulls)); err != nil {
return xerrors.Errorf("failed to validate blocks random beacon values: %w", err)
}
// TODO: check if first value links to value from previous block/previous block containing a value
return nil
})
@ -971,13 +972,17 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to
}
{
// ensure consistency of beacon entires
targetBE := from.Blocks()[0].BeaconEntries
if len(targetBE) != 0 {
if len(targetBE) == 0 {
syncer.bad.Add(from.Cids()[0], "no beacon entires")
return nil, xerrors.Errorf("block (%s) contained no drand entires", from.Cids()[0])
}
cur := targetBE[0].Index
for _, e := range targetBE[1:] {
if cur <= e.Index {
markBad("wrong order of beacon entires")
if cur >= e.Index {
syncer.bad.Add(from.Cids()[0], "wrong order of beacon entires")
return nil, xerrors.Errorf("wrong order of beacon entires")
}
}
@ -985,12 +990,12 @@ func (syncer *Syncer) collectHeaders(ctx context.Context, from *types.TipSet, to
}
for _, bh := range from.Blocks()[1:] {
if len(targetBE) != len(bh.BeaconEntries) {
markBad("different number of beacon entires")
// cannot mark bad, I think @Kubuxu
return nil, xerrors.Errorf("tipset contained different number for beacon entires")
}
for i, be := range bh.BeaconEntries {
if targetBE[i].Index != be.Index || !bytes.Equal(targetBE[i].Data, be.Data) {
markBad("different beacon eintires in epoch")
// cannot mark bad, I think @Kubuxu
return nil, xerrors.Errorf("tipset contained different number for beacon entires")
}
}

View File

@ -173,39 +173,26 @@ var blocksPerEpoch = NewInt(build.BlocksPerEpoch)
const sha256bits = 256
func IsTicketWinner(partialTicket []byte, ssizeI abi.SectorSize, snum uint64, totpow BigInt) bool {
ssize := NewInt(uint64(ssizeI))
ssampled := ElectionPostChallengeCount(snum, 0) // TODO: faults in epost?
func IsTicketWinner(partialTicket []byte, mypow BigInt, totpow BigInt) bool {
/*
Need to check that
(h(vrfout) + 1) / (max(h) + 1) <= e * sectorSize / totalPower
(h(vrfout) + 1) / (max(h) + 1) <= e * myPower / totalPower
max(h) == 2^256-1
which in terms of integer math means:
(h(vrfout) + 1) * totalPower <= e * sectorSize * 2^256
(h(vrfout) + 1) * totalPower <= e * myPower * 2^256
in 2^256 space, it is equivalent to:
h(vrfout) * totalPower < e * sectorSize * 2^256
h(vrfout) * totalPower < e * myPower * 2^256
Because of SectorChallengeRatioDiv sampling for proofs
we need to scale this appropriately.
Let c = ceil(numSectors/SectorChallengeRatioDiv)
(c is the number of tickets a miner requests)
Accordingly we check
(h(vrfout) + 1) / 2^256 <= e * sectorSize / totalPower * snum / c
or
h(vrfout) * totalPower * c < e * sectorSize * 2^256 * snum
*/
h := sha256.Sum256(partialTicket)
lhs := BigFromBytes(h[:]).Int
lhs = lhs.Mul(lhs, totpow.Int)
lhs = lhs.Mul(lhs, new(big.Int).SetUint64(ssampled))
// rhs = sectorSize * 2^256
// rhs = sectorSize << 256
rhs := new(big.Int).Lsh(ssize.Int, sha256bits)
rhs = rhs.Mul(rhs, new(big.Int).SetUint64(snum))
rhs := new(big.Int).Lsh(mypow.Int, sha256bits)
rhs = rhs.Mul(rhs, blocksPerEpoch.Int)
// h(vrfout) * totalPower < e * sectorSize * 2^256?

View File

@ -317,7 +317,7 @@ 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, m.api)
proofin, err := gen.IsRoundWinner(ctx, base.ts, int64(round), addr, m.epp, bvals[len(bvals)-1] m.api)
if err != nil {
return nil, xerrors.Errorf("failed to check if we win next round: %w", err)
}