Mineone过程

2021/07/05

MineOne 过程

step1 :compute ticket

func (m *Miner) computeTicket(ctx context.Context, brand *types.BeaconEntry, base *MiningBase, mbi *api.MiningBaseInfo) (*types.Ticket, error) {
	// 序列化 miner id
    buf := new(bytes.Buffer)
	if err := m.address.MarshalCBOR(buf); err != nil {
		return nil, xerrors.Errorf("failed to marshal address to cbor: %w", err)
	}
    // round 为实际要计算的高度
	round := base.TipSet.Height() + base.NullRounds + 1
	if round > build.UpgradeSmokeHeight {
		buf.Write(base.TipSet.MinTicket().VRFProof)
	}
    // 根据 beccon miner round 随机生成 input 数据
    // 采用 black2b hash 算法
	input, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_TicketProduction, round-build.TicketRandomnessLookback, buf.Bytes())
	if err != nil {
		return nil, err
	}
    // 计算 vrf 数据
    // bls wallet 对 input 签名的结果
	vrfOut, err := gen.ComputeVRF(ctx, m.api.WalletSign, mbi.WorkerKey, input)
	if err != nil {
		return nil, err
	}

	return &types.Ticket{
		VRFProof: vrfOut,
	}, nil
}

step2:判断在回合中是否胜出

func IsRoundWinner(ctx context.Context, ts *types.TipSet, round abi.ChainEpoch,
	miner address.Address, brand types.BeaconEntry, mbi *api.MiningBaseInfo, a MiningCheckAPI) (*types.ElectionProof, error) {
	buf := new(bytes.Buffer)
	if err := miner.MarshalCBOR(buf); err != nil {
		return nil, xerrors.Errorf("failed to cbor marshal address: %w", err)
	}

	electionRand, err := store.DrawRandomness(brand.Data, crypto.DomainSeparationTag_ElectionProofProduction, round, buf.Bytes())
	if err != nil {
		return nil, xerrors.Errorf("failed to draw randomness: %w", err)
	}
	log.Infof("IsRoundWinner DrawRandomness: brand= %x, stage= ElectionProofProduction, round= %v, beacon= %x, electionRand= %x, WorkerKey= %s", brand.Data, round, buf.Bytes(), electionRand, mbi.WorkerKey.String())
	vrfout, err := ComputeVRF(ctx, a.WalletSign, mbi.WorkerKey, electionRand)
	if err != nil {
		return nil, xerrors.Errorf("failed to compute VRF: %w", err)
	}
    // 进入ComputeWinCount
	ep := &types.ElectionProof{VRFProof: vrfout}
	j := ep.ComputeWinCount(mbi.MinerPower, mbi.NetworkPower)
	ep.WinCount = j
	log.Infof("IsRoundWinner ComputeWinCount: vrfout= %x, mPower= %x, nPower= %x, winCount= %v", vrfout, mbi.MinerPower, mbi.NetworkPower, ep.WinCount)
	if j < 1 {
		return nil, nil
	}

	return ep, nil
}
// 计算 wincount
// ComputeWinCount uses VRFProof to compute number of wins
// The algorithm is based on Algorand's Sortition with Binomial distribution
// replaced by Poisson distribution.
func (ep *ElectionProof) ComputeWinCount(power BigInt, totalPower BigInt) int64 {
	h := blake2b.Sum256(ep.VRFProof)

	lhs := BigFromBytes(h[:]).Int // 256bits, assume Q.256 so [0, 1)

	// We are calculating upside-down CDF of Poisson distribution with
	// rate λ=power*E/totalPower
	// Steps:
	//  1. calculate λ=power*E/totalPower
	//  2. calculate elam = exp(-λ)
	//  3. Check how many times we win:
	//    j = 0
	//    pmf = elam
	//    rhs = 1 - pmf
	//    for h(vrf) < rhs: j++; pmf = pmf * lam / j; rhs = rhs - pmf
    // 求得泊松分布的 lambda
    // lam = (power * 5) << 256) / total
	lam := lambda(power.Int, totalPower.Int) // Q.256
    // 根据 miner 算力和全网算力求得 k=0 时的泊松分布
	p, rhs := newPoiss(lam)

	var j int64
    // Max Wincount = 15
	for lhs.Cmp(rhs) < 0 && j < MaxWinCount {
		rhs = p.next()
		j++
	}

	return j
}

