{"content":{"title":"Venus 获取deadline信息并进行windowPost计算","body":"每个sector封装完毕以后，会放到一个partition里面进行接受挑战，2349个sector一般情况下是一个矿工是在24小时后内无法封装完成的，但是协议要求24小时以后几要开始做winningpost了。做winngpost时，会锁定partition，封装完成的sector将不能写进锁定的partition。将会写到另外一个partition。也就是说，2349个sector虽然理论上面只需要一个deadline进行挑战，但是因为上面的原因，2349个sector会被分配到两个以上的partition里面，所以2349个sector的windowpost的挑战，大概率会占有两个以上的deadline。\r\n\r\n哪个sector在哪个deadline被挑战（要求做dindowpost），都记载在一个bitfield的结构体并存储在链上。而sector被挑战的具体点，则是根据epoch的不一样，去drand获取一个随机数，根据这个随机数来选择sector被挑战的具体点。\r\n\r\n`damocles-mamanger`启动后会调用run方法，方法里面有一个for循环。不停的监听ChainNotify信息，当有区块产出或者别的headchain的事件发生后，就会调用fetchMinerProvingDeadlineInfos()方法，主动去从链节点获取deadline信息，然后调用handleHeadChange()方法，处理headchange事件。在处理headechange事件的过程中，会根据当下的epoch信息，选择调用runner.start()进行winpost的proof生成或者runner.submit()方法把生的winpost proof提交上链。\r\n\r\ndeadline信息其实没有什么，主要的信息就是每个actorid的起始时间不一样，从而导致其24小时的，48个proving period的开始epooch不一样而已。deadline里面主要就是当下的deadline的startepoch信息。\r\n\r\n\r\n启动for循环，监听chainnotify信息。\r\n```golang\r\nfunc (p *PoSter) Run(ctx context.Context) {\r\n            ....\r\n            .....\r\n            ch, err := p.deps.chain.ChainNotify(ctx)\r\n            .......\r\n            .......\r\n            // 从链上获取deadline信息\r\n            dinfos := p.fetchMinerProvingDeadlineInfos(ctx, mids, highest)\r\n\t\t\tif len(dinfos) == 0 {\r\n\t\t\t\tcontinue CHAIN_HEAD_LOOP\r\n\t\t\t}\r\n        \r\n        //处理headchange消息。一般是有了新的区块出现。\r\n\tp.handleHeadChange(ctx, lowest, highest, dinfos)\r\n}\r\n```\r\n\r\n```\r\nfunc (p *PoSter) handleHeadChange(ctx context.Context, revert *types.TipSet, advance *types.TipSet, dinfos map[abi.ActorID]map[abi.ChainEpoch]*dline.Info) {\r\n\r\n        // cleanup\r\n\tfor mid := range p.schedulers {\r\n        ....\r\n        ....\r\n        \t\tfor open := range scheds {\r\n\t\t\tsched := scheds[open]\r\n                        \r\n                        // 某个actorid已经开始runner任务以获取deadline的任务，所以删除掉，不再次开启runner任务\r\n\t\t\tif dls, dlsOk := dinfos[mid]; dlsOk {\r\n\t\t\t\t// 尝试开启的 deadline 已经存在\r\n\t\t\t\tif _, dlOk := dls[open]; dlOk {\r\n\t\t\t\t\tdelete(dls, open)\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n                           .......\r\n                           .......\r\n\r\n\t\t\t// post config 由于某种原因缺失时，无法触发 start 或 submit\r\n\t\t\tif pcfg != nil && sched.isActive(currHeight) {\r\n\t\t\t\tif sched.shouldStart(pcfg, currHeight) {\r\n\t\t\t\t\tsched.runner.start(pcfg, advance)\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif sched.couldSubmit(pcfg, currHeight) {\r\n\t\t\t\t\tsched.runner.submit(pcfg, advance)\r\n\t\t\t\t}\r\n\t\t\t}\r\n        ....\r\n        ....\r\n        \r\n        }\r\n        \r\n        .....\r\n        ....\r\n        for mid := range dinfos {\r\n        .....\r\n        .....\r\n        dls := dinfos[mid]\r\n\t\tfor open := range dls {\r\n\t\t\tdl := dls[open]\r\n\r\n\t\t\tsched := newScheduler(\r\n\t\t\t\tdl,\r\n\t\t\t\tp.runnerConstructor(\r\n\t\t\t\t\tctx,\r\n\t\t\t\t\tp.deps,\r\n\t\t\t\t\tmid,\r\n\t\t\t\t\tmaddr,\r\n\t\t\t\t\tminfo.WindowPoStProofType,\r\n\t\t\t\t\tdl,\r\n\t\t\t\t),\r\n\t\t\t)\r\n\r\n\t\t\tif _, ok := p.schedulers[mid]; !ok {\r\n\t\t\t\tp.schedulers[mid] = map[abi.ChainEpoch]*scheduler{}\r\n\t\t\t}\r\n\r\n\t\t\tmdLog.Debugw(\"init deadline runner\", \"open\", dl.Open)\r\n\t\t\tp.schedulers[mid][dl.Open] = sched\r\n\t\t\tif sched.isActive(currHeight) && sched.shouldStart(pcfg, currHeight) {\r\n\t\t\t\tsched.runner.start(pcfg, advance) // 开启runner任务，计算windowpost proof\r\n\t\t\t}\r\n        .....\r\n        .....\r\n        }\r\n}\r\n```\r\n\r\n```\r\nfunc (pr *postRunner) start(pcfg *modules.MinerPoStConfig, ts *types.TipSet) {\r\n        // 因为是sync.once 对象，所以只会运行一次。即：计算一次windowpost proof\r\n\tpr.startOnce.Do(func() {\r\n\t\tpr.startCtx.pcfg = pcfg\r\n\t\tpr.startCtx.ts = ts\r\n\r\n\t\tbaseLog := pr.log.With(\"tsk\", ts.Key(), \"tsh\", ts.Height())\r\n\r\n\t\tgo pr.handleFaults(baseLog)\r\n\t\tgo pr.generatePoSt(baseLog)\r\n\t})\r\n}\r\n\r\n```\r\n\r\n```\r\n// 这里计算windowpost proof\r\nfunc (pr *postRunner) generatePoStForPartitionBatch(glog *logging.ZapLogger, rand core.WindowPoStRandomness, batchIdx int, batch []chain.Partition, batchPartitionStartIdx int) {\r\n....\r\n....\r\n....\r\n....\r\n//有些类型的失败，会重新计算windowpost proof\r\nfor attempt := 0; ; attempt++ {\r\n\t\talog := pblog.With(\"attempt\", attempt)\r\n                /\r\n\t\tneedRetry, err := proveAttempt(alog)\r\n\t\tif err != nil {\r\n\t\t\talog.Errorf(\"attempt to generate window post proof: %v\", err)\r\n\t\t}\r\n\r\n\t\tif !needRetry {\r\n\t\t\talog.Info(\"partition batch done\")\r\n\t\t\tbreak\r\n\t\t}\r\n\r\n\t\tselect {\r\n\t\tcase <-pr.ctx.Done():\r\n\t\t\treturn\r\n\r\n\t\tcase <-time.After(5 * time.Second):\r\n\t\t}\r\n\r\n\t\talog.Debug(\"retry partition batch\")\r\n\t}\r\n}\r\n```\r\n\r\n\r\n当runner.start()方法真正的生成了windowpost proof，`pr.proofs.proofs`就不会是nil。就可以提交到链上了。\r\n```\r\nfunc (pr *postRunner) submit(pcfg *modules.MinerPoStConfig, ts *types.TipSet) {\r\n\t// check for proofs\r\n\tpr.proofs.Lock()\r\n\tproofs := pr.proofs.proofs\r\n\tpr.proofs.proofs = nil\r\n\tpr.proofs.Unlock()\r\n\r\n\tif proofs == nil {\r\n\t\treturn\r\n\t}\r\n\r\n\tgo pr.submitPoSts(pcfg, ts, proofs)\r\n}\r\n\r\n```\r\n\r\n```\r\nfunc (pr *postRunner) submitSinglePost(slog *logging.ZapLogger, pcfg *modules.MinerPoStConfig, proof *miner.SubmitWindowedPoStParams) {\r\n\tuid, resCh, err := pr.publishMessage(stbuiltin.MethodsMiner.SubmitWindowedPoSt, proof, false)\r\n\tif err != nil {\r\n\t\tslog.Errorf(\"publish post message: %v\", err)\r\n\t\treturn\r\n\t}\r\n        ....\r\n        ...\r\n        .....\r\n}\r\n```\r\n\r\nwindowpost proof不会直接提交到链节点，而是先提交给messager，messager把收到的windowpost proof信息，放到自己的数据库后，方法就会返回成功。\r\n但是这个时候，信息还没有上链，所以会调用waitmessage()方法，等待消息上链。\r\n```\r\nfunc (pr *postRunner) publishMessage(method abi.MethodNum, params cbor.Marshaler, useExtraMsgID bool) (string, <-chan msgResult, error) {\r\n    .....\r\n    .....\r\n    uid, err := pr.deps.msg.PushMessageWithId(pr.ctx, mid, &msg, &spec)\r\n\tif err != nil {\r\n\t\treturn \"\", nil, fmt.Errorf(\"push msg with id %s: %w\", mid, err)\r\n\t}\r\n\r\n    .....\r\n    m, err := pr.waitMessage(uid, pr.startCtx.pcfg.Confidence)\r\n    .....\r\n}\r\n```"},"author":{"user":"https://learnblockchain.cn/people/808","address":null},"history":"QmcJAKYywQMyxVQ3MifiFzHcx4tbRZ2nXwcM5MpujB3mey","timestamp":1696916336,"version":1}