step3:compute proof

  • 首先调用 store.DrawRandomness 产生需要进行计算证明的数据,和 step 中调用该方法时传入的参数一致
  • 然后调用 ComputeProof() 进行计算,将 store.DrawRandomness 产生的源数据和 sector 信息传入,进行一些列处理后,调用 rust 计算
func (wpp *StorageWpp) ComputeProof(ctx context.Context, ssi []builtin.SectorInfo, rand abi.PoStRandomness) ([]builtin.PoStProof, error) {
	if build.InsecurePoStValidation {
		return []builtin.PoStProof, nil
	}

	log.Infof("Computing WinningPoSt ;%+v; %v", ssi, rand)

	start := build.Clock.Now()
	proof, err := wpp.prover.GenerateWinningPoSt(ctx, wpp.miner, ssi, rand)
	if err != nil {
		return nil, err
	}
	log.Infof("GenerateWinningPoSt took %s", time.Since(start))
	return proof, nil
}

step4:mpool select

func (a *MpoolAPI) MpoolSelect(ctx context.Context, tsk types.TipSetKey, ticketQuality float64) ([]*types.SignedMessage, error) {
	ts, err := a.Chain.GetTipSetFromKey(tsk)
	if err != nil {
		return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
	}

	return a.Mpool.SelectMessages(ctx, ts, ticketQuality)
}
func (mp *MessagePool) SelectMessages(ctx context.Context, ts *types.TipSet, tq float64) (msgs []*types.SignedMessage, err error) {
	mp.curTsLk.Lock()
	defer mp.curTsLk.Unlock()

	mp.lk.Lock()
	defer mp.lk.Unlock()

	// if the ticket quality is high enough that the first block has higher probability
	// than any other block, then we don't bother with optimal selection because the
	// first block will always have higher effective performance
    // 两种 select messages 的方式
    // 1. 贪婪:获取 mpool pending 中的全部消息,将 message 组装成 message chain,只受 block 的最大 gas limit 限制
    // 2. 择优:获取 mpool pending 中的全部消息,将 message 组装成 message chain,受 message chain 的最大数量(15个)、最大gas limit、评优计算限制
	if tq > 0.84 {
		msgs, err = mp.selectMessagesGreedy(ctx, mp.curTs, ts)
	} else {
		msgs, err = mp.selectMessagesOptimal(ctx, mp.curTs, ts, tq)
	}

	if err != nil {
		return nil, err
	}
    // MaxBlockMessages = 16000
	if len(msgs) > MaxBlockMessages {
		msgs = msgs[:MaxBlockMessages]
	}

	return msgs, nil
}

step5:create block

  • 把 ticket 数据、IsRoundWinner 产生的数据、beacon、ComputeProof 产生的数据、msgs 进行打包
func (m *Miner) createBlock(base *MiningBase, addr address.Address, ticket *types.Ticket,
	eproof *types.ElectionProof, bvals []types.BeaconEntry, wpostProof []proof2.PoStProof, msgs []*types.SignedMessage) (*types.BlockMsg, error) {
	uts := base.TipSet.MinTimestamp() + build.BlockDelaySecs*(uint64(base.NullRounds)+1)

	nheight := base.TipSet.Height() + base.NullRounds + 1

	// why even return this? that api call could just submit it for us
	return m.api.MinerCreateBlock(context.TODO(), &api.BlockTemplate{
		Miner:            addr,
		Parents:          base.TipSet.Key(),
		Ticket:           ticket,
		Eproof:           eproof,
		BeaconValues:     bvals,
		Messages:         msgs,
		Epoch:            nheight,
		Timestamp:        uts,
		WinningPoStProof: wpostProof,
	})
}

Search

    Table of Contents